slightning-coco-widget
Version:
SLIGHTNING 的 CoCo 控件框架。
200 lines (199 loc) • 9.57 kB
JavaScript
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];
}