slightning-coco-widget
Version:
SLIGHTNING 的 CoCo 控件框架。
235 lines (234 loc) • 14.2 kB
JavaScript
import React from "react";
import { addMessageToError, betterToString, errorToArray } from "../../utils";
import { StringEnumType, TypeValidateError, validate } from "../type";
import { MethodBlockParam } from "../types";
import { Logger } from "../utils";
import { getSuperWidget } from "../widget";
import { traverseTypes } from "./utils";
export function addCheck(types, widget) {
const methodsMap = {};
traverseTypes(types, {
MethodTypes(node) {
methodsMap[node.value.key] = {
types: node.value,
blockOptions: node.blockOptions
};
}
});
return [types, new Proxy(widget, {
construct(target, argArray, newTarget) {
let widget, logger;
try {
widget = Reflect.construct(target, argArray, newTarget);
logger = new Logger(types, widget);
}
catch (error) {
widget = new (class ConstructErrorWidget extends getSuperWidget(types) {
constructor(props) {
super(props);
logger = new Logger(types, this);
const newError = addMessageToError("控件构造失败", error);
logger.error(...errorToArray(newError));
for (const methodKey of Object.keys(methodsMap)) {
// @ts-ignore
this[methodKey] = function () {
throw newError;
};
}
if (types.options.visible) {
// @ts-ignore
this.render = function () {
throw newError;
};
}
}
})(argArray[0]);
}
return new Proxy(widget, {
get(target, p, receiver) {
const originalFunction = Reflect.get(target, p, receiver);
if (typeof p == "string" && p in methodsMap) {
const method = methodsMap[p];
let newFunction;
if (typeof originalFunction == "function") {
newFunction = originalFunction;
}
else if (!(p in target)) {
newFunction = function () {
throw new Error(`该方法(key: ${p})在控件实体定义中不存在`);
};
}
else {
newFunction = function () {
throw new Error(`该方法在控件实体定义中为 ${betterToString(originalFunction)},不是函数`);
};
}
return new Proxy(newFunction, {
apply(target, thisArg, argArray) {
var _a, _b;
let __description = null;
function getDescription() {
var _a;
if (__description == null) {
__description = [];
if ((_a = method.blockOptions.inline) !== null && _a !== void 0 ? _a : true) {
let i = 0;
for (const part of method.types.block) {
if (part == MethodBlockParam.THIS) {
continue;
}
else if (part == MethodBlockParam.METHOD) {
__description.push(method.types.label);
continue;
}
else if (typeof part == "string") {
__description.push(part);
continue;
}
else if (part.type instanceof StringEnumType) {
const label = part.type.valueToLabelMap[argArray[i]];
if (label != undefined) {
__description.push(`[${label}]`);
}
else {
__description.push(argArray[i]);
}
}
else if (typeof argArray[i] == "string") {
__description.push(JSON.stringify(argArray[i]));
}
else {
__description.push(argArray[i]);
}
i++;
}
}
else {
__description.push(method.types.label);
let i = 0;
for (const part of method.types.block) {
if (part == MethodBlockParam.THIS) {
continue;
}
else if (part == MethodBlockParam.METHOD) {
__description.push(method.types.label);
continue;
}
else if (typeof part == "string") {
continue;
}
else if (part.type instanceof StringEnumType) {
const label = part.type.valueToLabelMap[argArray[i]];
if (label != undefined) {
__description.push(`[${label}]`);
}
else {
__description.push(argArray[i]);
}
}
else if (typeof argArray[i] == "string") {
__description.push(JSON.stringify(argArray[i]));
}
else {
__description.push(argArray[i]);
}
i++;
}
}
}
return __description;
}
const deprecated = (_b = (_a = method.types.deprecated) !== null && _a !== void 0 ? _a : method.blockOptions.deprecated) !== null && _b !== void 0 ? _b : false;
if (typeof deprecated == "string") {
logger.warn(...getDescription(), "该方法已弃用:" + deprecated);
}
else if (deprecated) {
logger.warn(...getDescription(), "该方法已弃用,并且可能在未来版本中移除,请尽快迁移到其他方法");
}
const errors = [];
let i = 0;
for (const part of method.types.block) {
if (typeof part != "object") {
continue;
}
try {
validate(part.label, argArray[i], part.type);
}
catch (error) {
if (!(error instanceof TypeValidateError)) {
throw error;
}
errors.push(error);
}
i++;
}
if (errors.length != 0) {
logger.error(...getDescription(), "类型验证失败:" + errors.map((error) => `\n ${error.message.split("\n").join("\n ")}`).join(""));
}
try {
const returnValue = Reflect.apply(target, thisArg, argArray);
if (returnValue instanceof Promise) {
return returnValue.catch((error) => {
logger.error(...getDescription(), "出错:", ...errorToArray(error));
});
}
else {
return returnValue;
}
}
catch (error) {
logger.error(...getDescription(), "出错:", ...errorToArray(error));
}
}
});
}
else if (types.options.visible && p == "render") {
let newFunction;
if (typeof originalFunction == "function") {
newFunction = originalFunction;
}
else if (!(p in target)) {
newFunction = function () {
throw new Error(`渲染方法在控件实体定义中不存在`);
};
}
else {
newFunction = function () {
throw new Error(`渲染方法在控件实体定义中为 ${betterToString(originalFunction)},不是函数`);
};
}
return new Proxy(newFunction, {
apply(target, thisArg, argArray) {
try {
return Reflect.apply(target, thisArg, argArray);
}
catch (error) {
logger.error("渲染", "出错:", ...errorToArray(error));
return React.createElement("div", {
style: {
width: "100%",
height: "100%",
backgroundColor: "#FFFFFF80",
overflow: "auto"
}
}, React.createElement("div", {
style: {
width: "max-content",
color: "#C00000",
fontSize: "2em",
fontWeight: "bold",
fontFamily: "monospace",
}
}, "渲染出错:", betterToString(error).split("\n").map((line) => ([
line, React.createElement("br")
]))));
}
}
});
}
return originalFunction;
}
});
}
})];
}