From 3f8d3011333be50166d6808d6b4ae9511e600670 Mon Sep 17 00:00:00 2001 From: Marius Andra Date: Sun, 15 Jan 2023 23:28:30 +0100 Subject: [PATCH 1/9] write inline types --- package.json | 1 + src/cli/typegen.ts | 1 + src/inline/inline.ts | 82 ++++++++++++++++++++++++++++++++++++++++++++ src/typegen.ts | 7 ++-- src/types.ts | 2 ++ 5 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 src/inline/inline.ts diff --git a/package.json b/package.json index de7795d..7f616a5 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "test": "jest", "samples:check": "ts-node ./src/cli/typegen.ts check -r ./samples", "samples:write": "ts-node ./src/cli/typegen.ts write -r ./samples --write-paths", + "samples:write:inline": "ts-node ./src/cli/typegen.ts write -r ./samples --write-paths --inline", "samples:convert": "ts-node ./src/cli/typegen.ts write -r ./samples --convert-to-builders", "samples:watch": "ts-node ./src/cli/typegen.ts watch -r ./samples", "samples:write:posthog": "ts-node ./src/cli/typegen.ts write -c ../../PostHog/posthog/tsconfig.json", diff --git a/src/cli/typegen.ts b/src/cli/typegen.ts index 5c90edd..4e29c75 100755 --- a/src/cli/typegen.ts +++ b/src/cli/typegen.ts @@ -45,6 +45,7 @@ yargs type: 'string', }) .option('quiet', { alias: 'q', describe: 'Write nothing to stdout', type: 'boolean' }) + .option('inline', { alias: 'i', describe: 'Inline types', type: 'boolean' }) .option('no-import', { describe: 'Do not automatically import generated types in logic files', type: 'boolean' }) .option('write-paths', { describe: 'Write paths into logic files that have none', type: 'boolean' }) .option('add-ts-nocheck', { describe: 'Add @ts-nocheck to top of logicType.ts files', type: 'boolean' }) diff --git a/src/inline/inline.ts b/src/inline/inline.ts new file mode 100644 index 0000000..df7904d --- /dev/null +++ b/src/inline/inline.ts @@ -0,0 +1,82 @@ +import { ParsedLogic } from '../types' +import * as fs from 'fs' +import { runThroughPrettier } from '../print/print' +import { print, visit } from 'recast' +import type { NodePath } from 'ast-types/lib/node-path' +import { t, b, visitAllKeaCalls, getAst } from '../write/utils' + +export function inlineFiles( + program, + appOptions, + parsedLogics, +): { filesToWrite: number; writtenFiles: number; filesToModify: number } { + const { log } = appOptions + + const groupedByFile: Record = {} + for (const parsedLogic of parsedLogics) { + if (!groupedByFile[parsedLogic.fileName]) { + groupedByFile[parsedLogic.fileName] = [] + } + groupedByFile[parsedLogic.fileName].push(parsedLogic) + } + + for (const [filename, parsedLogics] of Object.entries(groupedByFile)) { + const sourceFile = program.getSourceFile(filename) + const rawCode = sourceFile.getText() + + const ast = getAst(filename, rawCode) + + const parsedLogicTypeNames = new Set(parsedLogics.map((l) => l.logicTypeName)) + const foundLogicTypes = new Map() + + // find all keaType calls, add interface declaration if missing + visit(ast, { + visitTSTypeAliasDeclaration(path): any { + if (parsedLogicTypeNames.has(path.value.id.name)) { + foundLogicTypes.set(path.value.id.name, path) + } + return false + }, + }) + + // find all kea calls, add `` type parameters if needed + visitAllKeaCalls(ast, parsedLogics, filename, ({ path, parsedLogic }) => { + if (parsedLogic.logicTypeName && foundLogicTypes.has(parsedLogic.logicTypeName)) { + const typeAlias: NodePath = foundLogicTypes.get(parsedLogic.logicTypeName) + if (t.TSTypeAliasDeclaration.check(typeAlias.value)) { + typeAlias.value.typeAnnotation = createLogicTypeReference(parsedLogic) + } + } + if (parsedLogic.logicTypeName && !foundLogicTypes.has(parsedLogic.logicTypeName)) { + let ptr: NodePath = path + while (ptr) { + if (ptr.parentPath?.value === ast.program.body) { + const index = ast.program.body.findIndex((n) => n === ptr.value) + ast.program.body = [ + ...ast.program.body.slice(0, index), + b.exportNamedDeclaration( + b.tsTypeAliasDeclaration( + b.identifier(parsedLogic.logicTypeName), + createLogicTypeReference(parsedLogic), + ), + ), + ...ast.program.body.slice(index), + ] + } + ptr = ptr.parentPath + } + } + }) + + const newText = runThroughPrettier(print(ast).code, filename) + fs.writeFileSync(filename, newText) + } + + return { filesToWrite: 0, writtenFiles: 0, filesToModify: 0 } +} + +export function createLogicTypeReference(parsedLogic: ParsedLogic): ReturnType { + const node = b.tsTypeReference(b.identifier('LogicType')) + debugger + return node +} diff --git a/src/typegen.ts b/src/typegen.ts index 9b2c9b1..7727bcb 100755 --- a/src/typegen.ts +++ b/src/typegen.ts @@ -3,8 +3,9 @@ import * as path from 'path' import { visitProgram } from './visit/visit' import { printToFiles } from './print/print' import { AppOptions } from './types' -import { formatDiagnosticsWithColorAndContext, Program } from 'typescript' +import { Program } from 'typescript' import { version } from '../package.json' +import { inlineFiles } from './inline/inline' export function runTypeGen(appOptions: AppOptions) { let program: Program @@ -106,7 +107,9 @@ export function runTypeGen(appOptions: AppOptions) { log(`🗒️ ${parsedLogics.length} logic${parsedLogics.length === 1 ? '' : 's'} found!`) } - const response = printToFiles(program, appOptions, parsedLogics) + const response = appOptions.inline + ? inlineFiles(program, appOptions, parsedLogics) + : printToFiles(program, appOptions, parsedLogics) // running "kea-typegen check" and would write files? // exit with 1 diff --git a/src/types.ts b/src/types.ts index 0235912..ff14e88 100644 --- a/src/types.ts +++ b/src/types.ts @@ -78,6 +78,8 @@ export interface AppOptions { convertToBuilders?: boolean /** Show TypeScript errors */ showTsErrors?: boolean + /** Inline types into source files */ + inline?: boolean log: (message: string) => void } From 49e9c6f5e9ba1ce7a2537140dc7ade23ea5ea7c8 Mon Sep 17 00:00:00 2001 From: Marius Andra Date: Sun, 15 Jan 2023 23:31:06 +0100 Subject: [PATCH 2/9] cleanup --- src/inline/inline.ts | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/inline/inline.ts b/src/inline/inline.ts index df7904d..d426217 100644 --- a/src/inline/inline.ts +++ b/src/inline/inline.ts @@ -1,6 +1,6 @@ import { ParsedLogic } from '../types' import * as fs from 'fs' -import { runThroughPrettier } from '../print/print' +import { runThroughPrettier } from '../print/print' import { print, visit } from 'recast' import type { NodePath } from 'ast-types/lib/node-path' import { t, b, visitAllKeaCalls, getAst } from '../write/utils' @@ -29,7 +29,6 @@ export function inlineFiles( const parsedLogicTypeNames = new Set(parsedLogics.map((l) => l.logicTypeName)) const foundLogicTypes = new Map() - // find all keaType calls, add interface declaration if missing visit(ast, { visitTSTypeAliasDeclaration(path): any { if (parsedLogicTypeNames.has(path.value.id.name)) { @@ -39,15 +38,16 @@ export function inlineFiles( }, }) - // find all kea calls, add `` type parameters if needed visitAllKeaCalls(ast, parsedLogics, filename, ({ path, parsedLogic }) => { - if (parsedLogic.logicTypeName && foundLogicTypes.has(parsedLogic.logicTypeName)) { + path.node.typeParameters = b.tsTypeParameterInstantiation([ + b.tsTypeReference(b.identifier(parsedLogic.logicTypeName)), + ]) + if (foundLogicTypes.has(parsedLogic.logicTypeName)) { const typeAlias: NodePath = foundLogicTypes.get(parsedLogic.logicTypeName) if (t.TSTypeAliasDeclaration.check(typeAlias.value)) { typeAlias.value.typeAnnotation = createLogicTypeReference(parsedLogic) } - } - if (parsedLogic.logicTypeName && !foundLogicTypes.has(parsedLogic.logicTypeName)) { + } else { let ptr: NodePath = path while (ptr) { if (ptr.parentPath?.value === ast.program.body) { @@ -55,10 +55,10 @@ export function inlineFiles( ast.program.body = [ ...ast.program.body.slice(0, index), b.exportNamedDeclaration( - b.tsTypeAliasDeclaration( - b.identifier(parsedLogic.logicTypeName), - createLogicTypeReference(parsedLogic), - ), + b.tsTypeAliasDeclaration( + b.identifier(parsedLogic.logicTypeName), + createLogicTypeReference(parsedLogic), + ), ), ...ast.program.body.slice(index), ] @@ -70,6 +70,7 @@ export function inlineFiles( const newText = runThroughPrettier(print(ast).code, filename) fs.writeFileSync(filename, newText) + debugger } return { filesToWrite: 0, writtenFiles: 0, filesToModify: 0 } From b15111168f985bb48085ae5faaee9cf6008a2be9 Mon Sep 17 00:00:00 2001 From: Marius Andra Date: Mon, 16 Jan 2023 00:18:28 +0100 Subject: [PATCH 3/9] MakeLogicType compatible inline --- src/inline/inline.ts | 61 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/src/inline/inline.ts b/src/inline/inline.ts index d426217..f00805d 100644 --- a/src/inline/inline.ts +++ b/src/inline/inline.ts @@ -1,9 +1,11 @@ import { ParsedLogic } from '../types' import * as fs from 'fs' -import { runThroughPrettier } from '../print/print' -import { print, visit } from 'recast' +import { nodeToString, runThroughPrettier } from '../print/print' +import { parse, print, visit } from 'recast' import type { NodePath } from 'ast-types/lib/node-path' -import { t, b, visitAllKeaCalls, getAst } from '../write/utils' +import { t, b, visitAllKeaCalls, getAst, assureImport } from '../write/utils' +import { factory, SyntaxKind } from 'typescript' +import { cleanDuplicateAnyNodes } from '../utils' export function inlineFiles( program, @@ -29,6 +31,8 @@ export function inlineFiles( const parsedLogicTypeNames = new Set(parsedLogics.map((l) => l.logicTypeName)) const foundLogicTypes = new Map() + let hasImportFromKea = false + visit(ast, { visitTSTypeAliasDeclaration(path): any { if (parsedLogicTypeNames.has(path.value.id.name)) { @@ -36,8 +40,18 @@ export function inlineFiles( } return false }, + visitImportDeclaration(path) { + const isKeaImport = + path.value.source && t.StringLiteral.check(path.value.source) && path.value.source.value === 'kea' + if (isKeaImport) { + hasImportFromKea = true + } + return false + }, }) + assureImport(ast, 'kea', 'MakeLogicType', 'MakeLogicType', hasImportFromKea) + visitAllKeaCalls(ast, parsedLogics, filename, ({ path, parsedLogic }) => { path.node.typeParameters = b.tsTypeParameterInstantiation([ b.tsTypeReference(b.identifier(parsedLogic.logicTypeName)), @@ -77,7 +91,46 @@ export function inlineFiles( } export function createLogicTypeReference(parsedLogic: ParsedLogic): ReturnType { - const node = b.tsTypeReference(b.identifier('LogicType')) + const typeReferenceNode = factory.createTypeReferenceNode(factory.createIdentifier('MakeLogicType'), [ + // values + factory.createTypeLiteralNode( + cleanDuplicateAnyNodes(parsedLogic.reducers.concat(parsedLogic.selectors)).map((reducer) => { + return factory.createPropertySignature( + undefined, + factory.createIdentifier(reducer.name), + undefined, + reducer.typeNode, + ) + }), + ), + // actions + factory.createTypeLiteralNode( + parsedLogic.actions.map(({ name, parameters, returnTypeNode }) => + factory.createPropertySignature(undefined, factory.createIdentifier(name), undefined, returnTypeNode), + ), + ), + // props + parsedLogic.propsType || + factory.createTypeReferenceNode(factory.createIdentifier('Record'), [ + factory.createKeywordTypeNode(SyntaxKind.StringKeyword), + factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword), + ]), + ]) + + // Transform Typescript API's AST to a string + const source = nodeToString( + factory.createTypeAliasDeclaration( + [], + [], + factory.createIdentifier('githubLogicType'), + undefined, + typeReferenceNode, + ), + ) + + // Convert that string to recast's AST + const node = getAst(parsedLogic.fileName, source).program.body[0].typeAnnotation debugger + return node } From 5b69b4206dfff032467289133db1fa00978954b4 Mon Sep 17 00:00:00 2001 From: Marius Andra Date: Mon, 16 Jan 2023 00:42:32 +0100 Subject: [PATCH 4/9] new style types --- src/inline/inline.ts | 98 ++++++++++++++++++++++++++++++++------------ 1 file changed, 72 insertions(+), 26 deletions(-) diff --git a/src/inline/inline.ts b/src/inline/inline.ts index f00805d..a75859d 100644 --- a/src/inline/inline.ts +++ b/src/inline/inline.ts @@ -1,7 +1,7 @@ import { ParsedLogic } from '../types' import * as fs from 'fs' import { nodeToString, runThroughPrettier } from '../print/print' -import { parse, print, visit } from 'recast' +import { print, visit } from 'recast' import type { NodePath } from 'ast-types/lib/node-path' import { t, b, visitAllKeaCalls, getAst, assureImport } from '../write/utils' import { factory, SyntaxKind } from 'typescript' @@ -12,8 +12,6 @@ export function inlineFiles( appOptions, parsedLogics, ): { filesToWrite: number; writtenFiles: number; filesToModify: number } { - const { log } = appOptions - const groupedByFile: Record = {} for (const parsedLogic of parsedLogics) { if (!groupedByFile[parsedLogic.fileName]) { @@ -32,6 +30,7 @@ export function inlineFiles( const foundLogicTypes = new Map() let hasImportFromKea = false + let foundKeaLogicTypeImport = false visit(ast, { visitTSTypeAliasDeclaration(path): any { @@ -43,14 +42,33 @@ export function inlineFiles( visitImportDeclaration(path) { const isKeaImport = path.value.source && t.StringLiteral.check(path.value.source) && path.value.source.value === 'kea' + if (isKeaImport) { hasImportFromKea = true + for (const specifier of path.value.specifiers) { + if (specifier.imported.name === 'KeaLogicType') { + foundKeaLogicTypeImport = true + } + } + } + + // remove non-inline imports from external loginType.ts files + for (const specifier of path.value.specifiers) { + if (specifier.imported?.name && parsedLogicTypeNames.has(specifier.imported.name)) { + path.value.specifiers = path.value.specifiers.filter((s) => s !== specifier) + if (path.value.specifiers.length === 0) { + path.prune() + } + } } + return false }, }) - assureImport(ast, 'kea', 'MakeLogicType', 'MakeLogicType', hasImportFromKea) + if (!foundKeaLogicTypeImport) { + assureImport(ast, 'kea', 'KeaLogicType', 'KeaLogicType', hasImportFromKea) + } visitAllKeaCalls(ast, parsedLogics, filename, ({ path, parsedLogic }) => { path.node.typeParameters = b.tsTypeParameterInstantiation([ @@ -84,37 +102,65 @@ export function inlineFiles( const newText = runThroughPrettier(print(ast).code, filename) fs.writeFileSync(filename, newText) - debugger + // debugger } return { filesToWrite: 0, writtenFiles: 0, filesToModify: 0 } } export function createLogicTypeReference(parsedLogic: ParsedLogic): ReturnType { - const typeReferenceNode = factory.createTypeReferenceNode(factory.createIdentifier('MakeLogicType'), [ - // values + const typeReferenceNode = factory.createTypeReferenceNode(factory.createIdentifier('KeaLogicType'), [ factory.createTypeLiteralNode( - cleanDuplicateAnyNodes(parsedLogic.reducers.concat(parsedLogic.selectors)).map((reducer) => { - return factory.createPropertySignature( + [ + // actions + factory.createPropertySignature( undefined, - factory.createIdentifier(reducer.name), + factory.createIdentifier('actions'), undefined, - reducer.typeNode, - ) - }), - ), - // actions - factory.createTypeLiteralNode( - parsedLogic.actions.map(({ name, parameters, returnTypeNode }) => - factory.createPropertySignature(undefined, factory.createIdentifier(name), undefined, returnTypeNode), - ), + + factory.createTypeLiteralNode( + parsedLogic.actions.map(({ name, parameters, returnTypeNode }) => + factory.createPropertySignature( + undefined, + factory.createIdentifier(name), + undefined, + factory.createFunctionTypeNode(undefined, parameters, returnTypeNode), + ), + ), + ), + ), + // values + factory.createPropertySignature( + undefined, + factory.createIdentifier('values'), + undefined, + factory.createTypeLiteralNode( + cleanDuplicateAnyNodes(parsedLogic.reducers.concat(parsedLogic.selectors)).map((reducer) => + factory.createPropertySignature( + undefined, + factory.createIdentifier(reducer.name), + undefined, + reducer.typeNode, + ), + ), + ), + ), + // props + parsedLogic.propsType + ? factory.createPropertySignature( + undefined, + factory.createIdentifier('props'), + undefined, + + parsedLogic.propsType || + factory.createTypeReferenceNode(factory.createIdentifier('Record'), [ + factory.createKeywordTypeNode(SyntaxKind.StringKeyword), + factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword), + ]), + ) + : undefined, + ].filter((a) => !!a), ), - // props - parsedLogic.propsType || - factory.createTypeReferenceNode(factory.createIdentifier('Record'), [ - factory.createKeywordTypeNode(SyntaxKind.StringKeyword), - factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword), - ]), ]) // Transform Typescript API's AST to a string @@ -130,7 +176,7 @@ export function createLogicTypeReference(parsedLogic: ParsedLogic): ReturnType Date: Mon, 16 Jan 2023 00:46:29 +0100 Subject: [PATCH 5/9] move it below --- src/inline/inline.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/inline/inline.ts b/src/inline/inline.ts index a75859d..6aea628 100644 --- a/src/inline/inline.ts +++ b/src/inline/inline.ts @@ -85,14 +85,14 @@ export function inlineFiles( if (ptr.parentPath?.value === ast.program.body) { const index = ast.program.body.findIndex((n) => n === ptr.value) ast.program.body = [ - ...ast.program.body.slice(0, index), + ...ast.program.body.slice(0, index+1), b.exportNamedDeclaration( b.tsTypeAliasDeclaration( b.identifier(parsedLogic.logicTypeName), createLogicTypeReference(parsedLogic), ), ), - ...ast.program.body.slice(index), + ...ast.program.body.slice(index+1), ] } ptr = ptr.parentPath From ab5711bf78ce06bcaffe63f91e84ff953f1324f1 Mon Sep 17 00:00:00 2001 From: Marius Andra Date: Mon, 16 Jan 2023 01:33:06 +0100 Subject: [PATCH 6/9] jsx --- .babelrc | 6 +- package.json | 3 +- src/inline/inline.ts | 206 ++++++++++++++++++++++++------------------- src/write/utils.ts | 2 +- yarn.lock | 95 ++++++++++++++++++++ 5 files changed, 220 insertions(+), 92 deletions(-) diff --git a/.babelrc b/.babelrc index 62475f2..ec771f1 100644 --- a/.babelrc +++ b/.babelrc @@ -1,3 +1,7 @@ { - "presets": [["@babel/preset-env", { "targets": { "node": "current" } }], "@babel/preset-typescript"] + "presets": [ + ["@babel/preset-env", { "targets": { "node": "current" } }], + "@babel/preset-react", + "@babel/preset-typescript" + ] } diff --git a/package.json b/package.json index 7f616a5..4a60958 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "samples:write:inline": "ts-node ./src/cli/typegen.ts write -r ./samples --write-paths --inline", "samples:convert": "ts-node ./src/cli/typegen.ts write -r ./samples --convert-to-builders", "samples:watch": "ts-node ./src/cli/typegen.ts watch -r ./samples", - "samples:write:posthog": "ts-node ./src/cli/typegen.ts write -c ../../PostHog/posthog/tsconfig.json", + "samples:write:posthog": "ts-node ./src/cli/typegen.ts write --inline --write-paths -c ../../PostHog/posthog/tsconfig.json", "form-plugin:build": "cd form-plugin && yarn && yarn build && cd ..", "form-plugin:rebuild": "yarn form-plugin:build && rm -rf node_modules && yarn" }, @@ -34,6 +34,7 @@ "yargs": "^16.2.0" }, "devDependencies": { + "@babel/preset-react": "^7.18.6", "@types/jest": "^26.0.20", "@types/node": "^14.14.31", "@types/yargs": "^16.0.0", diff --git a/src/inline/inline.ts b/src/inline/inline.ts index 6aea628..9681783 100644 --- a/src/inline/inline.ts +++ b/src/inline/inline.ts @@ -4,7 +4,7 @@ import { nodeToString, runThroughPrettier } from '../print/print' import { print, visit } from 'recast' import type { NodePath } from 'ast-types/lib/node-path' import { t, b, visitAllKeaCalls, getAst, assureImport } from '../write/utils' -import { factory, SyntaxKind } from 'typescript' +import { factory, SyntaxKind, PropertySignature, Identifier } from 'typescript' import { cleanDuplicateAnyNodes } from '../utils' export function inlineFiles( @@ -21,93 +21,111 @@ export function inlineFiles( } for (const [filename, parsedLogics] of Object.entries(groupedByFile)) { - const sourceFile = program.getSourceFile(filename) - const rawCode = sourceFile.getText() + try { + const sourceFile = program.getSourceFile(filename) + const rawCode = sourceFile.getText() - const ast = getAst(filename, rawCode) + const ast = getAst(filename, rawCode) - const parsedLogicTypeNames = new Set(parsedLogics.map((l) => l.logicTypeName)) - const foundLogicTypes = new Map() + const parsedLogicTypeNames = new Set(parsedLogics.map((l) => l.logicTypeName)) + const foundLogicTypes = new Map() - let hasImportFromKea = false - let foundKeaLogicTypeImport = false + let hasImportFromKea = false + let foundKeaLogicTypeImport = false - visit(ast, { - visitTSTypeAliasDeclaration(path): any { - if (parsedLogicTypeNames.has(path.value.id.name)) { - foundLogicTypes.set(path.value.id.name, path) - } - return false - }, - visitImportDeclaration(path) { - const isKeaImport = - path.value.source && t.StringLiteral.check(path.value.source) && path.value.source.value === 'kea' - - if (isKeaImport) { - hasImportFromKea = true - for (const specifier of path.value.specifiers) { - if (specifier.imported.name === 'KeaLogicType') { - foundKeaLogicTypeImport = true + visit(ast, { + visitTSTypeAliasDeclaration(path): any { + if (parsedLogicTypeNames.has(path.value.id.name)) { + foundLogicTypes.set(path.value.id.name, path) + } + return false + }, + visitImportDeclaration(path) { + const isKeaImport = + path.value.source && + t.StringLiteral.check(path.value.source) && + path.value.source.value === 'kea' + + if (isKeaImport) { + hasImportFromKea = true + for (const specifier of path.value.specifiers) { + if (specifier.imported.name === 'KeaLogicType') { + foundKeaLogicTypeImport = true + } } } - } - // remove non-inline imports from external loginType.ts files - for (const specifier of path.value.specifiers) { - if (specifier.imported?.name && parsedLogicTypeNames.has(specifier.imported.name)) { - path.value.specifiers = path.value.specifiers.filter((s) => s !== specifier) - if (path.value.specifiers.length === 0) { - path.prune() + // remove non-inline imports from external loginType.ts files + for (const specifier of path.value.specifiers) { + if (specifier.imported?.name && parsedLogicTypeNames.has(specifier.imported.name)) { + path.value.specifiers = path.value.specifiers.filter((s) => s !== specifier) + if (path.value.specifiers.length === 0) { + path.prune() + } } } - } - return false - }, - }) + return false + }, + }) - if (!foundKeaLogicTypeImport) { - assureImport(ast, 'kea', 'KeaLogicType', 'KeaLogicType', hasImportFromKea) - } + if (!foundKeaLogicTypeImport) { + assureImport(ast, 'kea', 'KeaLogicType', 'KeaLogicType', hasImportFromKea) + } - visitAllKeaCalls(ast, parsedLogics, filename, ({ path, parsedLogic }) => { - path.node.typeParameters = b.tsTypeParameterInstantiation([ - b.tsTypeReference(b.identifier(parsedLogic.logicTypeName)), - ]) - if (foundLogicTypes.has(parsedLogic.logicTypeName)) { - const typeAlias: NodePath = foundLogicTypes.get(parsedLogic.logicTypeName) - if (t.TSTypeAliasDeclaration.check(typeAlias.value)) { - typeAlias.value.typeAnnotation = createLogicTypeReference(parsedLogic) - } - } else { - let ptr: NodePath = path - while (ptr) { - if (ptr.parentPath?.value === ast.program.body) { - const index = ast.program.body.findIndex((n) => n === ptr.value) - ast.program.body = [ - ...ast.program.body.slice(0, index+1), - b.exportNamedDeclaration( - b.tsTypeAliasDeclaration( - b.identifier(parsedLogic.logicTypeName), - createLogicTypeReference(parsedLogic), + visitAllKeaCalls(ast, parsedLogics, filename, ({ path, parsedLogic }) => { + path.node.typeParameters = b.tsTypeParameterInstantiation([ + b.tsTypeReference(b.identifier(parsedLogic.logicTypeName)), + ]) + if (foundLogicTypes.has(parsedLogic.logicTypeName)) { + const typeAlias: NodePath = foundLogicTypes.get(parsedLogic.logicTypeName) + if (t.TSTypeAliasDeclaration.check(typeAlias.value)) { + typeAlias.value.typeAnnotation = createLogicTypeReference(parsedLogic) + } + } else { + let ptr: NodePath = path + while (ptr) { + if (ptr.parentPath?.value === ast.program.body) { + const index = ast.program.body.findIndex((n) => n === ptr.value) + ast.program.body = [ + ...ast.program.body.slice(0, index + 1), + b.exportNamedDeclaration( + b.tsTypeAliasDeclaration( + b.identifier(parsedLogic.logicTypeName), + createLogicTypeReference(parsedLogic), + ), ), - ), - ...ast.program.body.slice(index+1), - ] + ...ast.program.body.slice(index + 1), + ] + } + ptr = ptr.parentPath } - ptr = ptr.parentPath } - } - }) + }) - const newText = runThroughPrettier(print(ast).code, filename) - fs.writeFileSync(filename, newText) - // debugger + const newText = runThroughPrettier(print(ast).code, filename) + fs.writeFileSync(filename, newText) + } catch (e) { + console.error(`Error updating logic types in ${filename}`) + console.error(e) + } } return { filesToWrite: 0, writtenFiles: 0, filesToModify: 0 } } +function sortPropertySignatures( + propertySignatures: (PropertySignature | unknown | null | false)[], +): PropertySignature[] { + return propertySignatures + .filter((a): a is PropertySignature => !!a) + .sort((a, b) => + String((a.name as Identifier)?.escapedText || ('' as string)).localeCompare( + String((a.name as Identifier)?.escapedText || ('' as string)), + ), + ) +} + export function createLogicTypeReference(parsedLogic: ParsedLogic): ReturnType { const typeReferenceNode = factory.createTypeReferenceNode(factory.createIdentifier('KeaLogicType'), [ factory.createTypeLiteralNode( @@ -119,12 +137,14 @@ export function createLogicTypeReference(parsedLogic: ParsedLogic): ReturnType - factory.createPropertySignature( - undefined, - factory.createIdentifier(name), - undefined, - factory.createFunctionTypeNode(undefined, parameters, returnTypeNode), + sortPropertySignatures( + parsedLogic.actions.map(({ name, parameters, returnTypeNode }) => + factory.createPropertySignature( + undefined, + factory.createIdentifier(name), + undefined, + factory.createFunctionTypeNode(undefined, parameters, returnTypeNode), + ), ), ), ), @@ -135,12 +155,14 @@ export function createLogicTypeReference(parsedLogic: ParsedLogic): ReturnType - factory.createPropertySignature( - undefined, - factory.createIdentifier(reducer.name), - undefined, - reducer.typeNode, + sortPropertySignatures( + cleanDuplicateAnyNodes(parsedLogic.reducers.concat(parsedLogic.selectors)).map((reducer) => + factory.createPropertySignature( + undefined, + factory.createIdentifier(reducer.name), + undefined, + reducer.typeNode, + ), ), ), ), @@ -164,19 +186,25 @@ export function createLogicTypeReference(parsedLogic: ParsedLogic): ReturnType parseSync(source, { - presets: ['@babel/preset-env', '@babel/preset-typescript'], + presets: ['@babel/preset-env', '@babel/preset-react', '@babel/preset-typescript'], filename: filename, parserOpts: { tokens: true, // recast uses this diff --git a/yarn.lock b/yarn.lock index 5dee885..cbe5c11 100644 --- a/yarn.lock +++ b/yarn.lock @@ -172,6 +172,13 @@ dependencies: "@babel/types" "^7.16.7" +"@babel/helper-annotate-as-pure@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" + integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA== + dependencies: + "@babel/types" "^7.18.6" + "@babel/helper-builder-binary-assignment-operator-visitor@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz#38d138561ea207f0f69eb1626a418e4f7e6a580b" @@ -401,6 +408,13 @@ dependencies: "@babel/types" "^7.16.7" +"@babel/helper-module-imports@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" + integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== + dependencies: + "@babel/types" "^7.18.6" + "@babel/helper-module-transforms@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.10.4.tgz#ca1f01fdb84e48c24d7506bb818c961f1da8805d" @@ -483,6 +497,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5" integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA== +"@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.20.2": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz#d1b9000752b18d0877cff85a5c376ce5c3121629" + integrity sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ== + "@babel/helper-regex@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.10.4.tgz#59b373daaf3458e5747dece71bbaf45f9676af6d" @@ -587,6 +606,11 @@ dependencies: "@babel/types" "^7.16.7" +"@babel/helper-string-parser@^7.19.4": + version "7.19.4" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63" + integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw== + "@babel/helper-validator-identifier@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" @@ -612,6 +636,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== +"@babel/helper-validator-identifier@^7.19.1": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" + integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== + "@babel/helper-validator-option@^7.12.17": version "7.12.17" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz#d1fbf012e1a79b7eebbfdc6d270baaf8d9eb9831" @@ -627,6 +656,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== +"@babel/helper-validator-option@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8" + integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw== + "@babel/helper-wrap-function@^7.16.8": version "7.16.8" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz#58afda087c4cd235de92f7ceedebca2c41274200" @@ -935,6 +969,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" +"@babel/plugin-syntax-jsx@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz#a8feef63b010150abd97f1649ec296e849943ca0" + integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" @@ -1205,6 +1246,39 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-transform-react-display-name@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz#8b1125f919ef36ebdfff061d664e266c666b9415" + integrity sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-react-jsx-development@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz#dbe5c972811e49c7405b630e4d0d2e1380c0ddc5" + integrity sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA== + dependencies: + "@babel/plugin-transform-react-jsx" "^7.18.6" + +"@babel/plugin-transform-react-jsx@^7.18.6": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.20.7.tgz#025d85a1935fd7e19dfdcb1b1d4df34d4da484f7" + integrity sha512-Tfq7qqD+tRj3EoDhY00nn2uP2hsRxgYGi5mLQ5TimKav0a9Lrpd4deE+fcLXU8zFYRjlKPHZhpCvfEA6qnBxqQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/plugin-syntax-jsx" "^7.18.6" + "@babel/types" "^7.20.7" + +"@babel/plugin-transform-react-pure-annotations@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz#561af267f19f3e5d59291f9950fd7b9663d0d844" + integrity sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-transform-regenerator@^7.16.7": version "7.17.9" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.17.9.tgz#0a33c3a61cf47f45ed3232903683a0afd2d3460c" @@ -1370,6 +1444,18 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" +"@babel/preset-react@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.18.6.tgz#979f76d6277048dc19094c217b507f3ad517dd2d" + integrity sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-validator-option" "^7.18.6" + "@babel/plugin-transform-react-display-name" "^7.18.6" + "@babel/plugin-transform-react-jsx" "^7.18.6" + "@babel/plugin-transform-react-jsx-development" "^7.18.6" + "@babel/plugin-transform-react-pure-annotations" "^7.18.6" + "@babel/preset-typescript@^7.16.0": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.16.7.tgz#ab114d68bb2020afc069cd51b37ff98a046a70b9" @@ -1539,6 +1625,15 @@ "@babel/helper-validator-identifier" "^7.16.7" to-fast-properties "^2.0.0" +"@babel/types@^7.18.6", "@babel/types@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.7.tgz#54ec75e252318423fc07fb644dc6a58a64c09b7f" + integrity sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg== + dependencies: + "@babel/helper-string-parser" "^7.19.4" + "@babel/helper-validator-identifier" "^7.19.1" + to-fast-properties "^2.0.0" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" From 95bd0da81a6c6993826e4d927c6c9d788822b810 Mon Sep 17 00:00:00 2001 From: Marius Andra Date: Mon, 16 Jan 2023 22:22:58 +0100 Subject: [PATCH 7/9] support extra fields --- src/inline/inline.ts | 95 +++++++++++++++++++++++++++++++------------- yalc.lock | 10 +++++ 2 files changed, 78 insertions(+), 27 deletions(-) create mode 100644 yalc.lock diff --git a/src/inline/inline.ts b/src/inline/inline.ts index 9681783..b030c44 100644 --- a/src/inline/inline.ts +++ b/src/inline/inline.ts @@ -3,9 +3,14 @@ import * as fs from 'fs' import { nodeToString, runThroughPrettier } from '../print/print' import { print, visit } from 'recast' import type { NodePath } from 'ast-types/lib/node-path' +import type { namedTypes } from 'ast-types/gen/namedTypes' import { t, b, visitAllKeaCalls, getAst, assureImport } from '../write/utils' import { factory, SyntaxKind, PropertySignature, Identifier } from 'typescript' import { cleanDuplicateAnyNodes } from '../utils' +import { printInternalExtraInput } from '../print/printInternalExtraInput' +import { printInternalSelectorTypes } from '../print/printInternalSelectorTypes' +import { printInternalReducerActions } from '../print/printInternalReducerActions' +import * as ts from 'typescript' export function inlineFiles( program, @@ -79,6 +84,7 @@ export function inlineFiles( ]) if (foundLogicTypes.has(parsedLogic.logicTypeName)) { const typeAlias: NodePath = foundLogicTypes.get(parsedLogic.logicTypeName) + typeAlias.parentPath.value.comments = createLogicTypeComments(parsedLogic) if (t.TSTypeAliasDeclaration.check(typeAlias.value)) { typeAlias.value.typeAnnotation = createLogicTypeReference(parsedLogic) } @@ -87,14 +93,16 @@ export function inlineFiles( while (ptr) { if (ptr.parentPath?.value === ast.program.body) { const index = ast.program.body.findIndex((n) => n === ptr.value) + const logicTypeNode = b.exportNamedDeclaration( + b.tsTypeAliasDeclaration( + b.identifier(parsedLogic.logicTypeName), + createLogicTypeReference(parsedLogic), + ), + ) + logicTypeNode.comments = createLogicTypeComments(parsedLogic) ast.program.body = [ ...ast.program.body.slice(0, index + 1), - b.exportNamedDeclaration( - b.tsTypeAliasDeclaration( - b.identifier(parsedLogic.logicTypeName), - createLogicTypeReference(parsedLogic), - ), - ), + logicTypeNode, ...ast.program.body.slice(index + 1), ] } @@ -114,20 +122,8 @@ export function inlineFiles( return { filesToWrite: 0, writtenFiles: 0, filesToModify: 0 } } -function sortPropertySignatures( - propertySignatures: (PropertySignature | unknown | null | false)[], -): PropertySignature[] { - return propertySignatures - .filter((a): a is PropertySignature => !!a) - .sort((a, b) => - String((a.name as Identifier)?.escapedText || ('' as string)).localeCompare( - String((a.name as Identifier)?.escapedText || ('' as string)), - ), - ) -} - export function createLogicTypeReference(parsedLogic: ParsedLogic): ReturnType { - const typeReferenceNode = factory.createTypeReferenceNode(factory.createIdentifier('KeaLogicType'), [ + let typeReferenceNode: ts.TypeNode = factory.createTypeReferenceNode(factory.createIdentifier('KeaLogicType'), [ factory.createTypeLiteralNode( [ // actions @@ -135,10 +131,10 @@ export function createLogicTypeReference(parsedLogic: ParsedLogic): ReturnType + [...parsedLogic.actions] + .sort((a, b) => a.name.localeCompare(b.name)) + .map(({ name, parameters, returnTypeNode }) => factory.createPropertySignature( undefined, factory.createIdentifier(name), @@ -146,7 +142,6 @@ export function createLogicTypeReference(parsedLogic: ParsedLogic): ReturnType + cleanDuplicateAnyNodes(parsedLogic.reducers.concat(parsedLogic.selectors)) + .sort((a, b) => a.name.localeCompare(b.name)) + .map((reducer) => factory.createPropertySignature( undefined, factory.createIdentifier(reducer.name), @@ -164,7 +160,6 @@ export function createLogicTypeReference(parsedLogic: ParsedLogic): ReturnType s.functionTypes.length > 0).length > 0 + ? factory.createPropertySignature( + undefined, + factory.createIdentifier('__keaTypeGenInternalSelectorTypes'), + undefined, + printInternalSelectorTypes(parsedLogic), + ) + : null, + + Object.keys(parsedLogic.extraActions).length > 0 + ? factory.createPropertySignature( + undefined, + factory.createIdentifier('__keaTypeGenInternalReducerActions'), + undefined, + printInternalReducerActions(parsedLogic), + ) + : null, + Object.keys(parsedLogic.extraInput).length > 0 + ? factory.createPropertySignature( + undefined, + factory.createIdentifier('__keaTypeGenInternalExtraInput'), + undefined, + printInternalExtraInput(parsedLogic), + ) + : null, ].filter((a) => !!a), ), ]) + if (Object.keys(parsedLogic.extraLogicFields).length > 0) { + typeReferenceNode = factory.createIntersectionTypeNode([ + typeReferenceNode, + factory.createTypeLiteralNode( + Object.entries(parsedLogic.extraLogicFields).map(([key, field]) => + factory.createPropertySignature(undefined, factory.createIdentifier(key), undefined, field), + ), + ), + ]) + } + // Transform Typescript API's AST to a string let source: string = '' try { @@ -208,3 +239,13 @@ export function createLogicTypeReference(parsedLogic: ParsedLogic): ReturnType Date: Mon, 16 Jan 2023 23:30:34 +0100 Subject: [PATCH 8/9] add imports --- src/inline/inline.ts | 74 ++++++++++++++++++++++++++++++++++++++------ src/print/print.ts | 49 ++++++++++++++++------------- 2 files changed, 92 insertions(+), 31 deletions(-) diff --git a/src/inline/inline.ts b/src/inline/inline.ts index b030c44..9b710b6 100644 --- a/src/inline/inline.ts +++ b/src/inline/inline.ts @@ -1,21 +1,22 @@ -import { ParsedLogic } from '../types' +import { AppOptions, ParsedLogic } from '../types' import * as fs from 'fs' -import { nodeToString, runThroughPrettier } from '../print/print' +import { getShouldIgnore, nodeToString, runThroughPrettier } from '../print/print' import { print, visit } from 'recast' import type { NodePath } from 'ast-types/lib/node-path' import type { namedTypes } from 'ast-types/gen/namedTypes' import { t, b, visitAllKeaCalls, getAst, assureImport } from '../write/utils' -import { factory, SyntaxKind, PropertySignature, Identifier } from 'typescript' +import { factory, SyntaxKind, Program } from 'typescript' import { cleanDuplicateAnyNodes } from '../utils' import { printInternalExtraInput } from '../print/printInternalExtraInput' import { printInternalSelectorTypes } from '../print/printInternalSelectorTypes' import { printInternalReducerActions } from '../print/printInternalReducerActions' import * as ts from 'typescript' +import * as path from 'path' export function inlineFiles( - program, - appOptions, - parsedLogics, + program: Program, + appOptions: AppOptions, + parsedLogics: ParsedLogic[], ): { filesToWrite: number; writtenFiles: number; filesToModify: number } { const groupedByFile: Record = {} for (const parsedLogic of parsedLogics) { @@ -37,6 +38,7 @@ export function inlineFiles( let hasImportFromKea = false let foundKeaLogicTypeImport = false + const importedVariables = new Set() visit(ast, { visitTSTypeAliasDeclaration(path): any { @@ -67,6 +69,8 @@ export function inlineFiles( if (path.value.specifiers.length === 0) { path.prune() } + } else { + importedVariables.add(specifier.local?.name ?? specifier.imported?.name) } } @@ -86,7 +90,13 @@ export function inlineFiles( const typeAlias: NodePath = foundLogicTypes.get(parsedLogic.logicTypeName) typeAlias.parentPath.value.comments = createLogicTypeComments(parsedLogic) if (t.TSTypeAliasDeclaration.check(typeAlias.value)) { - typeAlias.value.typeAnnotation = createLogicTypeReference(parsedLogic) + typeAlias.value.typeAnnotation = createLogicTypeReference( + program, + appOptions, + parsedLogic, + importedVariables, + ast.program.body, + ) } } else { let ptr: NodePath = path @@ -96,7 +106,13 @@ export function inlineFiles( const logicTypeNode = b.exportNamedDeclaration( b.tsTypeAliasDeclaration( b.identifier(parsedLogic.logicTypeName), - createLogicTypeReference(parsedLogic), + createLogicTypeReference( + program, + appOptions, + parsedLogic, + importedVariables, + ast.program.body, + ), ), ) logicTypeNode.comments = createLogicTypeComments(parsedLogic) @@ -122,7 +138,13 @@ export function inlineFiles( return { filesToWrite: 0, writtenFiles: 0, filesToModify: 0 } } -export function createLogicTypeReference(parsedLogic: ParsedLogic): ReturnType { +export function createLogicTypeReference( + program: Program, + appOptions: AppOptions, + parsedLogic: ParsedLogic, + importedVariables: Set, + body: namedTypes.Program['body'], +): ReturnType { let typeReferenceNode: ts.TypeNode = factory.createTypeReferenceNode(factory.createIdentifier('KeaLogicType'), [ factory.createTypeLiteralNode( [ @@ -216,6 +238,40 @@ export function createLogicTypeReference(parsedLogic: ParsedLogic): ReturnType 0) { + const shouldIgnore = getShouldIgnore(program, appOptions) + const requiredImports = Object.entries(parsedLogic.typeReferencesToImportFromFiles) + .map(([file, list]): [string, string[]] => [file, [...list].filter((key) => !importedVariables.has(key))]) + .filter(([file, list]) => list.length > 0 && !shouldIgnore(file) && file !== parsedLogic.fileName) + + for (const [file, list] of requiredImports) { + let relativePath = path.relative(path.dirname(parsedLogic.fileName), file) + relativePath = relativePath.replace(/\.tsx?$/, '') + if (!relativePath.startsWith('.')) { + relativePath = `./${relativePath}` + } + + let importDeclaration = body.find( + (node) => t.ImportDeclaration.check(node) && node.source.value === relativePath, + ) as namedTypes.ImportDeclaration | undefined + if (importDeclaration) { + importDeclaration.specifiers.push(b.importSpecifier(b.identifier(list[0]))) + } else { + importDeclaration = b.importDeclaration( + list.map((key) => b.importSpecifier(b.identifier(key))), + b.stringLiteral(relativePath), + ) + let lastIndex = -1 + for (let i = 0; i < body.length; i++) { + if (t.ImportDeclaration.check(body[i])) { + lastIndex = i + } + } + body.splice(lastIndex + 1, 0, importDeclaration) + } + } + } + // Transform Typescript API's AST to a string let source: string = '' try { diff --git a/src/print/print.ts b/src/print/print.ts index ff8fb4d..07240fc 100644 --- a/src/print/print.ts +++ b/src/print/print.ts @@ -73,28 +73,7 @@ export function printToFiles( printLogicType(parsedLogic, appOptions) } - // Automatically ignore imports from "node_modules/@types/node", if {types: ["node"]} in tsconfig.json - const defaultGlobalTypePaths = appOptions.importGlobalTypes - ? [] - : (program.getCompilerOptions().types || []).map( - (type) => - path.join( - appOptions.packageJsonPath ? path.dirname(appOptions.packageJsonPath) : appOptions.rootPath, - 'node_modules', - '@types', - type, - ) + path.sep, - ) - - // Manually ignored - const ignoredImportPaths = (appOptions.ignoreImportPaths || []).map((importPath) => - path.resolve(appOptions.rootPath, importPath), - ) - - const doNotImportFromPaths = [...defaultGlobalTypePaths, ...ignoredImportPaths] - - const shouldIgnore = (absolutePath: string) => - !!doNotImportFromPaths.find((badPath) => absolutePath.startsWith(badPath)) + const shouldIgnore = getShouldIgnore(program, appOptions) let writtenFiles = 0 let filesToWrite = 0 @@ -251,6 +230,32 @@ export function printToFiles( return { filesToWrite, writtenFiles, filesToModify } } +export function getShouldIgnore(program: Program, appOptions: AppOptions): (absolutePath: string) => boolean { + // Automatically ignore imports from "node_modules/@types/node", if {types: ["node"]} in tsconfig.json + const defaultGlobalTypePaths = appOptions.importGlobalTypes + ? [] + : (program.getCompilerOptions().types || []).map( + (type) => + path.join( + appOptions.packageJsonPath ? path.dirname(appOptions.packageJsonPath) : appOptions.rootPath, + 'node_modules', + '@types', + type, + ) + path.sep, + ) + + // Manually ignored + const ignoredImportPaths = (appOptions.ignoreImportPaths || []).map((importPath) => + path.resolve(appOptions.rootPath, importPath), + ) + + const doNotImportFromPaths = [...defaultGlobalTypePaths, ...ignoredImportPaths] + + const shouldIgnore = (absolutePath: string) => + !!doNotImportFromPaths.find((badPath) => absolutePath.startsWith(badPath)) + return shouldIgnore +} + export function nodeToString(node: Node): string { const printer = createPrinter({ newLine: NewLineKind.LineFeed }) const sourceFile = createSourceFile('logic.ts', '', ScriptTarget.Latest, false, ScriptKind.TS) From 20c86cece0df13071b875372171dc86a7a3ecabb Mon Sep 17 00:00:00 2001 From: Marius Andra Date: Mon, 16 Jan 2023 23:45:12 +0100 Subject: [PATCH 9/9] update kea --- package.json | 4 ++-- yalc.lock | 10 ---------- yarn.lock | 25 +++++++++++++++++-------- 3 files changed, 19 insertions(+), 20 deletions(-) delete mode 100644 yalc.lock diff --git a/package.json b/package.json index 4a60958..367f707 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "@babel/preset-env": "^7.16.11", "@babel/preset-typescript": "^7.16.0", "@wessberg/ts-clone-node": "0.3.19", - "prettier": "^2.5.1", + "prettier": "^2.8.3", "recast": "^0.20.5", "yargs": "^16.2.0" }, @@ -43,7 +43,7 @@ "form-plugin": "file:./form-plugin", "husky": ">=4", "jest": "^27.0.5", - "kea": "^3.0.0-alpha.6", + "kea": "^3.1.3", "kea-router": "^3.0.0-alpha.0", "lint-staged": ">=12.1.2", "react": "^16.13.1", diff --git a/yalc.lock b/yalc.lock deleted file mode 100644 index c1aff87..0000000 --- a/yalc.lock +++ /dev/null @@ -1,10 +0,0 @@ -{ - "version": "v1", - "packages": { - "kea": { - "signature": "94abdf4ea4985fbaa3d2e117b926516d", - "file": true, - "replaced": "^3.0.0-alpha.6" - } - } -} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index cbe5c11..68961d3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4203,10 +4203,14 @@ kea-router@^3.0.0-alpha.0: dependencies: url-pattern "^1.0.3" -kea@^3.0.0-alpha.6: - version "3.0.0-alpha.6" - resolved "https://registry.yarnpkg.com/kea/-/kea-3.0.0-alpha.6.tgz#fef0b7f9c66a15df6437ed33a97dd152f2e0e20e" - integrity sha512-uKsuQezYIWW16TB5hTztC7VPsrT9fg0kKz5cy+WS6QPvDE6eMpeuTF6vNdG/WlHKJTKj5E54rp0dk+gcR+KKMA== +kea@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/kea/-/kea-3.1.3.tgz#2bc827cbba88e8b425fee8482acfae1199c8d0ac" + integrity sha512-BmPCe/s/JytLt5kJJgyt7i9ExfRLARJJfrjzxts6czfow0zkftHBGoPirP6+16mA+HIFFLGogu8dnPqQC9iLlw== + dependencies: + redux "^4.2.0" + reselect "^4.1.5" + use-sync-external-store "^1.2.0" kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" @@ -4764,10 +4768,10 @@ prelude-ls@~1.1.2: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= -prettier@^2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a" - integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg== +prettier@^2.8.3: + version "2.8.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.3.tgz#ab697b1d3dd46fb4626fbe2f543afe0cc98d8632" + integrity sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw== pretty-format@^26.0.0, pretty-format@^26.6.2: version "26.6.2" @@ -5657,6 +5661,11 @@ url-pattern@^1.0.3: resolved "https://registry.yarnpkg.com/url-pattern/-/url-pattern-1.0.3.tgz#0409292471b24f23c50d65a47931793d2b5acfc1" integrity sha1-BAkpJHGyTyPFDWWkeTF5PStaz8E= +use-sync-external-store@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" + integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== + use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"