@mbler/mcx-core 0.1.3-rc.5 → 0.1.3-rc.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -3
- package/dist/index.d.ts +33 -5
- package/dist/index.js +332 -123
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import * as Module from "node:module";
|
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { NodeTypes, baseParse } from "@vue/compiler-core";
|
|
5
5
|
import * as path from "node:path";
|
|
6
|
-
import { extname } from "node:path";
|
|
6
|
+
import { dirname, extname, resolve, sep } from "node:path";
|
|
7
7
|
import * as t from "@babel/types";
|
|
8
8
|
import { program } from "@babel/types";
|
|
9
9
|
import * as fs from "node:fs/promises";
|
|
@@ -1013,6 +1013,99 @@ function processHooks(code) {
|
|
|
1013
1013
|
//#endregion
|
|
1014
1014
|
//#region src/transforms/transform/layout.ts
|
|
1015
1015
|
const SETUP_CTX_INDEX = 0;
|
|
1016
|
+
const UI_TAGS = new Set([
|
|
1017
|
+
"input",
|
|
1018
|
+
"textField",
|
|
1019
|
+
"toggle",
|
|
1020
|
+
"dropdown",
|
|
1021
|
+
"slider",
|
|
1022
|
+
"button",
|
|
1023
|
+
"label",
|
|
1024
|
+
"body",
|
|
1025
|
+
"header",
|
|
1026
|
+
"title",
|
|
1027
|
+
"divider",
|
|
1028
|
+
"spacer",
|
|
1029
|
+
"close-button"
|
|
1030
|
+
]);
|
|
1031
|
+
const FORM_TAGS = new Set([
|
|
1032
|
+
"input",
|
|
1033
|
+
"dropdown",
|
|
1034
|
+
"submit",
|
|
1035
|
+
"toggle",
|
|
1036
|
+
"slider",
|
|
1037
|
+
"button",
|
|
1038
|
+
"button-m",
|
|
1039
|
+
"body",
|
|
1040
|
+
"divider",
|
|
1041
|
+
"title"
|
|
1042
|
+
]);
|
|
1043
|
+
const COMMON_ATTRS = new Set([
|
|
1044
|
+
"id",
|
|
1045
|
+
"for",
|
|
1046
|
+
"if",
|
|
1047
|
+
"tip",
|
|
1048
|
+
"disabled",
|
|
1049
|
+
"visible",
|
|
1050
|
+
"description",
|
|
1051
|
+
":id",
|
|
1052
|
+
":for",
|
|
1053
|
+
":if",
|
|
1054
|
+
":tip",
|
|
1055
|
+
":disabled",
|
|
1056
|
+
":visible",
|
|
1057
|
+
":description"
|
|
1058
|
+
]);
|
|
1059
|
+
const TAG_ATTRS = {
|
|
1060
|
+
input: new Set([
|
|
1061
|
+
"placeholderText",
|
|
1062
|
+
"default",
|
|
1063
|
+
"value",
|
|
1064
|
+
":placeholderText",
|
|
1065
|
+
":default",
|
|
1066
|
+
":value"
|
|
1067
|
+
]),
|
|
1068
|
+
textField: new Set([
|
|
1069
|
+
"placeholderText",
|
|
1070
|
+
"default",
|
|
1071
|
+
"value",
|
|
1072
|
+
":placeholderText",
|
|
1073
|
+
":default",
|
|
1074
|
+
":value"
|
|
1075
|
+
]),
|
|
1076
|
+
toggle: new Set([
|
|
1077
|
+
"default",
|
|
1078
|
+
"value",
|
|
1079
|
+
":default",
|
|
1080
|
+
":value"
|
|
1081
|
+
]),
|
|
1082
|
+
dropdown: new Set([
|
|
1083
|
+
"default",
|
|
1084
|
+
"value",
|
|
1085
|
+
"option",
|
|
1086
|
+
":default",
|
|
1087
|
+
":value",
|
|
1088
|
+
":option"
|
|
1089
|
+
]),
|
|
1090
|
+
slider: new Set([
|
|
1091
|
+
"default",
|
|
1092
|
+
"value",
|
|
1093
|
+
"min",
|
|
1094
|
+
"max",
|
|
1095
|
+
":default",
|
|
1096
|
+
":value",
|
|
1097
|
+
":min",
|
|
1098
|
+
":max"
|
|
1099
|
+
]),
|
|
1100
|
+
button: new Set([
|
|
1101
|
+
"click",
|
|
1102
|
+
"img",
|
|
1103
|
+
":click",
|
|
1104
|
+
":img"
|
|
1105
|
+
]),
|
|
1106
|
+
submit: new Set(["click", ":click"]),
|
|
1107
|
+
"button-m": new Set(["click", ":click"])
|
|
1108
|
+
};
|
|
1016
1109
|
/**
|
|
1017
1110
|
* Shared layout generation for both <Form> and <Ui>.
|
|
1018
1111
|
* Generates layout config with (s) => expr functions for content and params.
|
|
@@ -1061,24 +1154,38 @@ function generateLayout(ctx, tagNode, tagName, mode) {
|
|
|
1061
1154
|
const cleanedArr = { ...el.arr };
|
|
1062
1155
|
delete cleanedArr.for;
|
|
1063
1156
|
delete cleanedArr.if;
|
|
1064
|
-
if (mode === "
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1157
|
+
if (!(mode === "ui" ? UI_TAGS : FORM_TAGS).has(name)) {
|
|
1158
|
+
internalCtx.rollupContext.error(`[${tagName}]: don't support tag: ${name}`, el.loc ? {
|
|
1159
|
+
line: el.loc.start.line,
|
|
1160
|
+
column: el.loc.start.column
|
|
1161
|
+
} : void 0);
|
|
1162
|
+
continue;
|
|
1163
|
+
}
|
|
1164
|
+
const allowedAttrs = new Set(COMMON_ATTRS);
|
|
1165
|
+
const tagSpecific = TAG_ATTRS[name];
|
|
1166
|
+
if (tagSpecific) for (const attr of tagSpecific) allowedAttrs.add(attr);
|
|
1167
|
+
for (const key of Object.keys(cleanedArr)) {
|
|
1168
|
+
if (key === "for" || key === "if") continue;
|
|
1169
|
+
if (!allowedAttrs.has(key)) {
|
|
1170
|
+
internalCtx.rollupContext.error(`[${tagName}]: tag '${name}' does not support attribute '${key}'`, el.loc ? {
|
|
1068
1171
|
line: el.loc.start.line,
|
|
1069
1172
|
column: el.loc.start.column
|
|
1070
1173
|
} : void 0);
|
|
1071
1174
|
continue;
|
|
1072
1175
|
}
|
|
1176
|
+
}
|
|
1177
|
+
if (mode === "form") {
|
|
1178
|
+
const formType = detectFormType(name);
|
|
1073
1179
|
if (formType) typeTags.push(formType);
|
|
1074
1180
|
}
|
|
1181
|
+
const _paramCtx = t.identifier("ctx");
|
|
1075
1182
|
const paramsObj = t.objectExpression(Object.entries(cleanedArr).filter(([key]) => key !== "for" && key !== "if").map(([key, value]) => {
|
|
1076
1183
|
const isDynamic = key.startsWith(":");
|
|
1077
1184
|
const paramName = isDynamic ? key.slice(1) : key;
|
|
1078
1185
|
if (paramName === "click") return t.objectProperty(t.identifier(paramName), simpleFn(String(value)));
|
|
1079
|
-
return t.objectProperty(t.identifier(paramName), isDynamic ? simpleFn(String(value)) : typeof value === "boolean" ? t.booleanLiteral(value) : t.stringLiteral(value));
|
|
1186
|
+
return t.objectProperty(t.identifier(paramName), isDynamic ? simpleFn(String(value)) : t.arrowFunctionExpression([_paramCtx], typeof value === "boolean" ? t.booleanLiteral(value) : t.stringLiteral(value)));
|
|
1080
1187
|
}));
|
|
1081
|
-
const contentExpr = parseContent(el.content);
|
|
1188
|
+
const contentExpr = mode === "form" ? parseContentForm(el.content) : parseContent(el.content);
|
|
1082
1189
|
const props = [
|
|
1083
1190
|
t.objectProperty(t.identifier("type"), t.stringLiteral(name)),
|
|
1084
1191
|
t.objectProperty(t.identifier("params"), paramsObj),
|
|
@@ -1141,73 +1248,50 @@ function simpleFn(expr) {
|
|
|
1141
1248
|
const body = dotAccess(expr, ctx);
|
|
1142
1249
|
return t.arrowFunctionExpression([ctx], body);
|
|
1143
1250
|
}
|
|
1144
|
-
/**
|
|
1145
|
-
function
|
|
1146
|
-
const reserved = new Set([
|
|
1147
|
-
"true",
|
|
1148
|
-
"false",
|
|
1149
|
-
"null",
|
|
1150
|
-
"undefined",
|
|
1151
|
-
"this",
|
|
1152
|
-
"new",
|
|
1153
|
-
"typeof",
|
|
1154
|
-
"instanceof"
|
|
1155
|
-
]);
|
|
1156
|
-
const ids = /* @__PURE__ */ new Set();
|
|
1157
|
-
const regex = /\b([a-zA-Z_$][\w$]*)\b/g;
|
|
1158
|
-
let m;
|
|
1159
|
-
while ((m = regex.exec(expr)) !== null) if (!reserved.has(m[1])) ids.add(m[1]);
|
|
1160
|
-
return [...ids];
|
|
1161
|
-
}
|
|
1162
|
-
/** Generate new Computation((ctx) => expr, [deps]) */
|
|
1163
|
-
function arrowFn(expr) {
|
|
1251
|
+
/** Parse content for form mode: never creates Computation, uses plain functions */
|
|
1252
|
+
function parseContentForm(raw) {
|
|
1164
1253
|
const ctx = t.identifier("ctx");
|
|
1165
|
-
|
|
1166
|
-
const
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1254
|
+
if (!raw.includes("{{ ")) return t.arrowFunctionExpression([ctx], t.stringLiteral(raw));
|
|
1255
|
+
const parts = splitInterpolation(raw);
|
|
1256
|
+
if (parts.length === 1 && parts[0].type === "expr") return simpleFn(parts[0].value);
|
|
1257
|
+
const quasis = [];
|
|
1258
|
+
const expressions = [];
|
|
1259
|
+
for (const part of parts) if (part.type === "text") quasis.push(t.templateElement({
|
|
1260
|
+
raw: part.value,
|
|
1261
|
+
cooked: part.value
|
|
1262
|
+
}));
|
|
1263
|
+
else expressions.push(dotAccess(part.value, ctx));
|
|
1264
|
+
quasis.push(t.templateElement({
|
|
1265
|
+
raw: "",
|
|
1266
|
+
cooked: ""
|
|
1267
|
+
}, true));
|
|
1268
|
+
const tpl = t.templateLiteral(quasis, expressions);
|
|
1269
|
+
return t.arrowFunctionExpression([ctx], tpl);
|
|
1172
1270
|
}
|
|
1173
1271
|
/**
|
|
1174
|
-
* Parse content string, returns:
|
|
1175
|
-
* -
|
|
1176
|
-
* -
|
|
1177
|
-
*
|
|
1178
|
-
* Supports:
|
|
1179
|
-
* - "Hello" → "Hello"
|
|
1180
|
-
* - "{{ a }}" → new Computation((ctx) => ctx[0].a, [ctx => ctx[0].a])
|
|
1181
|
-
* - "Hi {{ a }}" → new Computation((ctx) => `Hi ${ctx[0].a}`, [ctx => ctx[0].a])
|
|
1182
|
-
* - "{{ a.slice(1,2) }}" → new Computation((ctx) => ctx[0].a.slice(1,2), [ctx => ctx[0].a])
|
|
1272
|
+
* Parse content string, returns an arrow function (ctx) => result:
|
|
1273
|
+
* - "Hello" → (ctx) => "Hello"
|
|
1274
|
+
* - "{{ a }}" → (ctx) => ctx[0].a
|
|
1275
|
+
* - "Hi {{ a }}" → (ctx) => `Hi ${ctx[0].a}`
|
|
1183
1276
|
*/
|
|
1184
1277
|
function parseContent(raw) {
|
|
1185
|
-
if (!raw.includes("{{ ")) return t.stringLiteral(raw);
|
|
1186
|
-
const parts = splitInterpolation(raw);
|
|
1187
|
-
if (parts.length === 1 && parts[0].type === "expr") return arrowFn(parts[0].value);
|
|
1188
1278
|
const ctx = t.identifier("ctx");
|
|
1279
|
+
if (!raw.includes("{{ ")) return t.arrowFunctionExpression([ctx], t.stringLiteral(raw));
|
|
1280
|
+
const parts = splitInterpolation(raw);
|
|
1281
|
+
if (parts.length === 1 && parts[0].type === "expr") return simpleFn(parts[0].value);
|
|
1189
1282
|
const quasis = [];
|
|
1190
1283
|
const expressions = [];
|
|
1191
|
-
const allIds = /* @__PURE__ */ new Set();
|
|
1192
1284
|
for (const part of parts) if (part.type === "text") quasis.push(t.templateElement({
|
|
1193
1285
|
raw: part.value,
|
|
1194
1286
|
cooked: part.value
|
|
1195
1287
|
}));
|
|
1196
|
-
else
|
|
1197
|
-
expressions.push(dotAccess(part.value, ctx));
|
|
1198
|
-
for (const id of extractIdentifiers(part.value)) allIds.add(id);
|
|
1199
|
-
}
|
|
1288
|
+
else expressions.push(dotAccess(part.value, ctx));
|
|
1200
1289
|
quasis.push(t.templateElement({
|
|
1201
1290
|
raw: "",
|
|
1202
1291
|
cooked: ""
|
|
1203
1292
|
}, true));
|
|
1204
1293
|
const tpl = t.templateLiteral(quasis, expressions);
|
|
1205
|
-
|
|
1206
|
-
const deps = [...allIds].map((id) => {
|
|
1207
|
-
const c = t.identifier("ctx");
|
|
1208
|
-
return t.arrowFunctionExpression([c], dotAccess(id, c));
|
|
1209
|
-
});
|
|
1210
|
-
return t.newExpression(t.identifier("Computation"), [evalFn, t.arrayExpression(deps)]);
|
|
1294
|
+
return t.arrowFunctionExpression([ctx], tpl);
|
|
1211
1295
|
}
|
|
1212
1296
|
function splitInterpolation(raw) {
|
|
1213
1297
|
const result = [];
|
|
@@ -1252,7 +1336,7 @@ function buildUIConfig(ctx, tagNode, tagName, mode) {
|
|
|
1252
1336
|
//#endregion
|
|
1253
1337
|
//#region src/transforms/transform/ui.ts
|
|
1254
1338
|
async function Comp$3(ctx) {
|
|
1255
|
-
ctx.impBody.push(t.importDeclaration([t.importSpecifier(t.identifier("__mcx__ui"), t.identifier("ui"))], t.stringLiteral("@mbler/mcx")), t.importDeclaration([t.importNamespaceSpecifier(t.identifier("__minecraft__ui"))], t.stringLiteral("@minecraft/server-ui")));
|
|
1339
|
+
ctx.impBody.push(t.importDeclaration([t.importSpecifier(t.identifier("__mcx__ui"), t.identifier("ui")), t.importSpecifier(t.identifier("Computation"), t.identifier("Computation"))], t.stringLiteral("@mbler/mcx")), t.importDeclaration([t.importNamespaceSpecifier(t.identifier("__minecraft__ui"))], t.stringLiteral("@minecraft/server-ui")));
|
|
1256
1340
|
const tagNode = ctx.ctx.compiledCode.strLoc.UI;
|
|
1257
1341
|
if (!tagNode || tagNode.name !== "Ui") throw new Error("[UI Component]: why did parent not verify?");
|
|
1258
1342
|
const configObj = buildUIConfig(ctx, tagNode, "Ui", "ui");
|
|
@@ -1447,12 +1531,14 @@ var RunScript = class {
|
|
|
1447
1531
|
_context;
|
|
1448
1532
|
_module;
|
|
1449
1533
|
_pluginContext;
|
|
1450
|
-
|
|
1534
|
+
_moduleResolver;
|
|
1535
|
+
constructor(filePath = "<repl>", module = "cjs", pluginContext, moduleResolver) {
|
|
1451
1536
|
this.filePath = filePath;
|
|
1452
1537
|
this.module = module;
|
|
1453
1538
|
this.pluginContext = pluginContext;
|
|
1454
1539
|
this._module = new Module.Module(this.filePath);
|
|
1455
1540
|
this._pluginContext = pluginContext || {};
|
|
1541
|
+
this._moduleResolver = moduleResolver;
|
|
1456
1542
|
this._context = this.getContext(this._pluginContext);
|
|
1457
1543
|
}
|
|
1458
1544
|
/**
|
|
@@ -1504,15 +1590,21 @@ var RunScript = class {
|
|
|
1504
1590
|
id: this.filePath
|
|
1505
1591
|
};
|
|
1506
1592
|
const originalRequire = Module.createRequire ? Module.createRequire(this.filePath) : __require;
|
|
1507
|
-
const
|
|
1593
|
+
const contextRequire = new Proxy(originalRequire, { apply: (target, thisArg, args) => {
|
|
1508
1594
|
const id = args[0];
|
|
1509
1595
|
if (typeof id === "string" && BLOCKED_MODULES.has(id)) throw new Error(`[mcx component]: require('${id}') is not allowed in component scripts`);
|
|
1596
|
+
if (this._moduleResolver) try {
|
|
1597
|
+
return Reflect.apply(target, thisArg, args);
|
|
1598
|
+
} catch {
|
|
1599
|
+
const currentImporter = context.module?.filename || this.filePath;
|
|
1600
|
+
return this._moduleResolver.ensureModule(id, currentImporter, context, void 0);
|
|
1601
|
+
}
|
|
1510
1602
|
return Reflect.apply(target, thisArg, args);
|
|
1511
1603
|
} });
|
|
1512
1604
|
Object.assign(context, {
|
|
1513
1605
|
exports,
|
|
1514
1606
|
module,
|
|
1515
|
-
require:
|
|
1607
|
+
require: contextRequire,
|
|
1516
1608
|
global: context
|
|
1517
1609
|
});
|
|
1518
1610
|
return vm.createContext(context);
|
|
@@ -1733,23 +1825,7 @@ async function compileComponent(compiledCode, ctx) {
|
|
|
1733
1825
|
const src = compiledCode.strLoc.script;
|
|
1734
1826
|
const exportSources = collectExportSources(src);
|
|
1735
1827
|
checkComponentImports(exportSources, compiledCode.File);
|
|
1736
|
-
const scriptRunResult = await new RunScript(compiledCode.File, "esm").run(src, 0
|
|
1737
|
-
if (setData && data.type == "CallExpression" && data.callee.type == "Identifier" && data.arguments.length == 1 && data.arguments[0]?.type == "CallExpression" && data.arguments[0].callee.type == "Identifier" && data.arguments[0].callee.name == "require") {
|
|
1738
|
-
const arg = data.arguments[0].arguments[0];
|
|
1739
|
-
if (arg && arg.type == "StringLiteral") {
|
|
1740
|
-
if (/^.+?\.(png|svg|jpg|jpeg|gif)$/.test(arg.value)) {
|
|
1741
|
-
const imageComponentRequire = t.memberExpression(t.callExpression(t.identifier("require"), [t.stringLiteral("@mbler/mcx-component")]), t.identifier({
|
|
1742
|
-
png: "PNGImageComponent",
|
|
1743
|
-
svg: "SVGImageComponent",
|
|
1744
|
-
jpg: "JPGImageComponent",
|
|
1745
|
-
jpeg: "JPGImageComponent",
|
|
1746
|
-
gif: "GIFImageComponent"
|
|
1747
|
-
}[path.extname(arg.value).slice(1)]));
|
|
1748
|
-
setData(t.newExpression(imageComponentRequire, [t.callExpression(t.memberExpression(t.callExpression(t.identifier("require"), [t.stringLiteral("node:path")]), t.identifier("join")), [t.stringLiteral(path.dirname(compiledCode.File)), arg])]));
|
|
1749
|
-
}
|
|
1750
|
-
}
|
|
1751
|
-
}
|
|
1752
|
-
});
|
|
1828
|
+
const scriptRunResult = await new RunScript(compiledCode.File, "esm", void 0, ctx.moduleResolver).run(src, 0);
|
|
1753
1829
|
if (!component) throw new Error("[component internal error]: compile component: mcx is not component: filePath: " + compiledCode.File);
|
|
1754
1830
|
if (typeof scriptRunResult !== "object") throw new Error("[component compile error]: exec code: mcx export type is not object");
|
|
1755
1831
|
for (const i of Object.entries(component)) {
|
|
@@ -1847,14 +1923,10 @@ async function _transform(ctx) {
|
|
|
1847
1923
|
|
|
1848
1924
|
//#endregion
|
|
1849
1925
|
//#region src/transforms/index.ts
|
|
1850
|
-
function
|
|
1851
|
-
|
|
1852
|
-
...err,
|
|
1853
|
-
message: `${err.message} (At ${id})`
|
|
1854
|
-
};
|
|
1855
|
-
else return { message: String(err) };
|
|
1926
|
+
function toMcxError(err, id) {
|
|
1927
|
+
return { message: err instanceof Error ? `${err.message} (At ${id})` : String(err) };
|
|
1856
1928
|
}
|
|
1857
|
-
async function transform(code, cache, id, context, opt, output) {
|
|
1929
|
+
async function transform(code, cache, id, context, opt, output, moduleResolver) {
|
|
1858
1930
|
try {
|
|
1859
1931
|
const scriptTag = code.raw.find((node) => {
|
|
1860
1932
|
return node.name == "script";
|
|
@@ -1873,18 +1945,149 @@ async function transform(code, cache, id, context, opt, output) {
|
|
|
1873
1945
|
param: [],
|
|
1874
1946
|
body: []
|
|
1875
1947
|
},
|
|
1876
|
-
output
|
|
1948
|
+
output,
|
|
1949
|
+
...moduleResolver ? { moduleResolver } : {}
|
|
1877
1950
|
});
|
|
1878
1951
|
} catch (err) {
|
|
1879
|
-
context.error(
|
|
1952
|
+
context.error(toMcxError(err, id));
|
|
1880
1953
|
return "";
|
|
1881
1954
|
}
|
|
1882
1955
|
}
|
|
1883
1956
|
|
|
1957
|
+
//#endregion
|
|
1958
|
+
//#region src/compile-mcx/compiler/resolve.ts
|
|
1959
|
+
const RESOLVE_EXTS = [
|
|
1960
|
+
".ts",
|
|
1961
|
+
".mts",
|
|
1962
|
+
".cts",
|
|
1963
|
+
".js",
|
|
1964
|
+
".mjs",
|
|
1965
|
+
".cjs",
|
|
1966
|
+
""
|
|
1967
|
+
];
|
|
1968
|
+
function resolveFileSync(filePath) {
|
|
1969
|
+
for (const ext of RESOLVE_EXTS) try {
|
|
1970
|
+
const fullPath = filePath + ext;
|
|
1971
|
+
readFileSync(fullPath);
|
|
1972
|
+
return fullPath;
|
|
1973
|
+
} catch {}
|
|
1974
|
+
if (filePath.endsWith(sep) || !extname(filePath)) for (const ext of RESOLVE_EXTS) try {
|
|
1975
|
+
const fullPath = filePath + "/index" + ext;
|
|
1976
|
+
readFileSync(fullPath);
|
|
1977
|
+
return fullPath;
|
|
1978
|
+
} catch {}
|
|
1979
|
+
return null;
|
|
1980
|
+
}
|
|
1981
|
+
async function resolveFileAsync(filePath) {
|
|
1982
|
+
for (const ext of RESOLVE_EXTS) try {
|
|
1983
|
+
const fullPath = filePath + ext;
|
|
1984
|
+
await readFile(fullPath, "utf-8");
|
|
1985
|
+
return fullPath;
|
|
1986
|
+
} catch {}
|
|
1987
|
+
if (filePath.endsWith(sep) || !extname(filePath)) for (const ext of RESOLVE_EXTS) try {
|
|
1988
|
+
const fullPath = filePath + "/index" + ext;
|
|
1989
|
+
await readFile(fullPath, "utf-8");
|
|
1990
|
+
return fullPath;
|
|
1991
|
+
} catch {}
|
|
1992
|
+
return null;
|
|
1993
|
+
}
|
|
1994
|
+
function resolveSync(specifier, importerPath) {
|
|
1995
|
+
if (specifier.startsWith(".") || specifier.startsWith("/")) return resolveFileSync(resolve(dirname(importerPath), specifier));
|
|
1996
|
+
try {
|
|
1997
|
+
return __require.resolve(specifier, { paths: [dirname(importerPath)] });
|
|
1998
|
+
} catch {
|
|
1999
|
+
return null;
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
//#endregion
|
|
2004
|
+
//#region src/mcx-component/moduleResolver.ts
|
|
2005
|
+
var ModuleResolver = class {
|
|
2006
|
+
cache;
|
|
2007
|
+
loadingModules = /* @__PURE__ */ new Set();
|
|
2008
|
+
transformFile;
|
|
2009
|
+
constructor(cache, transformFile) {
|
|
2010
|
+
this.cache = cache;
|
|
2011
|
+
this.transformFile = transformFile;
|
|
2012
|
+
}
|
|
2013
|
+
getCache() {
|
|
2014
|
+
return this.cache;
|
|
2015
|
+
}
|
|
2016
|
+
clear() {
|
|
2017
|
+
this.cache.clear();
|
|
2018
|
+
this.loadingModules.clear();
|
|
2019
|
+
}
|
|
2020
|
+
ensureModule(specifier, importerPath, context, nativeRequire) {
|
|
2021
|
+
if (nativeRequire) try {
|
|
2022
|
+
return nativeRequire(specifier);
|
|
2023
|
+
} catch {}
|
|
2024
|
+
const resolved = resolveSync(specifier, importerPath);
|
|
2025
|
+
if (!resolved) throw new Error(`[mcx component]: cannot resolve '${specifier}' from '${importerPath}'`);
|
|
2026
|
+
if (this.cache.has(resolved)) return this.executeInContext(resolved, context);
|
|
2027
|
+
if (this.loadingModules.has(resolved)) return context.exports;
|
|
2028
|
+
this.loadingModules.add(resolved);
|
|
2029
|
+
try {
|
|
2030
|
+
const code = readFileSync(resolved, "utf-8");
|
|
2031
|
+
const compiled = this.transformFile(code, resolved);
|
|
2032
|
+
this.cache.set(resolved, compiled);
|
|
2033
|
+
return this.executeInContext(resolved, context);
|
|
2034
|
+
} finally {
|
|
2035
|
+
this.loadingModules.delete(resolved);
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
executeInContext(resolvedPath, context) {
|
|
2039
|
+
const compiled = this.cache.get(resolvedPath);
|
|
2040
|
+
const script = new vm.Script(compiled, { filename: resolvedPath });
|
|
2041
|
+
const savedExports = context.exports;
|
|
2042
|
+
const savedModule = context.module;
|
|
2043
|
+
const childExports = {};
|
|
2044
|
+
const childModule = {
|
|
2045
|
+
exports: childExports,
|
|
2046
|
+
filename: resolvedPath,
|
|
2047
|
+
path: dirname(resolvedPath),
|
|
2048
|
+
id: resolvedPath
|
|
2049
|
+
};
|
|
2050
|
+
context.exports = childExports;
|
|
2051
|
+
context.module = childModule;
|
|
2052
|
+
try {
|
|
2053
|
+
script.runInContext(context);
|
|
2054
|
+
return context.exports;
|
|
2055
|
+
} finally {
|
|
2056
|
+
context.exports = savedExports;
|
|
2057
|
+
context.module = savedModule;
|
|
2058
|
+
}
|
|
2059
|
+
}
|
|
2060
|
+
};
|
|
2061
|
+
function createImageTransformCode(absolutePath, ext) {
|
|
2062
|
+
const className = {
|
|
2063
|
+
".png": "PNGImageComponent",
|
|
2064
|
+
".svg": "SVGImageComponent",
|
|
2065
|
+
".jpg": "JPGImageComponent",
|
|
2066
|
+
".jpeg": "JPGImageComponent",
|
|
2067
|
+
".gif": "GIFImageComponent"
|
|
2068
|
+
}[ext.toLowerCase()];
|
|
2069
|
+
if (!className) throw new Error(`[mcx component]: unsupported image extension '${ext}' for '${absolutePath}'`);
|
|
2070
|
+
return [
|
|
2071
|
+
`Object.defineProperty(exports, '__esModule', { value: true });`,
|
|
2072
|
+
`var { ${className} } = require('@mbler/mcx-component');`,
|
|
2073
|
+
`var path = require('node:path');`,
|
|
2074
|
+
`exports.default = new ${className}(${JSON.stringify(absolutePath)});`
|
|
2075
|
+
].join("\n");
|
|
2076
|
+
}
|
|
2077
|
+
|
|
1884
2078
|
//#endregion
|
|
1885
2079
|
//#region src/compile-mcx/compiler/main.ts
|
|
2080
|
+
const IMAGE_EXTS = new Set([
|
|
2081
|
+
".png",
|
|
2082
|
+
".svg",
|
|
2083
|
+
".jpg",
|
|
2084
|
+
".jpeg",
|
|
2085
|
+
".gif"
|
|
2086
|
+
]);
|
|
1886
2087
|
function createMcxPlugin(opt, output) {
|
|
1887
2088
|
let cache = /* @__PURE__ */ new Map();
|
|
2089
|
+
let moduleTransformCache;
|
|
2090
|
+
let moduleResolver;
|
|
1888
2091
|
let tsconfig;
|
|
1889
2092
|
try {
|
|
1890
2093
|
const configResult = ts.readConfigFile(opt.tsconfigPath, (path) => {
|
|
@@ -1911,29 +2114,6 @@ function createMcxPlugin(opt, output) {
|
|
|
1911
2114
|
errors: []
|
|
1912
2115
|
};
|
|
1913
2116
|
}
|
|
1914
|
-
const resolveExtensions = [
|
|
1915
|
-
"",
|
|
1916
|
-
".ts",
|
|
1917
|
-
".mts",
|
|
1918
|
-
".cts",
|
|
1919
|
-
".js",
|
|
1920
|
-
".mjs",
|
|
1921
|
-
".cjs"
|
|
1922
|
-
];
|
|
1923
|
-
const indexExtensions = resolveExtensions.map((ext) => "/index" + ext);
|
|
1924
|
-
async function tryResolvePath(filePath) {
|
|
1925
|
-
for (const idxExt of indexExtensions) try {
|
|
1926
|
-
const fullPath = filePath + idxExt;
|
|
1927
|
-
await readFile(fullPath, "utf-8");
|
|
1928
|
-
return fullPath;
|
|
1929
|
-
} catch {}
|
|
1930
|
-
for (const ext of resolveExtensions) try {
|
|
1931
|
-
const fullPath = filePath + ext;
|
|
1932
|
-
await readFile(fullPath, "utf-8");
|
|
1933
|
-
return fullPath;
|
|
1934
|
-
} catch {}
|
|
1935
|
-
return null;
|
|
1936
|
-
}
|
|
1937
2117
|
async function resolvePackageExports(pkgDir, subPath, pkgJson) {
|
|
1938
2118
|
const exports = pkgJson.exports;
|
|
1939
2119
|
if (exports) {
|
|
@@ -1967,7 +2147,7 @@ function createMcxPlugin(opt, output) {
|
|
|
1967
2147
|
if (i.dir.startsWith(".") || i.root) {
|
|
1968
2148
|
if (imp) {
|
|
1969
2149
|
const baseDir = path.dirname(imp);
|
|
1970
|
-
const resolved = await
|
|
2150
|
+
const resolved = await resolveFileAsync(path.join(baseDir, id));
|
|
1971
2151
|
if (resolved) return resolved;
|
|
1972
2152
|
}
|
|
1973
2153
|
return null;
|
|
@@ -1992,9 +2172,9 @@ function createMcxPlugin(opt, output) {
|
|
|
1992
2172
|
if (subPath) {
|
|
1993
2173
|
const fromExports = await resolvePackageExports(d, subPath, pkgJson);
|
|
1994
2174
|
if (fromExports) return fromExports;
|
|
1995
|
-
const fromDist = await
|
|
2175
|
+
const fromDist = await resolveFileAsync(path.join(d, "./dist", subPath));
|
|
1996
2176
|
if (fromDist) return fromDist;
|
|
1997
|
-
const fromRoot = await
|
|
2177
|
+
const fromRoot = await resolveFileAsync(path.join(d, subPath));
|
|
1998
2178
|
if (fromRoot) return fromRoot;
|
|
1999
2179
|
return null;
|
|
2000
2180
|
}
|
|
@@ -2020,31 +2200,60 @@ function createMcxPlugin(opt, output) {
|
|
|
2020
2200
|
}
|
|
2021
2201
|
compileData.setFilePath(id);
|
|
2022
2202
|
return {
|
|
2023
|
-
code: await transform(compileData, cache, id, this, opt, output),
|
|
2024
|
-
|
|
2203
|
+
code: await transform(compileData, cache, id, this, opt, output, moduleResolver),
|
|
2204
|
+
...opt.sourcemap ? { map: magic.generateMap({
|
|
2025
2205
|
hires: true,
|
|
2026
2206
|
source: id
|
|
2027
|
-
}) :
|
|
2207
|
+
}) } : {}
|
|
2028
2208
|
};
|
|
2029
|
-
}
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
map: opt.sourcemap ? magic.generateMap({
|
|
2209
|
+
}
|
|
2210
|
+
const cached = moduleTransformCache.get(id);
|
|
2211
|
+
if (cached) return {
|
|
2212
|
+
code: cached,
|
|
2213
|
+
...opt.sourcemap ? { map: magic.generateMap({
|
|
2035
2214
|
hires: true,
|
|
2036
2215
|
source: id
|
|
2037
|
-
}) :
|
|
2216
|
+
}) } : {}
|
|
2038
2217
|
};
|
|
2218
|
+
let compiledCode = null;
|
|
2219
|
+
if (tsRegex.test(id)) compiledCode = ts.transpileModule(code, {
|
|
2220
|
+
compilerOptions: tsconfig.options,
|
|
2221
|
+
fileName: id
|
|
2222
|
+
}).outputText;
|
|
2223
|
+
else {
|
|
2224
|
+
const fileExt = extname(id).toLowerCase();
|
|
2225
|
+
if (IMAGE_EXTS.has(fileExt)) compiledCode = createImageTransformCode(id, fileExt);
|
|
2226
|
+
}
|
|
2227
|
+
if (compiledCode !== null) {
|
|
2228
|
+
moduleTransformCache.set(id, compiledCode);
|
|
2229
|
+
return {
|
|
2230
|
+
code: compiledCode,
|
|
2231
|
+
...opt.sourcemap ? { map: magic.generateMap({
|
|
2232
|
+
hires: true,
|
|
2233
|
+
source: id
|
|
2234
|
+
}) } : {}
|
|
2235
|
+
};
|
|
2236
|
+
}
|
|
2039
2237
|
return null;
|
|
2040
2238
|
},
|
|
2041
2239
|
async buildEnd() {
|
|
2042
2240
|
cache.clear();
|
|
2241
|
+
moduleResolver?.clear();
|
|
2043
2242
|
await generateItemTextureJson(output);
|
|
2044
2243
|
clearCachedOptions();
|
|
2045
2244
|
},
|
|
2046
2245
|
buildStart() {
|
|
2047
2246
|
cache = /* @__PURE__ */ new Map();
|
|
2247
|
+
moduleTransformCache = /* @__PURE__ */ new Map();
|
|
2248
|
+
moduleResolver = new ModuleResolver(moduleTransformCache, (fileCode, fileId) => {
|
|
2249
|
+
const fileExt = extname(fileId).toLowerCase();
|
|
2250
|
+
if (fileExt === ".ts" || fileExt === ".mts" || fileExt === ".cts") return ts.transpileModule(fileCode, {
|
|
2251
|
+
compilerOptions: tsconfig.options,
|
|
2252
|
+
fileName: fileId
|
|
2253
|
+
}).outputText;
|
|
2254
|
+
if (IMAGE_EXTS.has(fileExt)) return createImageTransformCode(fileId, fileExt);
|
|
2255
|
+
return fileCode;
|
|
2256
|
+
});
|
|
2048
2257
|
}
|
|
2049
2258
|
};
|
|
2050
2259
|
}
|