slightning-coco-widget
Version:
SLIGHTNING 的 CoCo 控件框架。
380 lines (379 loc) • 18 kB
JavaScript
import { capitalize, splitArray } from "../../utils";
import { traverseTypes } from "../decorators";
import { Color, MethodBlockParam } from "../types";
import { eventKeyMap } from "../utils";
export function convertToCoCo(types, widget) {
return [typesToCoCo(types), new Proxy(widget, {
construct(target, argArray, newTarget) {
const [props] = argArray;
const widgetInstance = Reflect.construct(target, argArray, newTarget);
for (const [key, value] of Object.entries(props)) {
Object.defineProperty(widgetInstance, key, {
value,
writable: true,
enumerable: true,
configurable: true
});
}
return widgetInstance;
}
})];
}
export function typesToCoCo(types) {
var _a, _b, _c, _d, _e, _f;
const result = {
type: types.type,
title: types.info.title,
icon: types.info.icon,
version: (_a = types.info.version) !== null && _a !== void 0 ? _a : undefined,
author: (_b = types.info.author) !== null && _b !== void 0 ? _b : undefined,
docs: {
url: (_d = (_c = types.info.url) === null || _c === void 0 ? void 0 : _c.docs) !== null && _d !== void 0 ? _d : undefined
},
isInvisibleWidget: !types.options.visible,
isGlobalWidget: types.options.global,
platforms: (_e = types.options.platforms) !== null && _e !== void 0 ? _e : undefined,
hasAnyWidget: (_f = types.options.any) !== null && _f !== void 0 ? _f : undefined,
properties: [],
methods: [],
events: []
};
const labels = [];
let showLine = false;
let addSpace = false;
let last = null;
let count = 0;
traverseTypes(types, {
PropertyGroup: {
enter(node) {
if (node.value.label != null) {
labels.push(node.value.label);
showLine = true;
}
addSpace = true;
},
exit(node) {
if (node.value.label != null) {
labels.pop();
showLine = true;
}
addSpace = true;
}
},
PropertyTypes(node) {
var _a;
if (addSpace) {
if (last != null) {
(_a = last.blockOptions) !== null && _a !== void 0 ? _a : (last.blockOptions = {});
last.blockOptions.space = 40;
}
addSpace = false;
}
result.properties.push(last = Object.assign(Object.assign({ key: node.value.key, label: node.value.label }, node.value.type.toCoCoPropertyValueTypes()), { blockOptions: {
getter: {
generateBlock: node.blockOptions.get != false
},
setter: {
generateBlock: node.blockOptions.set != false
},
line: typeof showLine == "string" ? showLine : showLine ? labels.join("·") : undefined
} }));
showLine = false;
},
MethodGroup: {
enter(node) {
if (node.value.label != null) {
labels.push(node.value.label);
showLine = true;
}
addSpace = true;
},
exit(node) {
if (node.value.label != null) {
labels.pop();
showLine = true;
}
addSpace = true;
}
},
MethodTypes(node) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
if (addSpace) {
if (last != null) {
(_a = last.blockOptions) !== null && _a !== void 0 ? _a : (last.blockOptions = {});
last.blockOptions.space = 40;
}
addSpace = false;
}
const { value: method } = node;
if (method.throws != null && !(method.throws.isVoid())) {
throw new Error(`无法将方法 ${method.label} 的抛出类型转为 CoCo 类型`);
}
const deprecated = (_c = (_b = method.deprecated) !== null && _b !== void 0 ? _b : node.blockOptions.deprecated) !== null && _c !== void 0 ? _c : false;
const transformed = Object.assign(Object.assign({ key: method.key, params: [] }, (_d = method.returns) === null || _d === void 0 ? void 0 : _d.toCoCoMethodValueTypes()), { tooltip: (_e = method.tooltip) !== null && _e !== void 0 ? _e : undefined, blockOptions: {
callMethodLabel: false,
line: typeof showLine == "string" ? showLine : showLine ? labels.join("·") : undefined,
order: ++count,
icon: (_f = node.blockOptions.icon) !== null && _f !== void 0 ? _f : undefined,
color: deprecated ? Color.GREY : (_g = node.blockOptions.color) !== null && _g !== void 0 ? _g : undefined,
inputsInline: (_h = node.blockOptions.inline) !== null && _h !== void 0 ? _h : undefined
} });
if (typeof deprecated == "string") {
if (transformed.tooltip == null) {
transformed.tooltip = `${deprecated}`;
}
else {
transformed.tooltip = `${deprecated}\n\n${transformed.tooltip}`;
}
}
else if (deprecated) {
if (transformed.tooltip == null) {
transformed.tooltip = `该方法已弃用,并且可能在未来版本中移除,请尽快迁移到其他方法`;
}
else {
transformed.tooltip = `该方法已弃用,并且可能在未来版本中移除,请尽快迁移到其他方法\n\n${transformed.tooltip}`;
}
}
if (!method.block.includes(MethodBlockParam.THIS)) {
throw new Error(`方法 ${method.label} 缺少 this 参数`);
}
(_j = transformed.blockOptions) !== null && _j !== void 0 ? _j : (transformed.blockOptions = {});
const inline = (_k = node.blockOptions.inline) !== null && _k !== void 0 ? _k : true;
if (inline) {
let restParts = null;
let labelsBeforeThis = [];
if (deprecated != false) {
labelsBeforeThis.push("[已弃用]");
}
for (let i = 0; i < method.block.length; i++) {
const part = method.block[i];
if (part == MethodBlockParam.METHOD) {
labelsBeforeThis.push(method.label);
}
else if (part == MethodBlockParam.BREAK_LINE) {
labelsBeforeThis.push("");
}
else if (part == MethodBlockParam.THIS) {
restParts = method.block.slice(i + 1);
break;
}
else if (typeof part == "string") {
labelsBeforeThis.push(part);
}
else if (part != undefined) {
throw new Error(`方法 ${method.label} 的积木 this 参数前存在他参数,不能将其转为 CoCo 类型`);
}
}
if (restParts == null) {
throw new Error(`方法 ${method.label} 缺少 this 参数`);
}
if (labelsBeforeThis.length != 0) {
transformed.blockOptions.callMethodLabel = labelsBeforeThis.join(" ");
}
let lastParam = null;
function addText(text) {
if (lastParam == null) {
if (transformed.label == null) {
transformed.label = text;
}
else {
transformed.label = `${transformed.label} ${text}`;
}
}
else {
if (lastParam.labelAfter == null) {
lastParam.labelAfter = text;
}
else {
lastParam.labelAfter = `${lastParam.labelAfter} ${text}`;
}
}
}
for (const part of restParts) {
if (part == MethodBlockParam.THIS) {
throw new Error(`方法只能有一个 this 参数,而方法 ${method.label} 有多个 this 参数`);
}
else if (part == MethodBlockParam.METHOD) {
addText(method.label);
}
else if (typeof part == "string") {
addText(part);
}
else {
lastParam = Object.assign({ key: part.key }, part.type.toCoCoMethodParamValueTypes());
transformed.params.push(lastParam);
}
}
}
else {
transformed.blockOptions.inputsInline = false;
const blockLines = splitArray(method.block, MethodBlockParam.BREAK_LINE);
if (!(() => {
var _a, _b;
const transformedParams = [];
let labelsBeforeThis = [];
let afterThis = false;
let labelsAfterThis = [];
let positionAfterThis = 1;
for (const item of (_a = blockLines[0]) !== null && _a !== void 0 ? _a : []) {
if (item == MethodBlockParam.THIS) {
if (afterThis) {
throw new Error(`方法只能有一个 this 参数,而方法 ${method.label} 有多个 this 参数`);
}
else {
afterThis = true;
}
}
else if (afterThis) {
return false;
}
else if (typeof item == "string") {
const text = item == MethodBlockParam.METHOD ? method.label : item;
labelsBeforeThis.push(text);
}
else {
throw new Error(`方法 ${method.label} 的积木 this 参数前存在他参数,不能将其转为 CoCo 类型`);
}
}
if (!afterThis) {
throw new Error(`方法 ${method.label} 的积木 this 参数前存在他参数,不能将其转为 CoCo 类型`);
}
if ((_b = blockLines[1]) === null || _b === void 0 ? void 0 : _b.every((item) => typeof item == "string")) {
positionAfterThis = 2;
for (const item of blockLines[1]) {
const text = item == MethodBlockParam.METHOD ? method.label : item;
labelsAfterThis.push(text);
}
}
let lastTransformedParam = null;
for (const line of blockLines.slice(positionAfterThis)) {
let labels = [];
let param = null;
for (const item of line) {
if (item == MethodBlockParam.THIS) {
throw new Error(`方法只能有一个 this 参数,而方法 ${method.label} 有多个 this 参数`);
}
else if (typeof item == "string") {
if (param != null) {
return false;
}
const text = item == MethodBlockParam.METHOD ? method.label : item;
labels.push(text);
}
else if (param == null) {
param = item;
}
else {
return false;
}
}
if (param != null) {
lastTransformedParam = Object.assign({ key: param.key, label: labels.join(" ") }, param.type.toCoCoMethodParamValueTypes());
transformedParams.push(lastTransformedParam);
}
else if (lastTransformedParam != null) {
lastTransformedParam.labelAfter = labels.join(" ");
lastTransformedParam = null;
}
else {
return false;
}
}
if (labelsBeforeThis.length != 0) {
transformed.blockOptions.callMethodLabel = labelsBeforeThis.join(" ");
}
transformed.label = labelsAfterThis.join(" ");
transformed.params = transformedParams;
return true;
})()) {
transformed.label = method.label;
for (const part of method.block) {
if (typeof part != "object") {
continue;
}
transformed.params.push(Object.assign({ key: part.key, label: part.label }, part.type.toCoCoMethodParamValueTypes()));
}
}
if (deprecated != false) {
transformed.blockOptions.callMethodLabel =
`[已弃用] ${transformed.blockOptions.callMethodLabel || ""}`;
}
}
showLine = false;
last = transformed;
result.methods.push(transformed);
},
EventTypes(node) {
var _a, _b, _c, _d, _e, _f;
if (addSpace) {
if (last != null) {
(_a = last.blockOptions) !== null && _a !== void 0 ? _a : (last.blockOptions = {});
last.blockOptions.space = 40;
}
addSpace = false;
}
const deprecated = (_c = (_b = node.value.deprecated) !== null && _b !== void 0 ? _b : node.blockOptions.deprecated) !== null && _c !== void 0 ? _c : false;
const transformed = {
key: node.value.key,
subTypes: (_d = node.value.subTypes) !== null && _d !== void 0 ? _d : undefined,
label: deprecated != false ? `[已弃用] ${node.value.label}` : node.value.label,
params: node.value.params.map((param) => {
return Object.assign({ key: param.key, label: param.label }, param.type.toCoCoEventParamValueTypes());
}),
tooltip: (_e = node.value.tooltip) !== null && _e !== void 0 ? _e : undefined,
blockOptions: {
line: typeof showLine == "string" ? showLine : showLine ? labels.join("·") : undefined,
order: ++count,
icon: (_f = node.blockOptions.icon) !== null && _f !== void 0 ? _f : undefined
}
};
if (node.value.subTypes != null) {
addEventSubTypesMap(node.value.subTypes, 0, [node.value.key], [node.value.key], [node.value.label], node.value);
}
if (typeof deprecated == "string") {
if (transformed.tooltip == null) {
transformed.tooltip = `${deprecated}`;
}
else {
transformed.tooltip = `${deprecated}\n\n${transformed.tooltip}`;
}
}
else if (deprecated) {
if (transformed.tooltip == null) {
transformed.tooltip = `该事件已弃用,并且可能在未来版本中移除,请尽快迁移到其他事件`;
}
else {
transformed.tooltip = `该事件已弃用,并且可能在未来版本中移除,请尽快迁移到其他事件\n\n${transformed.tooltip}`;
}
}
showLine = false;
last = transformed;
result.events.push(transformed);
},
BlockBoxOptions(node) {
var _a;
if (node.value.space != null && last != null) {
(_a = last.blockOptions) !== null && _a !== void 0 ? _a : (last.blockOptions = {});
last.blockOptions.space = node.value.space;
}
if (node.value.line != null) {
showLine = node.value.line;
}
}
});
return result;
}
function addEventSubTypesMap(subTypes, i, keys, capitalizedKeys, labels, event) {
if (i >= subTypes.length) {
eventKeyMap[capitalizedKeys.join("")] = keys.join("");
return;
}
const subType = subTypes[i];
if (subType == undefined) {
addEventSubTypesMap(subTypes, i + 1, keys, capitalizedKeys, labels, event);
return;
}
for (const item of subType.dropdown) {
addEventSubTypesMap(subTypes, i + 1, [...keys, item.value], [...capitalizedKeys, capitalize(item.value)], [...labels, item.label], event);
}
}