diff --git a/packages/cli/package.json b/packages/cli/package.json index 0c4cc64..2a6db79 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -20,6 +20,7 @@ "author": "smallstonesk", "license": "MIT", "dependencies": { + "@imove/compile-code": "^0.0.1", "body-parser": "^1.19.0", "commander": "^6.0.0", "cors": "^2.8.5", diff --git a/packages/cli/src/cmd/dev/extractCodes.js b/packages/cli/src/cmd/dev/extractCodes.js deleted file mode 100644 index 6bce61c..0000000 --- a/packages/cli/src/cmd/dev/extractCodes.js +++ /dev/null @@ -1,46 +0,0 @@ -const path = require('path'); -const fs = require('fs-extra'); - -const writeEntryFile = async (basePath, fileIds) => { - const imports = []; - const funcMaps = []; - fileIds.forEach((id, idx) => { - const funcName = `fn_${idx}`; - imports.push(`import ${funcName} from './${id}';`); - funcMaps.push(`'${id}': ${funcName}`); - }); - const fileContent = [ - imports.join('\n'), - `const nodeFns = {\n ${funcMaps.join(',\n ')}\n};`, - 'export default nodeFns;', - ].join('\n'); - const entryFilePath = path.join(basePath, 'index.js'); - await fs.outputFile(entryFilePath, fileContent, { encoding: 'utf8', flag: 'w' }); -}; - -const writeNodeCodes = async (basePath, dsl) => { - const fileIds = []; - const { cells = [] } = dsl; - const nodes = cells.filter((cell) => cell.shape !== 'edge'); - for (const { - id, - shape, - data: { label, code }, - } of nodes) { - fileIds.push(id); - const filePath = path.join(basePath, id + '.js'); - const preData = `// ${shape}: ${label}\n`; - const saveData = `${preData}\n${code}`; - await fs.outputFile(filePath, saveData, { encoding: 'utf8', flag: 'w' }); - } - return fileIds; -}; - -const setup = async (dsl, logicBasePath) => { - const nodeCodesPath = path.join(logicBasePath, 'nodeFns'); - await fs.remove(nodeCodesPath); - const fileIds = await writeNodeCodes(nodeCodesPath, dsl); - await writeEntryFile(nodeCodesPath, fileIds); -}; - -module.exports = setup; diff --git a/packages/cli/src/cmd/dev/index.js b/packages/cli/src/cmd/dev/index.js index f313c9d..349b53e 100644 --- a/packages/cli/src/cmd/dev/index.js +++ b/packages/cli/src/cmd/dev/index.js @@ -2,17 +2,27 @@ const path = require('path'); const fs = require('fs-extra'); const Base = require('../base'); const mergePkg = require('./mergePkg'); -const addPlugins = require('./addPlugins'); -const simplifyDSL = require('./simplifyDSL'); -const extractCodes = require('./extractCodes'); +const compileCode = require('@imove/compile-code'); const { createServer } = require('../../utils/server'); const noop = () => {}; -const TPL_PATH = path.join(__dirname, './template'); const CACHE_PATH = path.join(process.cwd(), './.cache'); const CACHE_DSL_FILE = path.join(CACHE_PATH, 'imove.dsl.json'); class Dev extends Base { + + async writeOutputIntoFiles(curPath, output) { + for(let key in output) { + const newPath = path.join(curPath, key); + if(path.extname(newPath)) { + await fs.writeFile(newPath, output[key]); + } else { + await fs.ensureDir(newPath); + await this.writeOutputIntoFiles(newPath, output[key]); + } + } + } + async save(req, res) { const { outputPath, plugins = [] } = this.config; @@ -28,10 +38,8 @@ class Dev extends Base { // compile try { const { dsl } = req.body; - await simplifyDSL(dsl, outputPath); - await extractCodes(dsl, outputPath); - await fs.copy(TPL_PATH, outputPath); - await addPlugins(plugins, outputPath); + const output = compileCode(dsl, plugins); + await this.writeOutputIntoFiles(outputPath, output); await mergePkg(dsl, this.projectPath); await fs.outputFile(CACHE_DSL_FILE, JSON.stringify(dsl, null, 2)); res.status(200).json({ isCompiled: true }).end(); diff --git a/packages/cli/src/cmd/dev/simplifyDSL.js b/packages/cli/src/cmd/dev/simplifyDSL.js deleted file mode 100644 index 53867de..0000000 --- a/packages/cli/src/cmd/dev/simplifyDSL.js +++ /dev/null @@ -1,35 +0,0 @@ -const path = require('path'); -const fs = require('fs-extra'); - -const extractObj = (obj = {}, keys = []) => { - const ret = {}; - keys.forEach((key) => { - if (obj[key]) { - ret[key] = obj[key]; - } - }); - return ret; -}; - -const simplify = (dsl) => { - const { cells = [] } = dsl; - return { - cells: cells.map((cell) => { - if (cell.shape === 'edge') { - return extractObj(cell, ['id', 'shape', 'source', 'target']); - } else { - const newCell = extractObj(cell, ['id', 'shape']); - newCell.data = extractObj(cell.data, ['trigger', 'configData']); - return newCell; - } - }), - }; -}; - -const setup = async (dsl, logicBasePath) => { - const simpilifiedDSL = simplify(dsl); - const dslFilePath = path.join(logicBasePath, 'dsl.json'); - await fs.writeFile(dslFilePath, JSON.stringify(simpilifiedDSL, null, 2)); -}; - -module.exports = setup; diff --git a/packages/compile-code/.babelrc b/packages/compile-code/.babelrc new file mode 100644 index 0000000..633f93f --- /dev/null +++ b/packages/compile-code/.babelrc @@ -0,0 +1,3 @@ +{ + "extends": "../../.babelrc" +} diff --git a/packages/compile-code/.npmignore b/packages/compile-code/.npmignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/packages/compile-code/.npmignore @@ -0,0 +1 @@ +node_modules diff --git a/packages/compile-code/README.md b/packages/compile-code/README.md new file mode 100644 index 0000000..23f9272 --- /dev/null +++ b/packages/compile-code/README.md @@ -0,0 +1 @@ +# @imove/compile-code \ No newline at end of file diff --git a/packages/compile-code/package.json b/packages/compile-code/package.json new file mode 100644 index 0000000..6f6a6e7 --- /dev/null +++ b/packages/compile-code/package.json @@ -0,0 +1,41 @@ +{ + "name": "@imove/compile-code", + "version": "0.0.1", + "description": "imove compile code", + "main": "dist/core.common.js", + "module": "dist/core.esm.js", + "types": "dist/types/index.d.ts", + "directories": { + "dist": "dist" + }, + "files": [ + "dist" + ], + "publishConfig": { + "access": "public", + "registry": "http://registry.npmjs.org/" + }, + "keywords": [ + "imove", + "compile code" + ], + "scripts": { + "prepublishOnly": "node scripts/prepublish.js", + "declare-type": "tsc --emitDeclarationOnly", + "build": "rollup -c & npm run declare-type", + "watch": "watch 'npm run build' ./src" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/imgcook/iMove.git" + }, + "author": "smallstonesk", + "license": "MIT", + "dependencies": { + "@antv/x6": "^1.5.1" + }, + "devDependencies": { + "rollup": "^2.7.3", + "watch": "^1.0.2" + } +} diff --git a/packages/compile-code/rollup.config.js b/packages/compile-code/rollup.config.js new file mode 100644 index 0000000..95d7542 --- /dev/null +++ b/packages/compile-code/rollup.config.js @@ -0,0 +1,17 @@ +import path from 'path'; +import rollupBaseConfig from '../../rollup.config'; +import pkg from './package.json'; + +export default Object.assign(rollupBaseConfig, { + input: path.join(__dirname, './src/index.ts'), + output: [ + { + file: pkg.main, + format: 'cjs', + }, + { + file: pkg.module, + format: 'es', + }, + ] +}); diff --git a/packages/compile-code/scripts/prepublish.js b/packages/compile-code/scripts/prepublish.js new file mode 100644 index 0000000..7dd2753 --- /dev/null +++ b/packages/compile-code/scripts/prepublish.js @@ -0,0 +1,6 @@ +#!/usr/bin/env node + +const path = require('path'); +const prePublish = require('../../../scripts/prepublish'); + +prePublish('@imove/plugin-store', path.join(__dirname, '../')); diff --git a/packages/cli/src/cmd/dev/addPlugins.js b/packages/compile-code/src/addPlugins.ts similarity index 56% rename from packages/cli/src/cmd/dev/addPlugins.js rename to packages/compile-code/src/addPlugins.ts index 6e58b40..234ff93 100644 --- a/packages/cli/src/cmd/dev/addPlugins.js +++ b/packages/compile-code/src/addPlugins.ts @@ -1,20 +1,16 @@ -const path = require('path'); -const fs = require('fs-extra'); const INSERT_IMPORT_PLUGINS_COMMENT = '// import plugins here'; const INSERT_USE_PLUGINS_COMMENT = '// use plugins here'; -const setup = async (plugins = [], logicBasePath) => { - const entryFilePath = path.join(logicBasePath, 'index.js'); - const codes = await fs.readFile(entryFilePath, 'utf8'); - const modifiedContent = codes +const addPlugins = (originalCode: string = '', plugins: string[] = []): string => { + const modifiedContent: string = originalCode .replace(new RegExp(INSERT_IMPORT_PLUGINS_COMMENT), () => { return plugins.map((plugin, index) => `import plugin${index} from '${plugin}';`).join('\n'); }) .replace(new RegExp(INSERT_USE_PLUGINS_COMMENT), () => { return plugins.map((_, index) => `logic.use(plugin${index});`).join('\n'); }); - await fs.outputFile(entryFilePath, modifiedContent); + return modifiedContent; }; -module.exports = setup; +export default addPlugins; diff --git a/packages/compile-code/src/extractNodeFns.ts b/packages/compile-code/src/extractNodeFns.ts new file mode 100644 index 0000000..1cbb194 --- /dev/null +++ b/packages/compile-code/src/extractNodeFns.ts @@ -0,0 +1,52 @@ +import {Cell} from '@antv/x6'; + +interface DSL { + cells: Cell.Properties[]; +} + +interface INodesFns { + [fileName: string]: string; +} + +const genEntryFile = (nodeIds: string[]): string => { + const imports: string[] = []; + const funcMaps: string[] = []; + nodeIds.forEach((id, idx) => { + const funcName = `fn_${idx}`; + imports.push(`import ${funcName} from './${id}';`); + funcMaps.push(`'${id}': ${funcName}`); + }); + const fileContent: string = [ + imports.join('\n'), + `const nodeFns = {\n ${funcMaps.join(',\n ')}\n};`, + 'export default nodeFns;', + ].join('\n'); + return fileContent; +}; + +const genNodeFns = (dsl: DSL): INodesFns => { + const nodeFns: INodesFns = {}; + const { cells = [] } = dsl; + const nodes = cells.filter((cell) => cell.shape !== 'edge'); + for (const { + id, + shape, + data: { label, code }, + } of nodes) { + const fileName: string = id + '.js'; + const descData: string = `// ${shape}: ${label}\n`; + const saveData: string = `${descData}\n${code}`; + nodeFns[fileName] = saveData; + } + return nodeFns; +}; + +const extract = (dsl: DSL): INodesFns => { + const nodeFns = genNodeFns(dsl); + const nodeIds = Object.keys(nodeFns).map(fileName => fileName.slice(0, -3)); + const entryFileContent = genEntryFile(nodeIds); + nodeFns['index.js'] = entryFileContent; + return nodeFns; +}; + +export default extract; diff --git a/packages/compile-code/src/index.ts b/packages/compile-code/src/index.ts new file mode 100644 index 0000000..2d48d3a --- /dev/null +++ b/packages/compile-code/src/index.ts @@ -0,0 +1,34 @@ +import {Cell} from '@antv/x6'; +import addPlugins from './addPlugins'; +import simplifyDSL from './simplifyDSL'; +import extractNodeFns from './extractNodeFns'; +import logicTpl from './template/logic'; +import indexTpl from './template/index'; +import contextTpl from './template/context'; + +interface DSL { + cells: Cell.Properties[]; +} + +interface IOutput { + 'nodeFns': { + [fileName: string]: string + }; + 'context.js': string; + 'dsl.json': string; + 'index.js': string; + 'logic.js': string; +} + +const compile = (dsl: DSL, plugins = []): IOutput => { + const output: IOutput = { + 'nodeFns': extractNodeFns(dsl), + "context.js": contextTpl, + 'dsl.json': JSON.stringify(simplifyDSL(dsl), null, 2), + 'index.js': addPlugins(indexTpl, plugins), + 'logic.js': logicTpl + }; + return output; +}; + +export default compile; diff --git a/packages/compile-code/src/simplifyDSL.ts b/packages/compile-code/src/simplifyDSL.ts new file mode 100644 index 0000000..197ded9 --- /dev/null +++ b/packages/compile-code/src/simplifyDSL.ts @@ -0,0 +1,32 @@ +import {Cell} from '@antv/x6'; + +interface DSL { + cells: Cell.Properties[]; +} + +const extractObj = (obj: Cell.Properties = {}, keys: string[] = []): Cell.Properties => { + const ret: Cell.Properties = {}; + keys.forEach((key) => { + if (obj[key]) { + ret[key] = obj[key]; + } + }); + return ret; +}; + +const simplifyDSL = (dsl: DSL): Cell.Properties => { + const { cells = [] } = dsl; + return { + cells: cells.map((cell) => { + if (cell.shape === 'edge') { + return extractObj(cell, ['id', 'shape', 'source', 'target']); + } else { + const newCell = extractObj(cell, ['id', 'shape', 'data']); + newCell.data = extractObj(cell.data, ['trigger', 'configData', 'ports']); + return newCell; + } + }), + }; +}; + +export default simplifyDSL; diff --git a/packages/cli/src/cmd/dev/template/context.js b/packages/compile-code/src/template/context.ts similarity index 93% rename from packages/cli/src/cmd/dev/template/context.js rename to packages/compile-code/src/template/context.ts index 827c60d..962c8d0 100644 --- a/packages/cli/src/cmd/dev/template/context.js +++ b/packages/compile-code/src/template/context.ts @@ -1,4 +1,4 @@ -export default class Context { +export default `export default class Context { constructor(opts) { this._init(opts); } @@ -42,3 +42,4 @@ export default class Context { }); } } +`; diff --git a/packages/cli/src/cmd/dev/template/index.js b/packages/compile-code/src/template/index.ts similarity index 73% rename from packages/cli/src/cmd/dev/template/index.js rename to packages/compile-code/src/template/index.ts index 4729f8a..ee3017b 100644 --- a/packages/cli/src/cmd/dev/template/index.js +++ b/packages/compile-code/src/template/index.ts @@ -1,4 +1,4 @@ -import Logic from './logic'; +export default `import Logic from './logic'; import dsl from './dsl.json'; // import plugins here @@ -7,3 +7,4 @@ const logic = new Logic({ dsl }); // use plugins here export default logic; +`; diff --git a/packages/cli/src/cmd/dev/template/logic.js b/packages/compile-code/src/template/logic.ts similarity index 88% rename from packages/cli/src/cmd/dev/template/logic.js rename to packages/compile-code/src/template/logic.ts index e9d37bc..563f9ad 100644 --- a/packages/cli/src/cmd/dev/template/logic.js +++ b/packages/compile-code/src/template/logic.ts @@ -1,4 +1,4 @@ -import nodeFns from './nodeFns'; +export default `import nodeFns from './nodeFns'; import Context from './context'; import EventEmitter from 'eventemitter3'; @@ -34,7 +34,7 @@ export default class Logic extends EventEmitter { _runLifecycleEvent(eventName, ctx) { if (!LIFECYCLE.has(eventName)) { - return console.warn(`Lifecycle ${eventName} is not supported!`); + return console.warn(\`Lifecycle \${eventName} is not supported!\`); } if (this.lifeCycleEvents[eventName]) { this.lifeCycleEvents[eventName].forEach((fn) => fn(ctx)); @@ -66,10 +66,7 @@ export default class Logic extends EventEmitter { const { ports } = curNode.data; for (const key in ports) { const { condition } = ports[key]; - const ret = ((ctx) => { - return condition; - })(ctx); - // const ret = new Function('ctx', 'return ' + condition)(ctx); + const ret = new Function('ctx', 'return ' + condition)(ctx); if (ret === Boolean(curRet)) { matchedPort = key; break; @@ -101,7 +98,7 @@ export default class Logic extends EventEmitter { continue; } if (!LIFECYCLE.has(eventName)) { - console.warn(`Lifecycle ${eventName} is not supported in imove.`); + console.warn(\`Lifecycle \${eventName} is not supported in imove.\`); continue; } if (!this.lifeCycleEvents[eventName]) { @@ -129,9 +126,10 @@ export default class Logic extends EventEmitter { async invoke(trigger, data) { const curNode = this._getStartNode(trigger); if (!curNode) { - return Promise.reject(new Error(`Invoke failed! No logic-start named ${trigger} found!`)); + return Promise.reject(new Error(\`Invoke failed! No logic-start named \${trigger} found!\`)); } const ctx = this._createCtx({ payload: data }); await this._execNode(ctx, curNode); } } +`; diff --git a/packages/compile-code/tsconfig.json b/packages/compile-code/tsconfig.json new file mode 100644 index 0000000..61ac029 --- /dev/null +++ b/packages/compile-code/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig", + "compilerOptions": { + "outDir": "dist/types" + }, + "include": ["./src", "./types"] +}