@imove/compile-code
Advanced tools
Comparing version 0.0.1 to 0.1.0
'use strict'; | ||
var INSERT_IMPORT_PLUGINS_COMMENT = '// import plugins here'; | ||
var INSERT_USE_PLUGINS_COMMENT = '// use plugins here'; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
var addPlugins = function addPlugins(originalCode, plugins) { | ||
if (originalCode === void 0) { | ||
originalCode = ''; | ||
} | ||
var logicTpl = "import nodeFns from './nodeFns';\nimport Context from './context';\nimport EventEmitter from 'eventemitter3';\n\nconst LIFECYCLE = new Set(['ctxCreated', 'enterNode', 'leaveNode']);\nconst SHAPES = {\n START: 'imove-start',\n BRANCH: 'imove-branch',\n BEHAVIOR: 'imove-behavior',\n};\n\nexport default class Logic extends EventEmitter {\n constructor(opts = {}) {\n super();\n this.dsl = opts.dsl;\n this.lifeCycleEvents = {};\n }\n\n get cells() {\n return this.dsl.cells;\n }\n\n get nodes() {\n return this.cells.filter((cell) => cell.shape !== 'edge');\n }\n\n get startNodes() {\n return this.cells.filter((cell) => cell.shape === SHAPES.START);\n }\n\n get edges() {\n return this.cells.filter((cell) => cell.shape === 'edge');\n }\n\n _getUnsafeCtx() {\n // NOTE: don't use in prod\n return this._unsafeCtx;\n }\n\n _runLifecycleEvent(eventName, ctx) {\n if (!LIFECYCLE.has(eventName)) {\n return console.warn(`Lifecycle ${eventName} is not supported!`);\n }\n if (this.lifeCycleEvents[eventName]) {\n this.lifeCycleEvents[eventName].forEach((fn) => fn(ctx));\n }\n }\n\n _createCtx(opts) {\n const ctx = new Context(opts);\n ctx.emit = this.emit.bind(this);\n this._runLifecycleEvent('ctxCreated', ctx);\n return ctx;\n }\n\n _getStartNode(trigger) {\n for (const cell of this.startNodes) {\n if (cell.data.trigger === trigger) {\n return cell;\n }\n }\n }\n\n _getNextNodes(ctx, curNode, curRet) {\n const nodes = [];\n for (const edge of this.edges) {\n let isMatched = edge.source.cell === curNode.id;\n // NOTE: if it is a imove-branch node, each port's condition should be tested whether it is matched\n if (curNode.shape === SHAPES.BRANCH) {\n let matchedPort = '';\n const { ports } = curNode.data;\n for (const key in ports) {\n const { condition } = ports[key];\n const ret = new Function('ctx', 'return ' + condition)(ctx);\n if (ret === Boolean(curRet)) {\n matchedPort = key;\n break;\n }\n }\n isMatched = isMatched && edge.source.port === matchedPort;\n }\n if (isMatched) {\n // NOTE: not each edge both has source and target\n const nextNode = this.nodes.find((item) => item.id === edge.target.cell);\n nextNode && nodes.push(nextNode);\n }\n }\n return nodes;\n }\n\n use(pluginCreator) {\n if (typeof pluginCreator !== 'function') {\n console.error('imove plugin must be a function.');\n return;\n }\n const plugin = pluginCreator(this);\n if (typeof plugin !== 'object' || plugin === null) {\n console.error('imove plugin must return an object.');\n return;\n }\n for (const eventName in plugin) {\n if (!Object.prototype.hasOwnProperty.call(plugin, eventName)) {\n continue;\n }\n if (!LIFECYCLE.has(eventName)) {\n console.warn(`Lifecycle ${eventName} is not supported in imove.`);\n continue;\n }\n if (!this.lifeCycleEvents[eventName]) {\n this.lifeCycleEvents[eventName] = [];\n }\n this.lifeCycleEvents[eventName].push(plugin[eventName]);\n }\n }\n\n async _execNode(ctx, curNode, lastRet, callback) {\n ctx._transitTo(curNode, lastRet);\n const fn = nodeFns[curNode.id];\n this._runLifecycleEvent('enterNode', ctx);\n const curRet = await fn(ctx);\n this._runLifecycleEvent('leaveNode', ctx);\n if (curNode.shape !== SHAPES.BRANCH) {\n lastRet = curRet;\n }\n const nextNodes = this._getNextNodes(ctx, curNode, curRet);\n if (nextNodes.length > 0) {\n nextNodes.forEach(async (node) => {\n await this._execNode(ctx, node, lastRet, callback);\n });\n } else {\n callback && callback(lastRet);\n }\n }\n\n async invoke(trigger, data, callback) {\n const curNode = this._getStartNode(trigger);\n if (!curNode) {\n return Promise.reject(new Error(`Invoke failed! No logic-start named ${trigger} found!`));\n }\n this._unsafeCtx = this._createCtx({ payload: data });\n await this._execNode(this._unsafeCtx, curNode, undefined, callback);\n }\n}\n"; | ||
if (plugins === void 0) { | ||
plugins = []; | ||
} | ||
var contextTpl = "export default class Context {\n constructor(opts) {\n this._init(opts);\n }\n\n _init(opts = {}) {\n const { payload = {} } = opts;\n this.curNode = null;\n this.context = {};\n this.payload = Object.freeze({ ...payload });\n }\n\n _transitTo(node, lastRet) {\n this.curNode = node;\n this.lastRet = lastRet;\n }\n\n getConfig() {\n return this.curNode.data.configData;\n }\n\n getPayload() {\n return this.payload;\n }\n\n getPipe() {\n return this.lastRet;\n }\n\n getContext() {\n return this.context;\n }\n\n setContext(data = {}) {\n Object.keys(data).forEach((key) => {\n this.context[key] = data[key];\n });\n }\n}\n"; | ||
var modifiedContent = originalCode.replace(new RegExp(INSERT_IMPORT_PLUGINS_COMMENT), function () { | ||
return plugins.map(function (plugin, index) { | ||
return "import plugin" + index + " from '" + plugin + "';"; | ||
}).join('\n'); | ||
}).replace(new RegExp(INSERT_USE_PLUGINS_COMMENT), function () { | ||
return plugins.map(function (_, index) { | ||
return "logic.use(plugin" + index + ");"; | ||
}).join('\n'); | ||
}); | ||
return modifiedContent; | ||
var makeCode = function (mockNode, mockInput) { return "\n(async function run() {\n // Context\n " + contextTpl.replace(/export\s+default/, '') + "\n\n // Logic\n " + logicTpl | ||
.split('\n') | ||
.filter(function (line) { return !line.match(/import nodeFns/) && !line.match(/import Context/); }) | ||
.join('\n') | ||
.replace(/export\s+default/, '') | ||
.replace("import EventEmitter from 'eventemitter3';", "const EventEmitter = (await import('https://jspm.dev/eventemitter3')).default;") + "\n\n // DSL\n // define dsl here\n\n // nodeFns map\n // define nodeFns here\n\n // imove plugin\n const mockPlugin = () => {\n const mockNode = " + JSON.stringify(mockNode) + ";\n const mockInput = " + JSON.stringify(mockInput) + ";\n const toMockTargets = [\n ['pipe', 'getPipe'],\n ['config', 'getConfig'],\n ['payload', 'getPayload'],\n ['context', 'getContext'],\n ];\n return {\n enterNode(ctx) {\n // hijack\n if(ctx.curNode.id === mockNode.id) {\n toMockTargets.forEach(item => {\n const [type, method] = item;\n item[2] = ctx[method];\n ctx[method] = () => mockInput[type];\n });\n }\n },\n leaveNode(ctx) {\n // restore\n if(ctx.curNode.id === mockNode.id) {\n toMockTargets.forEach(item => {\n const [type, method, originMethod] = item;\n ctx[method] = originMethod;\n });\n }\n }\n };\n };\n\n // instantiation and invoke\n const logic = new Logic({ dsl });\n logic.use(mockPlugin);\n logic.invoke('$TRIGGER$', {}, (pipe) => {\n const ctx = logic._getUnsafeCtx();\n const context = ctx.getContext();\n window.dispatchEvent(new CustomEvent('iMoveOnlineExecEnds', {detail: {pipe, context}}));\n });\n})().catch(err => {\n console.error(err.message);\n window.dispatchEvent(new CustomEvent('iMoveOnlineExecEnds', {detail: {error: {message: err.message}}}));\n});\n"; }; | ||
var extractObj = function (obj, keys) { | ||
if (obj === void 0) { obj = {}; } | ||
if (keys === void 0) { keys = []; } | ||
var ret = {}; | ||
keys.forEach(function (key) { | ||
if (obj[key]) { | ||
ret[key] = obj[key]; | ||
} | ||
}); | ||
return ret; | ||
}; | ||
var simplifyDSL = function (dsl) { | ||
var _a = dsl.cells, cells = _a === void 0 ? [] : _a; | ||
return { | ||
cells: cells.map(function (cell) { | ||
if (cell.shape === 'edge') { | ||
return extractObj(cell, ['id', 'shape', 'source', 'target']); | ||
} | ||
else { | ||
var newCell = extractObj(cell, ['id', 'shape', 'data']); | ||
newCell.data = extractObj(cell.data, ['trigger', 'configData', 'ports']); | ||
return newCell; | ||
} | ||
}), | ||
}; | ||
}; | ||
var extractObj = function extractObj(obj, keys) { | ||
if (obj === void 0) { | ||
obj = {}; | ||
} | ||
if (keys === void 0) { | ||
keys = []; | ||
} | ||
var ret = {}; | ||
keys.forEach(function (key) { | ||
if (obj[key]) { | ||
ret[key] = obj[key]; | ||
/** | ||
* Solution | ||
* | ||
* 1. find the source node form dsl, and if it is not imove-start, | ||
* then insert a vitural imove-start at first. | ||
* | ||
* 2. transform node funciton, follows should be noted: | ||
* - import statement should be replaced with import('packge/from/network') | ||
* - export statement should be replace with return function | ||
* - each node function should be wrapped within a new function to avoid duplicate declaration global variable | ||
* | ||
* 3. assemble Logic, Context, simplyfied dsl and nodeFns map into one file | ||
* | ||
*/ | ||
var INSERT_DSL_COMMENT = '// define dsl here'; | ||
var INSERT_NODE_FNS_COMMENT = '// define nodeFns here'; | ||
var importRegex = /import\s+([\s\S]*?)\s+from\s+(?:('[@\.\/\-\w]+')|("[@\.\/\-\w]+"))\s*;?/mg; | ||
var virtualSourceNode = { | ||
id: 'virtual-imove-start', | ||
shape: 'imove-start', | ||
data: { | ||
trigger: 'virtual-imove-start', | ||
configData: {}, | ||
code: 'export default async function(ctx) {\n \n}' | ||
} | ||
}); | ||
return ret; | ||
}; | ||
var findStartNode = function (dsl) { | ||
var nodes = dsl.cells.filter(function (cell) { return cell.shape !== 'edge'; }); | ||
var edges = dsl.cells.filter(function (cell) { return cell.shape === 'edge'; }); | ||
if (nodes.length === 0) { | ||
throw new Error('Compile failed, no node is selected'); | ||
} | ||
var foundEdge = null; | ||
var startNode = nodes[0]; | ||
var _loop_1 = function () { | ||
var newSourceId = foundEdge.source.cell; | ||
startNode = nodes.find(function (node) { return node.id === newSourceId; }); | ||
}; | ||
while (foundEdge = edges.find(function (edge) { return edge.target.cell === startNode.id; })) { | ||
_loop_1(); | ||
} | ||
if (startNode.shape !== 'imove-start') { | ||
dsl.cells.push(virtualSourceNode, { | ||
shape: "edge", | ||
source: { | ||
cell: 'virtual-imove-start', | ||
}, | ||
target: { | ||
cell: startNode.id | ||
} | ||
}); | ||
startNode = virtualSourceNode; | ||
} | ||
return startNode; | ||
}; | ||
var getNextNode = function (curNode, dsl) { | ||
var nodes = dsl.cells.filter(function (cell) { return cell.shape !== 'edge'; }); | ||
var edges = dsl.cells.filter(function (cell) { return cell.shape === 'edge'; }); | ||
var foundEdge = edges.find(function (edge) { return edge.source.cell === curNode.id; }); | ||
if (foundEdge) { | ||
return nodes.find(function (node) { return node.id === foundEdge.target.cell; }); | ||
} | ||
}; | ||
var compileSimplifiedDSL = function (dsl) { | ||
var simplyfiedDSL = JSON.stringify(simplifyDSL(dsl), null, 2); | ||
return "const dsl = " + simplyfiedDSL + ";"; | ||
}; | ||
var compileNodeFn = function (node) { | ||
var _a = node.data, label = _a.label, code = _a.code; | ||
var newCode = code.replace(importRegex, function (match, p1, p2, p3) { | ||
var pkgName = (p2 || p3).replace(/('|")/g, ''); | ||
return "const " + p1 + " = (await import('https://jspm.dev/" + pkgName + "')).default;"; | ||
}).replace(/export\s+default/, 'return'); | ||
return "await (async function() {\n " + newCode + "\n }())"; | ||
}; | ||
var compileNodeFnsMap = function (dsl) { | ||
var nodes = dsl.cells.filter(function (cell) { return cell.shape !== 'edge'; }); | ||
var kvs = nodes.map(function (node) { | ||
var id = node.id; | ||
return "'" + id + "': " + compileNodeFn(node); | ||
}); | ||
return "const nodeFns = {\n " + kvs.join(',\n ') + "\n}"; | ||
}; | ||
var compile = function (dsl, mockInput) { | ||
var startNode = findStartNode(dsl); | ||
var mockNode = getNextNode(startNode, dsl); | ||
return makeCode(mockNode, mockInput) | ||
.replace(INSERT_DSL_COMMENT, compileSimplifiedDSL(dsl)) | ||
.replace(INSERT_NODE_FNS_COMMENT, compileNodeFnsMap(dsl)) | ||
.replace('$TRIGGER$', startNode.data.trigger); | ||
}; | ||
var simplifyDSL = function simplifyDSL(dsl) { | ||
var _dsl$cells = dsl.cells, | ||
cells = _dsl$cells === void 0 ? [] : _dsl$cells; | ||
return { | ||
cells: cells.map(function (cell) { | ||
if (cell.shape === 'edge') { | ||
return extractObj(cell, ['id', 'shape', 'source', 'target']); | ||
} else { | ||
var newCell = extractObj(cell, ['id', 'shape', 'data']); | ||
newCell.data = extractObj(cell.data, ['trigger', 'configData', 'ports']); | ||
return newCell; | ||
} | ||
var INSERT_IMPORT_PLUGINS_COMMENT = '// import plugins here'; | ||
var INSERT_USE_PLUGINS_COMMENT = '// use plugins here'; | ||
var addPlugins = function (originalCode, plugins) { | ||
if (originalCode === void 0) { originalCode = ''; } | ||
if (plugins === void 0) { plugins = []; } | ||
var modifiedContent = originalCode | ||
.replace(new RegExp(INSERT_IMPORT_PLUGINS_COMMENT), function () { | ||
return plugins.map(function (plugin, index) { return "import plugin" + index + " from '" + plugin + "';"; }).join('\n'); | ||
}) | ||
}; | ||
.replace(new RegExp(INSERT_USE_PLUGINS_COMMENT), function () { | ||
return plugins.map(function (_, index) { return "logic.use(plugin" + index + ");"; }).join('\n'); | ||
}); | ||
return modifiedContent; | ||
}; | ||
function _createForOfIteratorHelperLoose(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; return function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } it = o[Symbol.iterator](); return it.next.bind(it); } | ||
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } | ||
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } | ||
var genEntryFile = function genEntryFile(nodeIds) { | ||
var imports = []; | ||
var funcMaps = []; | ||
nodeIds.forEach(function (id, idx) { | ||
var funcName = "fn_" + idx; | ||
imports.push("import " + funcName + " from './" + id + "';"); | ||
funcMaps.push("'" + id + "': " + funcName); | ||
}); | ||
var fileContent = [imports.join('\n'), "const nodeFns = {\n " + funcMaps.join(',\n ') + "\n};", 'export default nodeFns;'].join('\n'); | ||
return fileContent; | ||
var genEntryFile = function (nodeIds) { | ||
var imports = []; | ||
var funcMaps = []; | ||
nodeIds.forEach(function (id, idx) { | ||
var funcName = "fn_" + idx; | ||
imports.push("import " + funcName + " from './" + id + "';"); | ||
funcMaps.push("'" + id + "': " + funcName); | ||
}); | ||
var fileContent = [ | ||
imports.join('\n'), | ||
"const nodeFns = {\n " + funcMaps.join(',\n ') + "\n};", | ||
'export default nodeFns;', | ||
].join('\n'); | ||
return fileContent; | ||
}; | ||
var genNodeFns = function genNodeFns(dsl) { | ||
var nodeFns = {}; | ||
var _dsl$cells = dsl.cells, | ||
cells = _dsl$cells === void 0 ? [] : _dsl$cells; | ||
var nodes = cells.filter(function (cell) { | ||
return cell.shape !== 'edge'; | ||
}); | ||
for (var _iterator = _createForOfIteratorHelperLoose(nodes), _step; !(_step = _iterator()).done;) { | ||
var _step$value = _step.value, | ||
id = _step$value.id, | ||
shape = _step$value.shape, | ||
_step$value$data = _step$value.data, | ||
label = _step$value$data.label, | ||
code = _step$value$data.code; | ||
var _fileName = id + '.js'; | ||
var descData = "// " + shape + ": " + label + "\n"; | ||
var saveData = descData + "\n" + code; | ||
nodeFns[_fileName] = saveData; | ||
} | ||
return nodeFns; | ||
var genNodeFns = function (dsl) { | ||
var nodeFns = {}; | ||
var _a = dsl.cells, cells = _a === void 0 ? [] : _a; | ||
var nodes = cells.filter(function (cell) { return cell.shape !== 'edge'; }); | ||
for (var _i = 0, nodes_1 = nodes; _i < nodes_1.length; _i++) { | ||
var _b = nodes_1[_i], id = _b.id, shape = _b.shape, _c = _b.data, label = _c.label, code = _c.code; | ||
var fileName = id + '.js'; | ||
var descData = "// " + shape + ": " + label + "\n"; | ||
var saveData = descData + "\n" + code; | ||
nodeFns[fileName] = saveData; | ||
} | ||
return nodeFns; | ||
}; | ||
var extract = function extract(dsl) { | ||
var nodeFns = genNodeFns(dsl); | ||
var nodeIds = Object.keys(nodeFns).map(function (fileName) { | ||
return fileName.slice(0, -3); | ||
}); | ||
var entryFileContent = genEntryFile(nodeIds); | ||
nodeFns['index.js'] = entryFileContent; | ||
return nodeFns; | ||
var extract = function (dsl) { | ||
var nodeFns = genNodeFns(dsl); | ||
var nodeIds = Object.keys(nodeFns).map(function (fileName) { return fileName.slice(0, -3); }); | ||
var entryFileContent = genEntryFile(nodeIds); | ||
nodeFns['index.js'] = entryFileContent; | ||
return nodeFns; | ||
}; | ||
var logicTpl = "import nodeFns from './nodeFns';\nimport Context from './context';\nimport EventEmitter from 'eventemitter3';\n\nconst LIFECYCLE = new Set(['ctxCreated']);\nconst SHAPES = {\n START: 'imove-start',\n BRANCH: 'imove-branch',\n BEHAVIOR: 'imove-behavior',\n};\n\nexport default class Logic extends EventEmitter {\n constructor(opts = {}) {\n super();\n this.dsl = opts.dsl;\n this.lifeCycleEvents = {};\n }\n\n get cells() {\n return this.dsl.cells;\n }\n\n get nodes() {\n return this.cells.filter((cell) => cell.shape !== 'edge');\n }\n\n get startNodes() {\n return this.cells.filter((cell) => cell.shape === SHAPES.START);\n }\n\n get edges() {\n return this.cells.filter((cell) => cell.shape === 'edge');\n }\n\n _runLifecycleEvent(eventName, ctx) {\n if (!LIFECYCLE.has(eventName)) {\n return console.warn(`Lifecycle ${eventName} is not supported!`);\n }\n if (this.lifeCycleEvents[eventName]) {\n this.lifeCycleEvents[eventName].forEach((fn) => fn(ctx));\n }\n }\n\n _createCtx(opts) {\n const ctx = new Context(opts);\n ctx.emit = this.emit.bind(this);\n this._runLifecycleEvent('ctxCreated', ctx);\n return ctx;\n }\n\n _getStartNode(trigger) {\n for (const cell of this.startNodes) {\n if (cell.data.trigger === trigger) {\n return cell;\n }\n }\n }\n\n _getNextNodes(ctx, curNode, curRet) {\n const nodes = [];\n for (const edge of this.edges) {\n let isMatched = edge.source.cell === curNode.id;\n // NOTE: if it is a imove-branch node, each port's condition should be tested whether it is matched\n if (curNode.shape === SHAPES.BRANCH) {\n let matchedPort = '';\n const { ports } = curNode.data;\n for (const key in ports) {\n const { condition } = ports[key];\n const ret = new Function('ctx', 'return ' + condition)(ctx);\n if (ret === Boolean(curRet)) {\n matchedPort = key;\n break;\n }\n }\n isMatched = isMatched && edge.source.port === matchedPort;\n }\n if (isMatched) {\n // NOTE: not each edge both has source and target\n const nextNode = this.nodes.find((item) => item.id === edge.target.cell);\n nextNode && nodes.push(nextNode);\n }\n }\n return nodes;\n }\n\n use(pluginCreator) {\n if (typeof pluginCreator !== 'function') {\n console.error('imove plugin must be a function.');\n return;\n }\n const plugin = pluginCreator(this);\n if (typeof plugin !== 'object' || plugin === null) {\n console.error('imove plugin must return an object.');\n return;\n }\n for (const eventName in plugin) {\n if (!Object.prototype.hasOwnProperty.call(plugin, eventName)) {\n continue;\n }\n if (!LIFECYCLE.has(eventName)) {\n console.warn(`Lifecycle ${eventName} is not supported in imove.`);\n continue;\n }\n if (!this.lifeCycleEvents[eventName]) {\n this.lifeCycleEvents[eventName] = [];\n }\n this.lifeCycleEvents[eventName].push(plugin[eventName]);\n }\n }\n\n async _execNode(ctx, curNode, lastRet) {\n ctx._transitTo(curNode, lastRet);\n const fn = nodeFns[curNode.id];\n const curRet = await fn(ctx);\n if (curNode.shape !== SHAPES.BRANCH) {\n lastRet = curRet;\n }\n const nextNodes = this._getNextNodes(ctx, curNode, curRet);\n if (nextNodes.length > 0) {\n nextNodes.forEach(async (node) => {\n await this._execNode(ctx, node, lastRet);\n });\n }\n }\n\n async invoke(trigger, data) {\n const curNode = this._getStartNode(trigger);\n if (!curNode) {\n return Promise.reject(new Error(`Invoke failed! No logic-start named ${trigger} found!`));\n }\n const ctx = this._createCtx({ payload: data });\n await this._execNode(ctx, curNode);\n }\n}\n"; | ||
var indexTpl = "import Logic from './logic';\nimport dsl from './dsl.json';\n// import plugins here\n\nconst logic = new Logic({ dsl });\n\n// use plugins here\n\nexport default logic;\n"; | ||
var contextTpl = "export default class Context {\n constructor(opts) {\n this._init(opts);\n }\n\n _init(opts = {}) {\n const { payload = {} } = opts;\n this.curNode = null;\n this.context = Object.create(null);\n this.payload = Object.freeze({ ...payload });\n }\n\n _transitTo(node, lastRet) {\n this.curNode = node;\n this.lastRet = lastRet;\n }\n\n prepare(opts = {}) {\n this.payload = opts.payload;\n this.context = {};\n }\n\n getConfig() {\n return this.curNode.data.configData;\n }\n\n getPayload() {\n return this.payload;\n }\n\n getPipe() {\n return this.lastRet;\n }\n\n getContext() {\n return this.context;\n }\n\n setContext(data = {}) {\n Object.keys(data).forEach((key) => {\n this.context[key] = data[key];\n });\n }\n}\n"; | ||
var compile = function compile(dsl, plugins) { | ||
if (plugins === void 0) { | ||
plugins = []; | ||
} | ||
var output = { | ||
'nodeFns': extract(dsl), | ||
"context.js": contextTpl, | ||
'dsl.json': JSON.stringify(simplifyDSL(dsl), null, 2), | ||
'index.js': addPlugins(indexTpl, plugins), | ||
'logic.js': logicTpl | ||
}; | ||
return output; | ||
var compile$1 = function (dsl, plugins) { | ||
if (plugins === void 0) { plugins = []; } | ||
var output = { | ||
'nodeFns': extract(dsl), | ||
"context.js": contextTpl, | ||
'dsl.json': JSON.stringify(simplifyDSL(dsl), null, 2), | ||
'index.js': addPlugins(indexTpl, plugins), | ||
'logic.js': logicTpl | ||
}; | ||
return output; | ||
}; | ||
module.exports = compile; | ||
exports.compileForOnline = compile; | ||
exports.compileForProject = compile$1; |
@@ -1,134 +0,196 @@ | ||
var INSERT_IMPORT_PLUGINS_COMMENT = '// import plugins here'; | ||
var INSERT_USE_PLUGINS_COMMENT = '// use plugins here'; | ||
var logicTpl = "import nodeFns from './nodeFns';\nimport Context from './context';\nimport EventEmitter from 'eventemitter3';\n\nconst LIFECYCLE = new Set(['ctxCreated', 'enterNode', 'leaveNode']);\nconst SHAPES = {\n START: 'imove-start',\n BRANCH: 'imove-branch',\n BEHAVIOR: 'imove-behavior',\n};\n\nexport default class Logic extends EventEmitter {\n constructor(opts = {}) {\n super();\n this.dsl = opts.dsl;\n this.lifeCycleEvents = {};\n }\n\n get cells() {\n return this.dsl.cells;\n }\n\n get nodes() {\n return this.cells.filter((cell) => cell.shape !== 'edge');\n }\n\n get startNodes() {\n return this.cells.filter((cell) => cell.shape === SHAPES.START);\n }\n\n get edges() {\n return this.cells.filter((cell) => cell.shape === 'edge');\n }\n\n _getUnsafeCtx() {\n // NOTE: don't use in prod\n return this._unsafeCtx;\n }\n\n _runLifecycleEvent(eventName, ctx) {\n if (!LIFECYCLE.has(eventName)) {\n return console.warn(`Lifecycle ${eventName} is not supported!`);\n }\n if (this.lifeCycleEvents[eventName]) {\n this.lifeCycleEvents[eventName].forEach((fn) => fn(ctx));\n }\n }\n\n _createCtx(opts) {\n const ctx = new Context(opts);\n ctx.emit = this.emit.bind(this);\n this._runLifecycleEvent('ctxCreated', ctx);\n return ctx;\n }\n\n _getStartNode(trigger) {\n for (const cell of this.startNodes) {\n if (cell.data.trigger === trigger) {\n return cell;\n }\n }\n }\n\n _getNextNodes(ctx, curNode, curRet) {\n const nodes = [];\n for (const edge of this.edges) {\n let isMatched = edge.source.cell === curNode.id;\n // NOTE: if it is a imove-branch node, each port's condition should be tested whether it is matched\n if (curNode.shape === SHAPES.BRANCH) {\n let matchedPort = '';\n const { ports } = curNode.data;\n for (const key in ports) {\n const { condition } = ports[key];\n const ret = new Function('ctx', 'return ' + condition)(ctx);\n if (ret === Boolean(curRet)) {\n matchedPort = key;\n break;\n }\n }\n isMatched = isMatched && edge.source.port === matchedPort;\n }\n if (isMatched) {\n // NOTE: not each edge both has source and target\n const nextNode = this.nodes.find((item) => item.id === edge.target.cell);\n nextNode && nodes.push(nextNode);\n }\n }\n return nodes;\n }\n\n use(pluginCreator) {\n if (typeof pluginCreator !== 'function') {\n console.error('imove plugin must be a function.');\n return;\n }\n const plugin = pluginCreator(this);\n if (typeof plugin !== 'object' || plugin === null) {\n console.error('imove plugin must return an object.');\n return;\n }\n for (const eventName in plugin) {\n if (!Object.prototype.hasOwnProperty.call(plugin, eventName)) {\n continue;\n }\n if (!LIFECYCLE.has(eventName)) {\n console.warn(`Lifecycle ${eventName} is not supported in imove.`);\n continue;\n }\n if (!this.lifeCycleEvents[eventName]) {\n this.lifeCycleEvents[eventName] = [];\n }\n this.lifeCycleEvents[eventName].push(plugin[eventName]);\n }\n }\n\n async _execNode(ctx, curNode, lastRet, callback) {\n ctx._transitTo(curNode, lastRet);\n const fn = nodeFns[curNode.id];\n this._runLifecycleEvent('enterNode', ctx);\n const curRet = await fn(ctx);\n this._runLifecycleEvent('leaveNode', ctx);\n if (curNode.shape !== SHAPES.BRANCH) {\n lastRet = curRet;\n }\n const nextNodes = this._getNextNodes(ctx, curNode, curRet);\n if (nextNodes.length > 0) {\n nextNodes.forEach(async (node) => {\n await this._execNode(ctx, node, lastRet, callback);\n });\n } else {\n callback && callback(lastRet);\n }\n }\n\n async invoke(trigger, data, callback) {\n const curNode = this._getStartNode(trigger);\n if (!curNode) {\n return Promise.reject(new Error(`Invoke failed! No logic-start named ${trigger} found!`));\n }\n this._unsafeCtx = this._createCtx({ payload: data });\n await this._execNode(this._unsafeCtx, curNode, undefined, callback);\n }\n}\n"; | ||
var addPlugins = function addPlugins(originalCode, plugins) { | ||
if (originalCode === void 0) { | ||
originalCode = ''; | ||
} | ||
var contextTpl = "export default class Context {\n constructor(opts) {\n this._init(opts);\n }\n\n _init(opts = {}) {\n const { payload = {} } = opts;\n this.curNode = null;\n this.context = {};\n this.payload = Object.freeze({ ...payload });\n }\n\n _transitTo(node, lastRet) {\n this.curNode = node;\n this.lastRet = lastRet;\n }\n\n getConfig() {\n return this.curNode.data.configData;\n }\n\n getPayload() {\n return this.payload;\n }\n\n getPipe() {\n return this.lastRet;\n }\n\n getContext() {\n return this.context;\n }\n\n setContext(data = {}) {\n Object.keys(data).forEach((key) => {\n this.context[key] = data[key];\n });\n }\n}\n"; | ||
if (plugins === void 0) { | ||
plugins = []; | ||
} | ||
var makeCode = function (mockNode, mockInput) { return "\n(async function run() {\n // Context\n " + contextTpl.replace(/export\s+default/, '') + "\n\n // Logic\n " + logicTpl | ||
.split('\n') | ||
.filter(function (line) { return !line.match(/import nodeFns/) && !line.match(/import Context/); }) | ||
.join('\n') | ||
.replace(/export\s+default/, '') | ||
.replace("import EventEmitter from 'eventemitter3';", "const EventEmitter = (await import('https://jspm.dev/eventemitter3')).default;") + "\n\n // DSL\n // define dsl here\n\n // nodeFns map\n // define nodeFns here\n\n // imove plugin\n const mockPlugin = () => {\n const mockNode = " + JSON.stringify(mockNode) + ";\n const mockInput = " + JSON.stringify(mockInput) + ";\n const toMockTargets = [\n ['pipe', 'getPipe'],\n ['config', 'getConfig'],\n ['payload', 'getPayload'],\n ['context', 'getContext'],\n ];\n return {\n enterNode(ctx) {\n // hijack\n if(ctx.curNode.id === mockNode.id) {\n toMockTargets.forEach(item => {\n const [type, method] = item;\n item[2] = ctx[method];\n ctx[method] = () => mockInput[type];\n });\n }\n },\n leaveNode(ctx) {\n // restore\n if(ctx.curNode.id === mockNode.id) {\n toMockTargets.forEach(item => {\n const [type, method, originMethod] = item;\n ctx[method] = originMethod;\n });\n }\n }\n };\n };\n\n // instantiation and invoke\n const logic = new Logic({ dsl });\n logic.use(mockPlugin);\n logic.invoke('$TRIGGER$', {}, (pipe) => {\n const ctx = logic._getUnsafeCtx();\n const context = ctx.getContext();\n window.dispatchEvent(new CustomEvent('iMoveOnlineExecEnds', {detail: {pipe, context}}));\n });\n})().catch(err => {\n console.error(err.message);\n window.dispatchEvent(new CustomEvent('iMoveOnlineExecEnds', {detail: {error: {message: err.message}}}));\n});\n"; }; | ||
var modifiedContent = originalCode.replace(new RegExp(INSERT_IMPORT_PLUGINS_COMMENT), function () { | ||
return plugins.map(function (plugin, index) { | ||
return "import plugin" + index + " from '" + plugin + "';"; | ||
}).join('\n'); | ||
}).replace(new RegExp(INSERT_USE_PLUGINS_COMMENT), function () { | ||
return plugins.map(function (_, index) { | ||
return "logic.use(plugin" + index + ");"; | ||
}).join('\n'); | ||
}); | ||
return modifiedContent; | ||
var extractObj = function (obj, keys) { | ||
if (obj === void 0) { obj = {}; } | ||
if (keys === void 0) { keys = []; } | ||
var ret = {}; | ||
keys.forEach(function (key) { | ||
if (obj[key]) { | ||
ret[key] = obj[key]; | ||
} | ||
}); | ||
return ret; | ||
}; | ||
var simplifyDSL = function (dsl) { | ||
var _a = dsl.cells, cells = _a === void 0 ? [] : _a; | ||
return { | ||
cells: cells.map(function (cell) { | ||
if (cell.shape === 'edge') { | ||
return extractObj(cell, ['id', 'shape', 'source', 'target']); | ||
} | ||
else { | ||
var newCell = extractObj(cell, ['id', 'shape', 'data']); | ||
newCell.data = extractObj(cell.data, ['trigger', 'configData', 'ports']); | ||
return newCell; | ||
} | ||
}), | ||
}; | ||
}; | ||
var extractObj = function extractObj(obj, keys) { | ||
if (obj === void 0) { | ||
obj = {}; | ||
} | ||
if (keys === void 0) { | ||
keys = []; | ||
} | ||
var ret = {}; | ||
keys.forEach(function (key) { | ||
if (obj[key]) { | ||
ret[key] = obj[key]; | ||
/** | ||
* Solution | ||
* | ||
* 1. find the source node form dsl, and if it is not imove-start, | ||
* then insert a vitural imove-start at first. | ||
* | ||
* 2. transform node funciton, follows should be noted: | ||
* - import statement should be replaced with import('packge/from/network') | ||
* - export statement should be replace with return function | ||
* - each node function should be wrapped within a new function to avoid duplicate declaration global variable | ||
* | ||
* 3. assemble Logic, Context, simplyfied dsl and nodeFns map into one file | ||
* | ||
*/ | ||
var INSERT_DSL_COMMENT = '// define dsl here'; | ||
var INSERT_NODE_FNS_COMMENT = '// define nodeFns here'; | ||
var importRegex = /import\s+([\s\S]*?)\s+from\s+(?:('[@\.\/\-\w]+')|("[@\.\/\-\w]+"))\s*;?/mg; | ||
var virtualSourceNode = { | ||
id: 'virtual-imove-start', | ||
shape: 'imove-start', | ||
data: { | ||
trigger: 'virtual-imove-start', | ||
configData: {}, | ||
code: 'export default async function(ctx) {\n \n}' | ||
} | ||
}); | ||
return ret; | ||
}; | ||
var findStartNode = function (dsl) { | ||
var nodes = dsl.cells.filter(function (cell) { return cell.shape !== 'edge'; }); | ||
var edges = dsl.cells.filter(function (cell) { return cell.shape === 'edge'; }); | ||
if (nodes.length === 0) { | ||
throw new Error('Compile failed, no node is selected'); | ||
} | ||
var foundEdge = null; | ||
var startNode = nodes[0]; | ||
var _loop_1 = function () { | ||
var newSourceId = foundEdge.source.cell; | ||
startNode = nodes.find(function (node) { return node.id === newSourceId; }); | ||
}; | ||
while (foundEdge = edges.find(function (edge) { return edge.target.cell === startNode.id; })) { | ||
_loop_1(); | ||
} | ||
if (startNode.shape !== 'imove-start') { | ||
dsl.cells.push(virtualSourceNode, { | ||
shape: "edge", | ||
source: { | ||
cell: 'virtual-imove-start', | ||
}, | ||
target: { | ||
cell: startNode.id | ||
} | ||
}); | ||
startNode = virtualSourceNode; | ||
} | ||
return startNode; | ||
}; | ||
var getNextNode = function (curNode, dsl) { | ||
var nodes = dsl.cells.filter(function (cell) { return cell.shape !== 'edge'; }); | ||
var edges = dsl.cells.filter(function (cell) { return cell.shape === 'edge'; }); | ||
var foundEdge = edges.find(function (edge) { return edge.source.cell === curNode.id; }); | ||
if (foundEdge) { | ||
return nodes.find(function (node) { return node.id === foundEdge.target.cell; }); | ||
} | ||
}; | ||
var compileSimplifiedDSL = function (dsl) { | ||
var simplyfiedDSL = JSON.stringify(simplifyDSL(dsl), null, 2); | ||
return "const dsl = " + simplyfiedDSL + ";"; | ||
}; | ||
var compileNodeFn = function (node) { | ||
var _a = node.data, label = _a.label, code = _a.code; | ||
var newCode = code.replace(importRegex, function (match, p1, p2, p3) { | ||
var pkgName = (p2 || p3).replace(/('|")/g, ''); | ||
return "const " + p1 + " = (await import('https://jspm.dev/" + pkgName + "')).default;"; | ||
}).replace(/export\s+default/, 'return'); | ||
return "await (async function() {\n " + newCode + "\n }())"; | ||
}; | ||
var compileNodeFnsMap = function (dsl) { | ||
var nodes = dsl.cells.filter(function (cell) { return cell.shape !== 'edge'; }); | ||
var kvs = nodes.map(function (node) { | ||
var id = node.id; | ||
return "'" + id + "': " + compileNodeFn(node); | ||
}); | ||
return "const nodeFns = {\n " + kvs.join(',\n ') + "\n}"; | ||
}; | ||
var compile = function (dsl, mockInput) { | ||
var startNode = findStartNode(dsl); | ||
var mockNode = getNextNode(startNode, dsl); | ||
return makeCode(mockNode, mockInput) | ||
.replace(INSERT_DSL_COMMENT, compileSimplifiedDSL(dsl)) | ||
.replace(INSERT_NODE_FNS_COMMENT, compileNodeFnsMap(dsl)) | ||
.replace('$TRIGGER$', startNode.data.trigger); | ||
}; | ||
var simplifyDSL = function simplifyDSL(dsl) { | ||
var _dsl$cells = dsl.cells, | ||
cells = _dsl$cells === void 0 ? [] : _dsl$cells; | ||
return { | ||
cells: cells.map(function (cell) { | ||
if (cell.shape === 'edge') { | ||
return extractObj(cell, ['id', 'shape', 'source', 'target']); | ||
} else { | ||
var newCell = extractObj(cell, ['id', 'shape', 'data']); | ||
newCell.data = extractObj(cell.data, ['trigger', 'configData', 'ports']); | ||
return newCell; | ||
} | ||
var INSERT_IMPORT_PLUGINS_COMMENT = '// import plugins here'; | ||
var INSERT_USE_PLUGINS_COMMENT = '// use plugins here'; | ||
var addPlugins = function (originalCode, plugins) { | ||
if (originalCode === void 0) { originalCode = ''; } | ||
if (plugins === void 0) { plugins = []; } | ||
var modifiedContent = originalCode | ||
.replace(new RegExp(INSERT_IMPORT_PLUGINS_COMMENT), function () { | ||
return plugins.map(function (plugin, index) { return "import plugin" + index + " from '" + plugin + "';"; }).join('\n'); | ||
}) | ||
}; | ||
.replace(new RegExp(INSERT_USE_PLUGINS_COMMENT), function () { | ||
return plugins.map(function (_, index) { return "logic.use(plugin" + index + ");"; }).join('\n'); | ||
}); | ||
return modifiedContent; | ||
}; | ||
function _createForOfIteratorHelperLoose(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; return function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } it = o[Symbol.iterator](); return it.next.bind(it); } | ||
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } | ||
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } | ||
var genEntryFile = function genEntryFile(nodeIds) { | ||
var imports = []; | ||
var funcMaps = []; | ||
nodeIds.forEach(function (id, idx) { | ||
var funcName = "fn_" + idx; | ||
imports.push("import " + funcName + " from './" + id + "';"); | ||
funcMaps.push("'" + id + "': " + funcName); | ||
}); | ||
var fileContent = [imports.join('\n'), "const nodeFns = {\n " + funcMaps.join(',\n ') + "\n};", 'export default nodeFns;'].join('\n'); | ||
return fileContent; | ||
var genEntryFile = function (nodeIds) { | ||
var imports = []; | ||
var funcMaps = []; | ||
nodeIds.forEach(function (id, idx) { | ||
var funcName = "fn_" + idx; | ||
imports.push("import " + funcName + " from './" + id + "';"); | ||
funcMaps.push("'" + id + "': " + funcName); | ||
}); | ||
var fileContent = [ | ||
imports.join('\n'), | ||
"const nodeFns = {\n " + funcMaps.join(',\n ') + "\n};", | ||
'export default nodeFns;', | ||
].join('\n'); | ||
return fileContent; | ||
}; | ||
var genNodeFns = function genNodeFns(dsl) { | ||
var nodeFns = {}; | ||
var _dsl$cells = dsl.cells, | ||
cells = _dsl$cells === void 0 ? [] : _dsl$cells; | ||
var nodes = cells.filter(function (cell) { | ||
return cell.shape !== 'edge'; | ||
}); | ||
for (var _iterator = _createForOfIteratorHelperLoose(nodes), _step; !(_step = _iterator()).done;) { | ||
var _step$value = _step.value, | ||
id = _step$value.id, | ||
shape = _step$value.shape, | ||
_step$value$data = _step$value.data, | ||
label = _step$value$data.label, | ||
code = _step$value$data.code; | ||
var _fileName = id + '.js'; | ||
var descData = "// " + shape + ": " + label + "\n"; | ||
var saveData = descData + "\n" + code; | ||
nodeFns[_fileName] = saveData; | ||
} | ||
return nodeFns; | ||
var genNodeFns = function (dsl) { | ||
var nodeFns = {}; | ||
var _a = dsl.cells, cells = _a === void 0 ? [] : _a; | ||
var nodes = cells.filter(function (cell) { return cell.shape !== 'edge'; }); | ||
for (var _i = 0, nodes_1 = nodes; _i < nodes_1.length; _i++) { | ||
var _b = nodes_1[_i], id = _b.id, shape = _b.shape, _c = _b.data, label = _c.label, code = _c.code; | ||
var fileName = id + '.js'; | ||
var descData = "// " + shape + ": " + label + "\n"; | ||
var saveData = descData + "\n" + code; | ||
nodeFns[fileName] = saveData; | ||
} | ||
return nodeFns; | ||
}; | ||
var extract = function extract(dsl) { | ||
var nodeFns = genNodeFns(dsl); | ||
var nodeIds = Object.keys(nodeFns).map(function (fileName) { | ||
return fileName.slice(0, -3); | ||
}); | ||
var entryFileContent = genEntryFile(nodeIds); | ||
nodeFns['index.js'] = entryFileContent; | ||
return nodeFns; | ||
var extract = function (dsl) { | ||
var nodeFns = genNodeFns(dsl); | ||
var nodeIds = Object.keys(nodeFns).map(function (fileName) { return fileName.slice(0, -3); }); | ||
var entryFileContent = genEntryFile(nodeIds); | ||
nodeFns['index.js'] = entryFileContent; | ||
return nodeFns; | ||
}; | ||
var logicTpl = "import nodeFns from './nodeFns';\nimport Context from './context';\nimport EventEmitter from 'eventemitter3';\n\nconst LIFECYCLE = new Set(['ctxCreated']);\nconst SHAPES = {\n START: 'imove-start',\n BRANCH: 'imove-branch',\n BEHAVIOR: 'imove-behavior',\n};\n\nexport default class Logic extends EventEmitter {\n constructor(opts = {}) {\n super();\n this.dsl = opts.dsl;\n this.lifeCycleEvents = {};\n }\n\n get cells() {\n return this.dsl.cells;\n }\n\n get nodes() {\n return this.cells.filter((cell) => cell.shape !== 'edge');\n }\n\n get startNodes() {\n return this.cells.filter((cell) => cell.shape === SHAPES.START);\n }\n\n get edges() {\n return this.cells.filter((cell) => cell.shape === 'edge');\n }\n\n _runLifecycleEvent(eventName, ctx) {\n if (!LIFECYCLE.has(eventName)) {\n return console.warn(`Lifecycle ${eventName} is not supported!`);\n }\n if (this.lifeCycleEvents[eventName]) {\n this.lifeCycleEvents[eventName].forEach((fn) => fn(ctx));\n }\n }\n\n _createCtx(opts) {\n const ctx = new Context(opts);\n ctx.emit = this.emit.bind(this);\n this._runLifecycleEvent('ctxCreated', ctx);\n return ctx;\n }\n\n _getStartNode(trigger) {\n for (const cell of this.startNodes) {\n if (cell.data.trigger === trigger) {\n return cell;\n }\n }\n }\n\n _getNextNodes(ctx, curNode, curRet) {\n const nodes = [];\n for (const edge of this.edges) {\n let isMatched = edge.source.cell === curNode.id;\n // NOTE: if it is a imove-branch node, each port's condition should be tested whether it is matched\n if (curNode.shape === SHAPES.BRANCH) {\n let matchedPort = '';\n const { ports } = curNode.data;\n for (const key in ports) {\n const { condition } = ports[key];\n const ret = new Function('ctx', 'return ' + condition)(ctx);\n if (ret === Boolean(curRet)) {\n matchedPort = key;\n break;\n }\n }\n isMatched = isMatched && edge.source.port === matchedPort;\n }\n if (isMatched) {\n // NOTE: not each edge both has source and target\n const nextNode = this.nodes.find((item) => item.id === edge.target.cell);\n nextNode && nodes.push(nextNode);\n }\n }\n return nodes;\n }\n\n use(pluginCreator) {\n if (typeof pluginCreator !== 'function') {\n console.error('imove plugin must be a function.');\n return;\n }\n const plugin = pluginCreator(this);\n if (typeof plugin !== 'object' || plugin === null) {\n console.error('imove plugin must return an object.');\n return;\n }\n for (const eventName in plugin) {\n if (!Object.prototype.hasOwnProperty.call(plugin, eventName)) {\n continue;\n }\n if (!LIFECYCLE.has(eventName)) {\n console.warn(`Lifecycle ${eventName} is not supported in imove.`);\n continue;\n }\n if (!this.lifeCycleEvents[eventName]) {\n this.lifeCycleEvents[eventName] = [];\n }\n this.lifeCycleEvents[eventName].push(plugin[eventName]);\n }\n }\n\n async _execNode(ctx, curNode, lastRet) {\n ctx._transitTo(curNode, lastRet);\n const fn = nodeFns[curNode.id];\n const curRet = await fn(ctx);\n if (curNode.shape !== SHAPES.BRANCH) {\n lastRet = curRet;\n }\n const nextNodes = this._getNextNodes(ctx, curNode, curRet);\n if (nextNodes.length > 0) {\n nextNodes.forEach(async (node) => {\n await this._execNode(ctx, node, lastRet);\n });\n }\n }\n\n async invoke(trigger, data) {\n const curNode = this._getStartNode(trigger);\n if (!curNode) {\n return Promise.reject(new Error(`Invoke failed! No logic-start named ${trigger} found!`));\n }\n const ctx = this._createCtx({ payload: data });\n await this._execNode(ctx, curNode);\n }\n}\n"; | ||
var indexTpl = "import Logic from './logic';\nimport dsl from './dsl.json';\n// import plugins here\n\nconst logic = new Logic({ dsl });\n\n// use plugins here\n\nexport default logic;\n"; | ||
var contextTpl = "export default class Context {\n constructor(opts) {\n this._init(opts);\n }\n\n _init(opts = {}) {\n const { payload = {} } = opts;\n this.curNode = null;\n this.context = Object.create(null);\n this.payload = Object.freeze({ ...payload });\n }\n\n _transitTo(node, lastRet) {\n this.curNode = node;\n this.lastRet = lastRet;\n }\n\n prepare(opts = {}) {\n this.payload = opts.payload;\n this.context = {};\n }\n\n getConfig() {\n return this.curNode.data.configData;\n }\n\n getPayload() {\n return this.payload;\n }\n\n getPipe() {\n return this.lastRet;\n }\n\n getContext() {\n return this.context;\n }\n\n setContext(data = {}) {\n Object.keys(data).forEach((key) => {\n this.context[key] = data[key];\n });\n }\n}\n"; | ||
var compile = function compile(dsl, plugins) { | ||
if (plugins === void 0) { | ||
plugins = []; | ||
} | ||
var output = { | ||
'nodeFns': extract(dsl), | ||
"context.js": contextTpl, | ||
'dsl.json': JSON.stringify(simplifyDSL(dsl), null, 2), | ||
'index.js': addPlugins(indexTpl, plugins), | ||
'logic.js': logicTpl | ||
}; | ||
return output; | ||
var compile$1 = function (dsl, plugins) { | ||
if (plugins === void 0) { plugins = []; } | ||
var output = { | ||
'nodeFns': extract(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; | ||
export { compile as compileForOnline, compile$1 as compileForProject }; |
@@ -1,15 +0,3 @@ | ||
import { Cell } from '@antv/x6'; | ||
interface DSL { | ||
cells: Cell.Properties[]; | ||
} | ||
interface IOutput { | ||
'nodeFns': { | ||
[fileName: string]: string; | ||
}; | ||
'context.js': string; | ||
'dsl.json': string; | ||
'index.js': string; | ||
'logic.js': string; | ||
} | ||
declare const compile: (dsl: DSL, plugins?: never[]) => IOutput; | ||
export default compile; | ||
import compileForOnline from './compileForOnline'; | ||
import compileForProject from './compileForProject'; | ||
export { compileForOnline, compileForProject }; |
@@ -1,2 +0,2 @@ | ||
declare const _default: "export default class Context {\n constructor(opts) {\n this._init(opts);\n }\n\n _init(opts = {}) {\n const { payload = {} } = opts;\n this.curNode = null;\n this.context = Object.create(null);\n this.payload = Object.freeze({ ...payload });\n }\n\n _transitTo(node, lastRet) {\n this.curNode = node;\n this.lastRet = lastRet;\n }\n\n prepare(opts = {}) {\n this.payload = opts.payload;\n this.context = {};\n }\n\n getConfig() {\n return this.curNode.data.configData;\n }\n\n getPayload() {\n return this.payload;\n }\n\n getPipe() {\n return this.lastRet;\n }\n\n getContext() {\n return this.context;\n }\n\n setContext(data = {}) {\n Object.keys(data).forEach((key) => {\n this.context[key] = data[key];\n });\n }\n}\n"; | ||
declare const _default: "export default class Context {\n constructor(opts) {\n this._init(opts);\n }\n\n _init(opts = {}) {\n const { payload = {} } = opts;\n this.curNode = null;\n this.context = {};\n this.payload = Object.freeze({ ...payload });\n }\n\n _transitTo(node, lastRet) {\n this.curNode = node;\n this.lastRet = lastRet;\n }\n\n getConfig() {\n return this.curNode.data.configData;\n }\n\n getPayload() {\n return this.payload;\n }\n\n getPipe() {\n return this.lastRet;\n }\n\n getContext() {\n return this.context;\n }\n\n setContext(data = {}) {\n Object.keys(data).forEach((key) => {\n this.context[key] = data[key];\n });\n }\n}\n"; | ||
export default _default; |
@@ -1,2 +0,2 @@ | ||
declare const _default: "import nodeFns from './nodeFns';\nimport Context from './context';\nimport EventEmitter from 'eventemitter3';\n\nconst LIFECYCLE = new Set(['ctxCreated']);\nconst SHAPES = {\n START: 'imove-start',\n BRANCH: 'imove-branch',\n BEHAVIOR: 'imove-behavior',\n};\n\nexport default class Logic extends EventEmitter {\n constructor(opts = {}) {\n super();\n this.dsl = opts.dsl;\n this.lifeCycleEvents = {};\n }\n\n get cells() {\n return this.dsl.cells;\n }\n\n get nodes() {\n return this.cells.filter((cell) => cell.shape !== 'edge');\n }\n\n get startNodes() {\n return this.cells.filter((cell) => cell.shape === SHAPES.START);\n }\n\n get edges() {\n return this.cells.filter((cell) => cell.shape === 'edge');\n }\n\n _runLifecycleEvent(eventName, ctx) {\n if (!LIFECYCLE.has(eventName)) {\n return console.warn(`Lifecycle ${eventName} is not supported!`);\n }\n if (this.lifeCycleEvents[eventName]) {\n this.lifeCycleEvents[eventName].forEach((fn) => fn(ctx));\n }\n }\n\n _createCtx(opts) {\n const ctx = new Context(opts);\n ctx.emit = this.emit.bind(this);\n this._runLifecycleEvent('ctxCreated', ctx);\n return ctx;\n }\n\n _getStartNode(trigger) {\n for (const cell of this.startNodes) {\n if (cell.data.trigger === trigger) {\n return cell;\n }\n }\n }\n\n _getNextNodes(ctx, curNode, curRet) {\n const nodes = [];\n for (const edge of this.edges) {\n let isMatched = edge.source.cell === curNode.id;\n // NOTE: if it is a imove-branch node, each port's condition should be tested whether it is matched\n if (curNode.shape === SHAPES.BRANCH) {\n let matchedPort = '';\n const { ports } = curNode.data;\n for (const key in ports) {\n const { condition } = ports[key];\n const ret = new Function('ctx', 'return ' + condition)(ctx);\n if (ret === Boolean(curRet)) {\n matchedPort = key;\n break;\n }\n }\n isMatched = isMatched && edge.source.port === matchedPort;\n }\n if (isMatched) {\n // NOTE: not each edge both has source and target\n const nextNode = this.nodes.find((item) => item.id === edge.target.cell);\n nextNode && nodes.push(nextNode);\n }\n }\n return nodes;\n }\n\n use(pluginCreator) {\n if (typeof pluginCreator !== 'function') {\n console.error('imove plugin must be a function.');\n return;\n }\n const plugin = pluginCreator(this);\n if (typeof plugin !== 'object' || plugin === null) {\n console.error('imove plugin must return an object.');\n return;\n }\n for (const eventName in plugin) {\n if (!Object.prototype.hasOwnProperty.call(plugin, eventName)) {\n continue;\n }\n if (!LIFECYCLE.has(eventName)) {\n console.warn(`Lifecycle ${eventName} is not supported in imove.`);\n continue;\n }\n if (!this.lifeCycleEvents[eventName]) {\n this.lifeCycleEvents[eventName] = [];\n }\n this.lifeCycleEvents[eventName].push(plugin[eventName]);\n }\n }\n\n async _execNode(ctx, curNode, lastRet) {\n ctx._transitTo(curNode, lastRet);\n const fn = nodeFns[curNode.id];\n const curRet = await fn(ctx);\n if (curNode.shape !== SHAPES.BRANCH) {\n lastRet = curRet;\n }\n const nextNodes = this._getNextNodes(ctx, curNode, curRet);\n if (nextNodes.length > 0) {\n nextNodes.forEach(async (node) => {\n await this._execNode(ctx, node, lastRet);\n });\n }\n }\n\n async invoke(trigger, data) {\n const curNode = this._getStartNode(trigger);\n if (!curNode) {\n return Promise.reject(new Error(`Invoke failed! No logic-start named ${trigger} found!`));\n }\n const ctx = this._createCtx({ payload: data });\n await this._execNode(ctx, curNode);\n }\n}\n"; | ||
declare const _default: "import nodeFns from './nodeFns';\nimport Context from './context';\nimport EventEmitter from 'eventemitter3';\n\nconst LIFECYCLE = new Set(['ctxCreated', 'enterNode', 'leaveNode']);\nconst SHAPES = {\n START: 'imove-start',\n BRANCH: 'imove-branch',\n BEHAVIOR: 'imove-behavior',\n};\n\nexport default class Logic extends EventEmitter {\n constructor(opts = {}) {\n super();\n this.dsl = opts.dsl;\n this.lifeCycleEvents = {};\n }\n\n get cells() {\n return this.dsl.cells;\n }\n\n get nodes() {\n return this.cells.filter((cell) => cell.shape !== 'edge');\n }\n\n get startNodes() {\n return this.cells.filter((cell) => cell.shape === SHAPES.START);\n }\n\n get edges() {\n return this.cells.filter((cell) => cell.shape === 'edge');\n }\n\n _getUnsafeCtx() {\n // NOTE: don't use in prod\n return this._unsafeCtx;\n }\n\n _runLifecycleEvent(eventName, ctx) {\n if (!LIFECYCLE.has(eventName)) {\n return console.warn(`Lifecycle ${eventName} is not supported!`);\n }\n if (this.lifeCycleEvents[eventName]) {\n this.lifeCycleEvents[eventName].forEach((fn) => fn(ctx));\n }\n }\n\n _createCtx(opts) {\n const ctx = new Context(opts);\n ctx.emit = this.emit.bind(this);\n this._runLifecycleEvent('ctxCreated', ctx);\n return ctx;\n }\n\n _getStartNode(trigger) {\n for (const cell of this.startNodes) {\n if (cell.data.trigger === trigger) {\n return cell;\n }\n }\n }\n\n _getNextNodes(ctx, curNode, curRet) {\n const nodes = [];\n for (const edge of this.edges) {\n let isMatched = edge.source.cell === curNode.id;\n // NOTE: if it is a imove-branch node, each port's condition should be tested whether it is matched\n if (curNode.shape === SHAPES.BRANCH) {\n let matchedPort = '';\n const { ports } = curNode.data;\n for (const key in ports) {\n const { condition } = ports[key];\n const ret = new Function('ctx', 'return ' + condition)(ctx);\n if (ret === Boolean(curRet)) {\n matchedPort = key;\n break;\n }\n }\n isMatched = isMatched && edge.source.port === matchedPort;\n }\n if (isMatched) {\n // NOTE: not each edge both has source and target\n const nextNode = this.nodes.find((item) => item.id === edge.target.cell);\n nextNode && nodes.push(nextNode);\n }\n }\n return nodes;\n }\n\n use(pluginCreator) {\n if (typeof pluginCreator !== 'function') {\n console.error('imove plugin must be a function.');\n return;\n }\n const plugin = pluginCreator(this);\n if (typeof plugin !== 'object' || plugin === null) {\n console.error('imove plugin must return an object.');\n return;\n }\n for (const eventName in plugin) {\n if (!Object.prototype.hasOwnProperty.call(plugin, eventName)) {\n continue;\n }\n if (!LIFECYCLE.has(eventName)) {\n console.warn(`Lifecycle ${eventName} is not supported in imove.`);\n continue;\n }\n if (!this.lifeCycleEvents[eventName]) {\n this.lifeCycleEvents[eventName] = [];\n }\n this.lifeCycleEvents[eventName].push(plugin[eventName]);\n }\n }\n\n async _execNode(ctx, curNode, lastRet, callback) {\n ctx._transitTo(curNode, lastRet);\n const fn = nodeFns[curNode.id];\n this._runLifecycleEvent('enterNode', ctx);\n const curRet = await fn(ctx);\n this._runLifecycleEvent('leaveNode', ctx);\n if (curNode.shape !== SHAPES.BRANCH) {\n lastRet = curRet;\n }\n const nextNodes = this._getNextNodes(ctx, curNode, curRet);\n if (nextNodes.length > 0) {\n nextNodes.forEach(async (node) => {\n await this._execNode(ctx, node, lastRet, callback);\n });\n } else {\n callback && callback(lastRet);\n }\n }\n\n async invoke(trigger, data, callback) {\n const curNode = this._getStartNode(trigger);\n if (!curNode) {\n return Promise.reject(new Error(`Invoke failed! No logic-start named ${trigger} found!`));\n }\n this._unsafeCtx = this._createCtx({ payload: data });\n await this._execNode(this._unsafeCtx, curNode, undefined, callback);\n }\n}\n"; | ||
export default _default; |
{ | ||
"name": "@imove/compile-code", | ||
"version": "0.0.1", | ||
"version": "0.1.0", | ||
"description": "imove compile code", | ||
@@ -26,3 +26,3 @@ "main": "dist/core.common.js", | ||
"build": "rollup -c & npm run declare-type", | ||
"watch": "watch 'npm run build' ./src" | ||
"watch": "watch \"npm run build\" ./src" | ||
}, | ||
@@ -38,6 +38,3 @@ "repository": { | ||
}, | ||
"devDependencies": { | ||
"rollup": "^2.7.3", | ||
"watch": "^1.0.2" | ||
} | ||
"devDependencies": {} | ||
} |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
35698
0
14
479
1