slightning-coco-widget
Version:
SLIGHTNING 的 CoCo 控件框架。
220 lines (219 loc) • 10.3 kB
JavaScript
import { capitalize } from "../../utils";
import { AnyType, InstanceOfClassType, ObjectType, StringEnumType, VoidType } from "../type";
import { BlockType } from "../types";
import { emit } from "../utils";
import { methodParamNeedsTransformToEvent, traverseTypes } from "./utils";
export function addTransformMethodsCallbackFunctionsToEvents(types, widget) {
traverseTypes(types, {
MethodTypes(node) {
if (!node.value.block.some(methodParamNeedsTransformToEvent)) {
return;
}
const argumentsTransformers = [];
const transformedMethod = Object.assign(Object.assign({}, node.value), { key: `__slightning_coco_widget_transformed_callback_function_to_events__${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 (!methodParamNeedsTransformToEvent(part)) {
argumentsTransformers.push((arg) => arg);
continue;
}
const key = `${transformedMethod.key}${capitalize(part.key)}`;
const label = `${transformedMethod.label}·${part.label}`;
const type = part.type;
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
});
const eventParams = [
{
key: "__slightning_coco_widget_call_data__",
label: part.label,
type: callDataType
}, {
key: "__slightning_coco_widget_call_context__",
label: "上下文",
type: new AnyType()
}
];
for (const part of type.block) {
if (typeof part != "object") {
continue;
}
eventParams.push({
key: part.key,
label: part.label,
type: part.type
});
}
transformedMethod.block.splice(i, 1, part.label, "(上下文", {
key: `__slightning_coco_widget_call_context__${part.key}`,
label: `${part.label}(上下文)`,
type: new AnyType({
defaultValue: `${part.label}上下文`
})
}, ")");
i++;
argumentsTransformers.push(function (context) {
const widget = this;
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
};
emit.call(widget, key, callData, context, ...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,
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
});
}
node.insertAfter({
type: BlockType.EVENT,
key,
label: `${label}被调用`,
params: eventParams
});
}
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];
}