UNPKG

slightning-coco-widget

Version:

SLIGHTNING 的 CoCo 控件框架。

200 lines (199 loc) 9.57 kB
import { capitalize } from "../../utils"; import { FunctionType, InstanceOfClassType, ObjectType, StringEnumType, VoidType } from "../type"; import { BlockType } from "../types"; import { methodParamNeedsTransformToCodeBlocks, traverseTypes } from "./utils"; export function addTransformMethodsCallbackFunctionsToCodeBlocks(types, widget) { traverseTypes(types, { MethodTypes(node) { if (!node.value.block.some(methodParamNeedsTransformToCodeBlocks)) { return; } let argumentsTransformers = []; const transformedMethod = Object.assign(Object.assign({}, node.value), { key: `__slightning_coco_widget_transformed_callback_function_to_code_blocks__${node.value.key}`, block: [...node.value.block] }); for (let i = 0; i < transformedMethod.block.length; i++) { const part = transformedMethod.block[i]; if (part == undefined) { continue; } if (typeof part != "object") { continue; } if (!methodParamNeedsTransformToCodeBlocks(part)) { argumentsTransformers.push((arg) => arg); continue; } const key = `${transformedMethod.key}${capitalize(part.key)}`; const label = `${transformedMethod.label}·${part.label}`; const type = part.type; const newType = new FunctionType({ block: type.block, defaultValue: type.defaultValue }); transformedMethod.block[i] = { key: `__slightning_coco_widget_transformed_callback_function_to_code_blocks__${part.key}`, label: part.label, type: newType }; class ResolveRef { constructor() { this.name = "解决函数引用"; } } class RejectRef { constructor() { this.name = "拒绝函数引用"; } } const resolveMap = new WeakMap(); const rejectMap = new WeakMap(); const callDataType = new ObjectType({ propertiesType: { state: new StringEnumType([ ["未完成", "undone"], ["已解决", "resolved"], ["已拒绝", "rejected"] ]), resolve: new InstanceOfClassType({ theClass: ResolveRef }), reject: new InstanceOfClassType({ theClass: RejectRef }) }, defaultValue: label }); newType.block.unshift({ key: "__slightning_coco_widget_call_data__", label: part.label, type: callDataType }); argumentsTransformers.push(function (originalFunction) { if (typeof originalFunction != "function") { return originalFunction; } return function (...args) { let promiseResolve = null; let promiseReject = null; function resolve(result) { if (callData.state == "undone") { callData.state = "resolved"; callData.value = result; promiseResolve === null || promiseResolve === void 0 ? void 0 : promiseResolve(result); } } function reject(reason) { if (callData.state == "undone") { callData.state = "rejected"; callData.value = reason; promiseReject === null || promiseReject === void 0 ? void 0 : promiseReject(reason); } } const resolveRef = new ResolveRef(); const rejectRef = new RejectRef(); resolveMap.set(resolveRef, resolve); rejectMap.set(rejectRef, reject); const callData = { state: "undone", resolve: resolveRef, reject: rejectRef }; originalFunction(callData, ...args); if (callData.state == "resolved") { return callData.value; } else if (callData.state == "rejected") { throw callData.value; } return new Promise((resolve, reject) => { promiseResolve = resolve; promiseReject = reject; }); }; }); if (type.throws != null && !(type.throws.isVoid())) { node.insertAfter({ space: 8 }, { type: BlockType.METHOD, key: `__slightning_coco_widget_throw__${key}`, label: `${label}抛出`, block: [ { key: "__slightning_coco_widget_call_data__", label: label, type: callDataType }, "抛出", { key: "Exception", label: "异常", type: type.throws } ], returns: new VoidType(), blockOptions: Object.assign(Object.assign({}, transformedMethod.blockOptions), { inline: true, previousStatement: true, nextStatement: false }) }); Object.defineProperty(widget.prototype, `__slightning_coco_widget_throw__${key}`, { value: function (callData, exception) { const reject = rejectMap.get(callData.reject); if (reject == null) { throw new Error("拒绝函数不存在"); } reject(exception); }, writable: true, enumerable: false, configurable: true }); } if (type.returns != null) { node.insertAfter({ space: 8 }, { type: BlockType.METHOD, key: `__slightning_coco_widget_return__${key}`, label: `${label}返回`, block: [ { key: "__slightning_coco_widget_call_data__", label, type: callDataType }, "返回", ...type.returns.isVoid() ? [] : [{ key: "returnValue", label: "返回值", type: type.returns }] ], returns: new VoidType(), blockOptions: Object.assign(Object.assign({}, transformedMethod.blockOptions), { inline: true, previousStatement: true, nextStatement: false }) }); Object.defineProperty(widget.prototype, `__slightning_coco_widget_return__${key}`, { value: function (callData, returnValue) { const resolve = resolveMap.get(callData.resolve); if (resolve == null) { throw new Error("解决函数不存在"); } resolve(returnValue); }, writable: true, enumerable: false, configurable: true }); } } Object.defineProperty(widget.prototype, transformedMethod.key, { value: function (...args) { var _a; const transformedArgs = []; for (let i = 0; i < args.length; i++) { transformedArgs.push((_a = argumentsTransformers[i]) === null || _a === void 0 ? void 0 : _a.call(this, args[i])); } return this[node.value.key].apply(this, transformedArgs); }, writable: true, enumerable: false, configurable: true }); node.insertAfter(transformedMethod); } }); return [types, widget]; }