Browse Source

refactor: extract compiling code into package @imove/compile-code

master
smallstonesk 5 years ago
parent
commit
bb7b667043
  1. 1
      packages/cli/package.json
  2. 46
      packages/cli/src/cmd/dev/extractCodes.js
  3. 24
      packages/cli/src/cmd/dev/index.js
  4. 35
      packages/cli/src/cmd/dev/simplifyDSL.js
  5. 3
      packages/compile-code/.babelrc
  6. 1
      packages/compile-code/.npmignore
  7. 1
      packages/compile-code/README.md
  8. 41
      packages/compile-code/package.json
  9. 17
      packages/compile-code/rollup.config.js
  10. 6
      packages/compile-code/scripts/prepublish.js
  11. 12
      packages/compile-code/src/addPlugins.ts
  12. 52
      packages/compile-code/src/extractNodeFns.ts
  13. 34
      packages/compile-code/src/index.ts
  14. 32
      packages/compile-code/src/simplifyDSL.ts
  15. 3
      packages/compile-code/src/template/context.ts
  16. 3
      packages/compile-code/src/template/index.ts
  17. 14
      packages/compile-code/src/template/logic.ts
  18. 7
      packages/compile-code/tsconfig.json

1
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",

46
packages/cli/src/cmd/dev/extractCodes.js

@ -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;

24
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();

35
packages/cli/src/cmd/dev/simplifyDSL.js

@ -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;

3
packages/compile-code/.babelrc

@ -0,0 +1,3 @@
{
"extends": "../../.babelrc"
}

1
packages/compile-code/.npmignore

@ -0,0 +1 @@
node_modules

1
packages/compile-code/README.md

@ -0,0 +1 @@
# @imove/compile-code

41
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"
}
}

17
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',
},
]
});

6
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, '../'));

12
packages/cli/src/cmd/dev/addPlugins.js → 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;

52
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;

34
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;

32
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;

3
packages/cli/src/cmd/dev/template/context.js → 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 {
});
}
}
`;

3
packages/cli/src/cmd/dev/template/index.js → 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;
`;

14
packages/cli/src/cmd/dev/template/logic.js → 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);
}
}
`;

7
packages/compile-code/tsconfig.json

@ -0,0 +1,7 @@
{
"extends": "../../tsconfig",
"compilerOptions": {
"outDir": "dist/types"
},
"include": ["./src", "./types"]
}
Loading…
Cancel
Save