diff --git a/cli/cli.ts b/cli/cli.ts index 463ab2c..154721c 100644 --- a/cli/cli.ts +++ b/cli/cli.ts @@ -1,8 +1,15 @@ #!/usr/bin/env node import * as program from "commander"; -import { ComposeFile, ComposeDirectory, InspectDirectory, InspectFile } from "./literator"; +import { + ComposeFile, + ComposeDirectory, + InspectDirectory, + InspectFile, + ITypeDraftConfig, +} from "./literator"; import { resolve } from "path"; import { readJSONSync, lstatSync } from "fs-extra"; +import { cosmiconfigSync } from "cosmiconfig"; const package_json = readJSONSync(resolve(__dirname, "../../package.json")); program.version(package_json.version); @@ -18,10 +25,19 @@ if (args.length === 0) { const [target] = args; if (target) { const path = resolve(working_directory, target); + + // find config + const config_info = cosmiconfigSync("typedraft").search(); + let config: ITypeDraftConfig = { DSLs: [], DraftPlugins: [] }; + if (config_info && !config_info.isEmpty) { + config = { ...config, ...config_info.config }; + } + + // if (lstatSync(path).isDirectory()) { - program.watch ? InspectDirectory(path) : ComposeDirectory(path); + program.watch ? InspectDirectory(path, config) : ComposeDirectory(path, config); } else { - program.watch ? InspectFile(path) : ComposeFile(path); + program.watch ? InspectFile(path, config) : ComposeFile(path, config); } } } diff --git a/cli/literator.ts b/cli/literator.ts index a8544df..1e2eafb 100644 --- a/cli/literator.ts +++ b/cli/literator.ts @@ -1,8 +1,35 @@ import * as traverse from "filewalker"; import { default as watch } from "node-watch"; import { outputFileSync, removeSync, readFileSync } from "fs-extra"; -import { MakeDefaultTranscriber } from "../src"; +import { MakeDefaultTranscriber, IDSL, IPlugin, Transcriber } from "../src"; +/** + * + */ +export interface ITypeDraftConfig { + DSLs: Array<{ name: string; dsl: () => IDSL }>; + DraftPlugins: Array; +} + +export function MakeTranscriberWithConfig(code: string, config: ITypeDraftConfig) { + const transcriber = MakeDefaultTranscriber(code); + + config.DSLs.forEach(({ name, dsl }) => { + transcriber.AddDSL(name, dsl()); + }); + + if (config.DraftPlugins.length !== 0) { + transcriber.m_Plugins = config.DraftPlugins.map(PluginConstructor => + Reflect.construct(PluginConstructor, [transcriber]) + ); + } + + return transcriber; +} + +/** + * + */ function TraverseDirectory(path: string, callback: (name: string, path: string) => void) { const action = (relative: string, stats, absolute: string) => callback(relative, absolute); traverse(path) @@ -11,14 +38,14 @@ function TraverseDirectory(path: string, callback: (name: string, path: string) .walk(); } -export function InspectDirectory(path: string) { - ComposeDirectory(path); +export function InspectDirectory(path: string, config?: ITypeDraftConfig) { + ComposeDirectory(path, config); watch(path, { recursive: true }, (event, name: string) => { if (name.endsWith(".tsx")) { console.log(event, name); try { - ComposeFile(name); + ComposeFile(name, config); } catch (error) { console.log(error.message); } @@ -26,14 +53,14 @@ export function InspectDirectory(path: string) { }); } -export function InspectFile(path: string) { - ComposeFile(path); +export function InspectFile(path: string, config?: ITypeDraftConfig) { + ComposeFile(path, config); watch(path, (event, name: string) => { if (name.endsWith(".tsx")) { console.log(event, name); try { - ComposeFile(name); + ComposeFile(name, config); } catch (error) { console.log(error.message); } @@ -41,11 +68,11 @@ export function InspectFile(path: string) { }); } -export function ComposeDirectory(path: string) { +export function ComposeDirectory(path: string, config?: ITypeDraftConfig) { TraverseDirectory(path, (relative: string, absolute: string) => { if (absolute.endsWith(".tsx")) { try { - ComposeFile(absolute); + ComposeFile(absolute, config); } catch (error) { console.log(`compose file failed: ${error.message}, source: ${relative}`); } @@ -61,9 +88,11 @@ export function CrossoutDirectory(path: string) { }); } -export function ComposeFile(source: string) { +export function ComposeFile(source: string, config?: ITypeDraftConfig) { const code = readFileSync(source, "utf8"); - const transcriber = MakeDefaultTranscriber(code); + const transcriber = config + ? MakeTranscriberWithConfig(code, config) + : MakeDefaultTranscriber(code); const result = transcriber.Transcribe(); outputFileSync(source.replace(".tsx", ".ts"), result, "utf8"); } diff --git a/package-lock.json b/package-lock.json index ff7af69..234a1e5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -524,8 +524,7 @@ "@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, "@types/stack-utils": { "version": "1.0.1", @@ -1432,8 +1431,7 @@ "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" }, "camelcase": { "version": "5.3.1", @@ -1747,7 +1745,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", - "dev": true, "requires": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.1.0", @@ -1760,7 +1757,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", - "dev": true, "requires": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -1771,8 +1767,7 @@ "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" } } }, @@ -2189,7 +2184,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, "requires": { "is-arrayish": "^0.2.1" } @@ -3127,7 +3121,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", - "dev": true, "requires": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -3136,8 +3129,7 @@ "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" } } }, @@ -3217,8 +3209,7 @@ "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" }, "is-binary-path": { "version": "2.1.0", @@ -4000,8 +3991,7 @@ "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" }, "json-schema": { "version": "0.2.3", @@ -4141,8 +4131,7 @@ "lines-and-columns": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "dev": true + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" }, "linkify-it": { "version": "2.2.0", @@ -4982,7 +4971,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, "requires": { "callsites": "^3.0.0" } @@ -7335,8 +7323,7 @@ "yaml": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz", - "integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==", - "dev": true + "integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==" }, "yargs": { "version": "13.3.2", diff --git a/package.json b/package.json index d98c6de..ab0382b 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "dependencies": { "@babel/core": "^7.6.2", "commander": "^4.0.1", + "cosmiconfig": "^6.0.0", "filewalker": "^0.1.3", "fs-extra": "^8.1.0", "node-watch": "^0.6.3", diff --git a/src/code-object/inline-context.tsx b/src/code-object/inline-context.tsx index 6be8225..3b1b197 100644 --- a/src/code-object/inline-context.tsx +++ b/src/code-object/inline-context.tsx @@ -22,7 +22,11 @@ export class InlineContext { + function Resolve(this: InlineContext & IInlineContext, dsl: IDSL) { - this.m_Code.body = dsl.Transcribe(this.ToStatements(), this.m_Path); + if (dsl.m_Merge) { + this.m_Path.replaceWithMultiple(dsl.Transcribe(this.ToStatements(), this.m_Path)); + } else { + this.m_Code.body = dsl.Transcribe(this.ToStatements(), this.m_Path); + } }; + diff --git a/src/core/transcriber.tsx b/src/core/transcriber.tsx index ee717fe..e75ffc8 100644 --- a/src/core/transcriber.tsx +++ b/src/core/transcriber.tsx @@ -32,12 +32,8 @@ export class Transcriber { /** * # Utility * Other methods are just utilities. - * - * ## Plugin */ - + function PreparePlugins(this: Transcriber & ITranscriber) {}; - /** * ## DSL */ @@ -52,8 +48,6 @@ export class Transcriber { return this.m_DSLMap.get(name); }; - + function PrepareDSLs(this: Transcriber) {}; - /** * ## Context and Class */ @@ -94,9 +88,7 @@ export class Transcriber { this.m_ContextMap = new Map(); this.m_InlineContextMap = new Map(); this.m_DSLMap = new Map(); - - this.PrepareDSLs(); - this.PreparePlugins(); + this.m_Plugins = new Array(); }; export interface IDSL { @@ -104,6 +96,8 @@ export interface IDSL { block: Array, path?: NodePath | NodePath ): Array; + + m_Merge?: boolean; } export interface IPlugin { @@ -111,8 +105,9 @@ export interface IPlugin { } export interface ITranscriber { - PrepareDSLs: () => void; - PreparePlugins: () => void; + Transcribe: () => string; + + AddDSL: (name: string, dsl: IDSL) => void; GetDSL: (name: string) => IDSL; GetClass: (name: string) => ExportClassCode; @@ -133,6 +128,7 @@ export interface ITranscriber { m_InlineContextMap: Map; m_DSLMap: Map; + m_Plugins: Array; } export type TraverseLocalContextCallback = (context: LocalContext, name: string) => void; diff --git a/src/index.ts b/src/index.ts index b8cfdbf..ce5ec09 100644 --- a/src/index.ts +++ b/src/index.ts @@ -17,14 +17,14 @@ export * from "./common/utility"; /** * */ -import { Transcriber } from "./core/transcriber"; +import { Transcriber, ITranscriber } from "./core/transcriber"; import { RefreshDraftPlugin } from "./plug-in/draft-plugin-refresh"; import { DSLPlugin } from "./plug-in/draft-plugin-dsl"; import { LocalContextPlugin } from "./plug-in/draft-plugin-local-context"; import { ClassPlugin } from "./plug-in/draft-plugin-class"; import { FilterPlugin } from "./plug-in/draft-plugin-filter"; -export function MakeDefaultTranscriber(_module: string) { +export function MakeDefaultTranscriber(_module: string): ITranscriber { const transcriber = new Transcriber(_module); transcriber.m_Plugins = [ new RefreshDraftPlugin(transcriber), diff --git a/test/plug-in/__snapshots__/dsl.test.ts.snap b/test/plug-in/__snapshots__/dsl.test.ts.snap index 212325b..94a13a0 100644 --- a/test/plug-in/__snapshots__/dsl.test.ts.snap +++ b/test/plug-in/__snapshots__/dsl.test.ts.snap @@ -10,6 +10,14 @@ exports[`inline context 1`] = ` }" `; +exports[`inline context: merge 1`] = ` +"export function Main() { + console.log(\\"hello\\"); + console.log(\\"current\\"); + console.log(\\"world\\"); +}" +`; + exports[`local context added after dsl resolved 1`] = ` "export function Main() { if (value === \\"a\\") { diff --git a/test/plug-in/dsl.test.ts b/test/plug-in/dsl.test.ts index 58c7bd0..0fc8191 100644 --- a/test/plug-in/dsl.test.ts +++ b/test/plug-in/dsl.test.ts @@ -10,6 +10,12 @@ import { NodePath } from "@babel/traverse"; import { PatternMatch } from "draft-dsl-match"; class Foo implements IDSL { + m_Merge: boolean; + + constructor(merge: boolean = false) { + this.m_Merge = merge; + } + Transcribe(block: Array): Array { const transcribed = ToAst(` console.log("current"); @@ -155,3 +161,21 @@ test("inline context", () => { const result = transcriber.Transcribe(); expect(result).toMatchSnapshot(); }); + +test("inline context: merge", () => { + const code = ` + export function Main(){ + console.log("hello"); + { + 'use foo'; + console.log("previous"); + } + console.log("world"); + } + `; + + const transcriber = MakeDefaultTranscriber(code); + transcriber.AddDSL("foo", new Foo(true)); + const result = transcriber.Transcribe(); + expect(result).toMatchSnapshot(); +});