UNPKG

@lunora/cli

Version:

The Lunora CLI: init, dev, deploy, codegen, run, reset, and migrate commands

65 lines (62 loc) 2.28 kB
import { Project, SyntaxKind, Node } from 'ts-morph'; const VALID_JS_IDENTIFIER = /^[A-Za-z_$][\w$]*$/u; const startMarker = (key) => `// lunora:add:${key}:start`; const endMarker = (key) => `// lunora:add:${key}:end`; const extensionImportSpecifier = (key) => `./${key}/schema`; const findDefineSchemaCall = (callExpressions) => { for (const call of callExpressions) { if (call.getExpression().getText() === "defineSchema") { return call; } } return void 0; }; const outermostChainExpression = (defineSchemaCall) => { let node = defineSchemaCall; for (let parent = node.getParent(); parent !== void 0; parent = node.getParent()) { if (Node.isPropertyAccessExpression(parent) && parent.getExpression() === node) { node = parent; } else if (Node.isCallExpression(parent) && parent.getExpression() === node) { node = parent; } else { break; } } return node; }; const insertSchemaExtension = (source, key) => { if (!VALID_JS_IDENTIFIER.test(key)) { return { ok: false, reason: "invalid-identifier" }; } if (source.includes(startMarker(key))) { return { ok: false, reason: "already-applied" }; } const project = new Project({ compilerOptions: { allowJs: true }, useInMemoryFileSystem: true }); const sourceFile = project.createSourceFile("schema.ts", source, { overwrite: true }); const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression); const defineSchemaCall = findDefineSchemaCall(callExpressions); if (!defineSchemaCall) { return { ok: false, reason: "no-define-schema" }; } const tablesArgument = defineSchemaCall.getArguments()[0]; if (tablesArgument?.getKind() !== SyntaxKind.ObjectLiteralExpression) { return { ok: false, reason: "non-object-argument" }; } const insertAt = outermostChainExpression(defineSchemaCall).getEnd(); const chainText = ` ${startMarker(key)} .extend(${key}.extension) ${endMarker(key)} `; sourceFile.insertText(insertAt, chainText); const importText = `${startMarker(key)} import { ${key} } from "${extensionImportSpecifier(key)}"; ${endMarker(key)} `; sourceFile.insertText(0, importText); return { ok: true, text: sourceFile.getFullText() }; }; export { insertSchemaExtension };