@mbler/mcx-core 0.1.3-rc.6 → 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 +204 -121
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,8 +22,8 @@ pnpm add -D @mbler/mcx-core
|
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
## Usage
|
|
25
|
-
|
|
26
|
-
Add the plugin to your Rollup or Rolldown config:
|
|
25
|
+
1. Use manually
|
|
26
|
+
Add the plugin to your Rollup or Rolldown/Rollup config:
|
|
27
27
|
|
|
28
28
|
```ts
|
|
29
29
|
import { rollupPlugin } from '@mbler/mcx-core'
|
|
@@ -32,7 +32,10 @@ export default {
|
|
|
32
32
|
plugins: [rollupPlugin({ moduleDir: './modules', tsconfigPath: './tsconfig.json' })],
|
|
33
33
|
}
|
|
34
34
|
```
|
|
35
|
-
|
|
35
|
+
2. Use with [mbler](https://npmjs.com/package/mbler)
|
|
36
|
+
```bash
|
|
37
|
+
pnpm create mbler
|
|
38
|
+
```
|
|
36
39
|
For full documentation, visit the **[Docs](https://mbler-docs.ruanhor.dpdns.org/guide/mcx)**.
|
|
37
40
|
|
|
38
41
|
## License
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import * as t from "@babel/types";
|
|
2
2
|
import { ArgumentPlaceholder, CallExpression, ExportAllDeclaration, ExportDefaultDeclaration, ExportNamedDeclaration, Expression, ImportDeclaration, SpreadElement } from "@babel/types";
|
|
3
3
|
import * as Parser from "@babel/parser";
|
|
4
|
-
import
|
|
4
|
+
import * as vm from "node:vm";
|
|
5
5
|
import { CompileOpt, CompileOpt as CompileOpt$1 } from "@mbler/mcx-types";
|
|
6
|
+
import { Plugin } from "rollup";
|
|
6
7
|
import { Plugin as Plugin$1 } from "rolldown";
|
|
7
8
|
import { EnchantableSlot, EntityComponentOptions, FoodEffect, ItemComponentOptions, ParticleType, Rarity, SoundEvent } from "@mbler/mcx-component";
|
|
8
9
|
|
|
@@ -75,8 +76,21 @@ declare class MCXCompileData {
|
|
|
75
76
|
constructor(raw: ParsedTagNode[], JSIR: JsCompileData, strLoc: MCXstructureLoc);
|
|
76
77
|
setFilePath(dir: string): void;
|
|
77
78
|
}
|
|
79
|
+
//#endregion
|
|
80
|
+
//#region src/mcx-component/moduleResolver.d.ts
|
|
81
|
+
type FileTransformFn = (code: string, id: string) => string;
|
|
82
|
+
declare class ModuleResolver {
|
|
83
|
+
private cache;
|
|
84
|
+
private loadingModules;
|
|
85
|
+
private transformFile;
|
|
86
|
+
constructor(cache: Map<string, string>, transformFile: FileTransformFn);
|
|
87
|
+
getCache(): Map<string, string>;
|
|
88
|
+
clear(): void;
|
|
89
|
+
ensureModule(specifier: string, importerPath: string, context: vm.Context, nativeRequire?: (id: string) => unknown): unknown;
|
|
90
|
+
private executeInContext;
|
|
91
|
+
}
|
|
78
92
|
declare namespace types_d_exports$1 {
|
|
79
|
-
export { AttributeMap, BaseToken, CommentToken, ContentToken, JsType, MCXLoc, MCXPosition, ParseReadFileOpt, ParsedCommentNode, ParsedTagContentNode, ParsedTagNode, PropNode, PropValue, ReadFileOpt, TagEndToken, TagToken, Token, TokenType, TypeVerifyBody, mcxType, transformCtx, transformParseCtx };
|
|
93
|
+
export { AttributeMap, BaseToken, CommentToken, ContentToken, JsType, MCXLoc, MCXPosition, McxPluginContext, ParseReadFileOpt, ParsedCommentNode, ParsedTagContentNode, ParsedTagNode, PropNode, PropValue, ReadFileOpt, TagEndToken, TagToken, Token, TokenType, TypeVerifyBody, mcxType, transformCtx, transformParseCtx };
|
|
80
94
|
}
|
|
81
95
|
interface BaseToken {
|
|
82
96
|
data: string;
|
|
@@ -143,8 +157,20 @@ interface ParseReadFileOpt {
|
|
|
143
157
|
}
|
|
144
158
|
type ReadFileOpt = Partial<ParseReadFileOpt>;
|
|
145
159
|
type mcxType = 'component' | 'event' | 'app' | 'ui' | 'form';
|
|
160
|
+
interface McxPluginContext {
|
|
161
|
+
error: (err: string | {
|
|
162
|
+
message: string;
|
|
163
|
+
[key: string]: unknown;
|
|
164
|
+
}, extra?: number | {
|
|
165
|
+
column: number;
|
|
166
|
+
line: number;
|
|
167
|
+
}) => void;
|
|
168
|
+
warn: (warning: string | {
|
|
169
|
+
message: string;
|
|
170
|
+
}) => void;
|
|
171
|
+
}
|
|
146
172
|
interface transformCtx {
|
|
147
|
-
rollupContext:
|
|
173
|
+
rollupContext: McxPluginContext;
|
|
148
174
|
compiledCode: MCXCompileData;
|
|
149
175
|
cache: Map<string, MCXCompileData>;
|
|
150
176
|
currentId: string;
|
|
@@ -161,6 +187,7 @@ interface transformCtx {
|
|
|
161
187
|
behavior: string;
|
|
162
188
|
resources: string;
|
|
163
189
|
};
|
|
190
|
+
moduleResolver?: ModuleResolver;
|
|
164
191
|
}
|
|
165
192
|
interface transformParseCtx {
|
|
166
193
|
prop: t.ObjectProperty[];
|
|
@@ -331,7 +358,8 @@ declare class RunScript {
|
|
|
331
358
|
private _context;
|
|
332
359
|
private _module;
|
|
333
360
|
private _pluginContext;
|
|
334
|
-
|
|
361
|
+
private _moduleResolver;
|
|
362
|
+
constructor(filePath?: string, module?: 'esm' | 'cjs', pluginContext?: Record<string, string | null | boolean | number> | undefined, moduleResolver?: ModuleResolver);
|
|
335
363
|
/**
|
|
336
364
|
* run code in nodejs vm
|
|
337
365
|
* @param code {string} exetuce code
|
|
@@ -392,7 +420,7 @@ declare function generateItemTextureJson(output: {
|
|
|
392
420
|
declare function compileComponent(compiledCode: MCXCompileData, ctx: transformCtx): Promise<void>;
|
|
393
421
|
//#endregion
|
|
394
422
|
//#region src/transforms/index.d.ts
|
|
395
|
-
declare function transform(code: MCXCompileData, cache: Map<string, MCXCompileData>, id: string, context:
|
|
423
|
+
declare function transform(code: MCXCompileData, cache: Map<string, MCXCompileData>, id: string, context: McxPluginContext, opt: CompileOpt, output: transformCtx['output'], moduleResolver?: ModuleResolver): Promise<string>;
|
|
396
424
|
//#endregion
|
|
397
425
|
export { _default as AST, types_d_exports as ComponentType, types_d_exports$1 as PubType, index_d_exports as compile_component, index_d_exports$1 as compiler, rolldownPlugin, rollupPlugin, transform, Utils as utils };
|
|
398
426
|
//# sourceMappingURL=index.d.ts.map
|
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";
|
|
@@ -1178,11 +1178,12 @@ function generateLayout(ctx, tagNode, tagName, mode) {
|
|
|
1178
1178
|
const formType = detectFormType(name);
|
|
1179
1179
|
if (formType) typeTags.push(formType);
|
|
1180
1180
|
}
|
|
1181
|
+
const _paramCtx = t.identifier("ctx");
|
|
1181
1182
|
const paramsObj = t.objectExpression(Object.entries(cleanedArr).filter(([key]) => key !== "for" && key !== "if").map(([key, value]) => {
|
|
1182
1183
|
const isDynamic = key.startsWith(":");
|
|
1183
1184
|
const paramName = isDynamic ? key.slice(1) : key;
|
|
1184
1185
|
if (paramName === "click") return t.objectProperty(t.identifier(paramName), simpleFn(String(value)));
|
|
1185
|
-
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)));
|
|
1186
1187
|
}));
|
|
1187
1188
|
const contentExpr = mode === "form" ? parseContentForm(el.content) : parseContent(el.content);
|
|
1188
1189
|
const props = [
|
|
@@ -1247,41 +1248,12 @@ function simpleFn(expr) {
|
|
|
1247
1248
|
const body = dotAccess(expr, ctx);
|
|
1248
1249
|
return t.arrowFunctionExpression([ctx], body);
|
|
1249
1250
|
}
|
|
1250
|
-
/** Extract root identifiers from an expression for dependency tracking */
|
|
1251
|
-
function extractIdentifiers(expr) {
|
|
1252
|
-
const reserved = new Set([
|
|
1253
|
-
"true",
|
|
1254
|
-
"false",
|
|
1255
|
-
"null",
|
|
1256
|
-
"undefined",
|
|
1257
|
-
"this",
|
|
1258
|
-
"new",
|
|
1259
|
-
"typeof",
|
|
1260
|
-
"instanceof"
|
|
1261
|
-
]);
|
|
1262
|
-
const ids = /* @__PURE__ */ new Set();
|
|
1263
|
-
const regex = /\b([a-zA-Z_$][\w$]*)\b/g;
|
|
1264
|
-
let m;
|
|
1265
|
-
while ((m = regex.exec(expr)) !== null) if (!reserved.has(m[1])) ids.add(m[1]);
|
|
1266
|
-
return [...ids];
|
|
1267
|
-
}
|
|
1268
|
-
/** Generate new Computation((ctx) => expr, [deps]) */
|
|
1269
|
-
function arrowFn(expr) {
|
|
1270
|
-
const ctx = t.identifier("ctx");
|
|
1271
|
-
const body = dotAccess(expr, ctx);
|
|
1272
|
-
const evalFn = t.arrowFunctionExpression([ctx], body);
|
|
1273
|
-
const deps = extractIdentifiers(expr).map((id) => {
|
|
1274
|
-
const c = t.identifier("ctx");
|
|
1275
|
-
return t.arrowFunctionExpression([c], dotAccess(id, c));
|
|
1276
|
-
});
|
|
1277
|
-
return t.newExpression(t.identifier("Computation"), [evalFn, t.arrayExpression(deps)]);
|
|
1278
|
-
}
|
|
1279
1251
|
/** Parse content for form mode: never creates Computation, uses plain functions */
|
|
1280
1252
|
function parseContentForm(raw) {
|
|
1281
|
-
|
|
1253
|
+
const ctx = t.identifier("ctx");
|
|
1254
|
+
if (!raw.includes("{{ ")) return t.arrowFunctionExpression([ctx], t.stringLiteral(raw));
|
|
1282
1255
|
const parts = splitInterpolation(raw);
|
|
1283
1256
|
if (parts.length === 1 && parts[0].type === "expr") return simpleFn(parts[0].value);
|
|
1284
|
-
const ctx = t.identifier("ctx");
|
|
1285
1257
|
const quasis = [];
|
|
1286
1258
|
const expressions = [];
|
|
1287
1259
|
for (const part of parts) if (part.type === "text") quasis.push(t.templateElement({
|
|
@@ -1297,43 +1269,29 @@ function parseContentForm(raw) {
|
|
|
1297
1269
|
return t.arrowFunctionExpression([ctx], tpl);
|
|
1298
1270
|
}
|
|
1299
1271
|
/**
|
|
1300
|
-
* Parse content string, returns:
|
|
1301
|
-
* -
|
|
1302
|
-
* -
|
|
1303
|
-
*
|
|
1304
|
-
* Supports:
|
|
1305
|
-
* - "Hello" → "Hello"
|
|
1306
|
-
* - "{{ a }}" → new Computation((ctx) => ctx[0].a, [ctx => ctx[0].a])
|
|
1307
|
-
* - "Hi {{ a }}" → new Computation((ctx) => `Hi ${ctx[0].a}`, [ctx => ctx[0].a])
|
|
1308
|
-
* - "{{ 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}`
|
|
1309
1276
|
*/
|
|
1310
1277
|
function parseContent(raw) {
|
|
1311
|
-
if (!raw.includes("{{ ")) return t.stringLiteral(raw);
|
|
1312
|
-
const parts = splitInterpolation(raw);
|
|
1313
|
-
if (parts.length === 1 && parts[0].type === "expr") return arrowFn(parts[0].value);
|
|
1314
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);
|
|
1315
1282
|
const quasis = [];
|
|
1316
1283
|
const expressions = [];
|
|
1317
|
-
const allIds = /* @__PURE__ */ new Set();
|
|
1318
1284
|
for (const part of parts) if (part.type === "text") quasis.push(t.templateElement({
|
|
1319
1285
|
raw: part.value,
|
|
1320
1286
|
cooked: part.value
|
|
1321
1287
|
}));
|
|
1322
|
-
else
|
|
1323
|
-
expressions.push(dotAccess(part.value, ctx));
|
|
1324
|
-
for (const id of extractIdentifiers(part.value)) allIds.add(id);
|
|
1325
|
-
}
|
|
1288
|
+
else expressions.push(dotAccess(part.value, ctx));
|
|
1326
1289
|
quasis.push(t.templateElement({
|
|
1327
1290
|
raw: "",
|
|
1328
1291
|
cooked: ""
|
|
1329
1292
|
}, true));
|
|
1330
1293
|
const tpl = t.templateLiteral(quasis, expressions);
|
|
1331
|
-
|
|
1332
|
-
const deps = [...allIds].map((id) => {
|
|
1333
|
-
const c = t.identifier("ctx");
|
|
1334
|
-
return t.arrowFunctionExpression([c], dotAccess(id, c));
|
|
1335
|
-
});
|
|
1336
|
-
return t.newExpression(t.identifier("Computation"), [evalFn, t.arrayExpression(deps)]);
|
|
1294
|
+
return t.arrowFunctionExpression([ctx], tpl);
|
|
1337
1295
|
}
|
|
1338
1296
|
function splitInterpolation(raw) {
|
|
1339
1297
|
const result = [];
|
|
@@ -1573,12 +1531,14 @@ var RunScript = class {
|
|
|
1573
1531
|
_context;
|
|
1574
1532
|
_module;
|
|
1575
1533
|
_pluginContext;
|
|
1576
|
-
|
|
1534
|
+
_moduleResolver;
|
|
1535
|
+
constructor(filePath = "<repl>", module = "cjs", pluginContext, moduleResolver) {
|
|
1577
1536
|
this.filePath = filePath;
|
|
1578
1537
|
this.module = module;
|
|
1579
1538
|
this.pluginContext = pluginContext;
|
|
1580
1539
|
this._module = new Module.Module(this.filePath);
|
|
1581
1540
|
this._pluginContext = pluginContext || {};
|
|
1541
|
+
this._moduleResolver = moduleResolver;
|
|
1582
1542
|
this._context = this.getContext(this._pluginContext);
|
|
1583
1543
|
}
|
|
1584
1544
|
/**
|
|
@@ -1630,15 +1590,21 @@ var RunScript = class {
|
|
|
1630
1590
|
id: this.filePath
|
|
1631
1591
|
};
|
|
1632
1592
|
const originalRequire = Module.createRequire ? Module.createRequire(this.filePath) : __require;
|
|
1633
|
-
const
|
|
1593
|
+
const contextRequire = new Proxy(originalRequire, { apply: (target, thisArg, args) => {
|
|
1634
1594
|
const id = args[0];
|
|
1635
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
|
+
}
|
|
1636
1602
|
return Reflect.apply(target, thisArg, args);
|
|
1637
1603
|
} });
|
|
1638
1604
|
Object.assign(context, {
|
|
1639
1605
|
exports,
|
|
1640
1606
|
module,
|
|
1641
|
-
require:
|
|
1607
|
+
require: contextRequire,
|
|
1642
1608
|
global: context
|
|
1643
1609
|
});
|
|
1644
1610
|
return vm.createContext(context);
|
|
@@ -1859,23 +1825,7 @@ async function compileComponent(compiledCode, ctx) {
|
|
|
1859
1825
|
const src = compiledCode.strLoc.script;
|
|
1860
1826
|
const exportSources = collectExportSources(src);
|
|
1861
1827
|
checkComponentImports(exportSources, compiledCode.File);
|
|
1862
|
-
const scriptRunResult = await new RunScript(compiledCode.File, "esm").run(src, 0
|
|
1863
|
-
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") {
|
|
1864
|
-
const arg = data.arguments[0].arguments[0];
|
|
1865
|
-
if (arg && arg.type == "StringLiteral") {
|
|
1866
|
-
if (/^.+?\.(png|svg|jpg|jpeg|gif)$/.test(arg.value)) {
|
|
1867
|
-
const imageComponentRequire = t.memberExpression(t.callExpression(t.identifier("require"), [t.stringLiteral("@mbler/mcx-component")]), t.identifier({
|
|
1868
|
-
png: "PNGImageComponent",
|
|
1869
|
-
svg: "SVGImageComponent",
|
|
1870
|
-
jpg: "JPGImageComponent",
|
|
1871
|
-
jpeg: "JPGImageComponent",
|
|
1872
|
-
gif: "GIFImageComponent"
|
|
1873
|
-
}[path.extname(arg.value).slice(1)]));
|
|
1874
|
-
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])]));
|
|
1875
|
-
}
|
|
1876
|
-
}
|
|
1877
|
-
}
|
|
1878
|
-
});
|
|
1828
|
+
const scriptRunResult = await new RunScript(compiledCode.File, "esm", void 0, ctx.moduleResolver).run(src, 0);
|
|
1879
1829
|
if (!component) throw new Error("[component internal error]: compile component: mcx is not component: filePath: " + compiledCode.File);
|
|
1880
1830
|
if (typeof scriptRunResult !== "object") throw new Error("[component compile error]: exec code: mcx export type is not object");
|
|
1881
1831
|
for (const i of Object.entries(component)) {
|
|
@@ -1973,14 +1923,10 @@ async function _transform(ctx) {
|
|
|
1973
1923
|
|
|
1974
1924
|
//#endregion
|
|
1975
1925
|
//#region src/transforms/index.ts
|
|
1976
|
-
function
|
|
1977
|
-
|
|
1978
|
-
...err,
|
|
1979
|
-
message: `${err.message} (At ${id})`
|
|
1980
|
-
};
|
|
1981
|
-
else return { message: String(err) };
|
|
1926
|
+
function toMcxError(err, id) {
|
|
1927
|
+
return { message: err instanceof Error ? `${err.message} (At ${id})` : String(err) };
|
|
1982
1928
|
}
|
|
1983
|
-
async function transform(code, cache, id, context, opt, output) {
|
|
1929
|
+
async function transform(code, cache, id, context, opt, output, moduleResolver) {
|
|
1984
1930
|
try {
|
|
1985
1931
|
const scriptTag = code.raw.find((node) => {
|
|
1986
1932
|
return node.name == "script";
|
|
@@ -1999,18 +1945,149 @@ async function transform(code, cache, id, context, opt, output) {
|
|
|
1999
1945
|
param: [],
|
|
2000
1946
|
body: []
|
|
2001
1947
|
},
|
|
2002
|
-
output
|
|
1948
|
+
output,
|
|
1949
|
+
...moduleResolver ? { moduleResolver } : {}
|
|
2003
1950
|
});
|
|
2004
1951
|
} catch (err) {
|
|
2005
|
-
context.error(
|
|
1952
|
+
context.error(toMcxError(err, id));
|
|
2006
1953
|
return "";
|
|
2007
1954
|
}
|
|
2008
1955
|
}
|
|
2009
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
|
+
|
|
2010
2078
|
//#endregion
|
|
2011
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
|
+
]);
|
|
2012
2087
|
function createMcxPlugin(opt, output) {
|
|
2013
2088
|
let cache = /* @__PURE__ */ new Map();
|
|
2089
|
+
let moduleTransformCache;
|
|
2090
|
+
let moduleResolver;
|
|
2014
2091
|
let tsconfig;
|
|
2015
2092
|
try {
|
|
2016
2093
|
const configResult = ts.readConfigFile(opt.tsconfigPath, (path) => {
|
|
@@ -2037,29 +2114,6 @@ function createMcxPlugin(opt, output) {
|
|
|
2037
2114
|
errors: []
|
|
2038
2115
|
};
|
|
2039
2116
|
}
|
|
2040
|
-
const resolveExtensions = [
|
|
2041
|
-
"",
|
|
2042
|
-
".ts",
|
|
2043
|
-
".mts",
|
|
2044
|
-
".cts",
|
|
2045
|
-
".js",
|
|
2046
|
-
".mjs",
|
|
2047
|
-
".cjs"
|
|
2048
|
-
];
|
|
2049
|
-
const indexExtensions = resolveExtensions.map((ext) => "/index" + ext);
|
|
2050
|
-
async function tryResolvePath(filePath) {
|
|
2051
|
-
for (const idxExt of indexExtensions) try {
|
|
2052
|
-
const fullPath = filePath + idxExt;
|
|
2053
|
-
await readFile(fullPath, "utf-8");
|
|
2054
|
-
return fullPath;
|
|
2055
|
-
} catch {}
|
|
2056
|
-
for (const ext of resolveExtensions) try {
|
|
2057
|
-
const fullPath = filePath + ext;
|
|
2058
|
-
await readFile(fullPath, "utf-8");
|
|
2059
|
-
return fullPath;
|
|
2060
|
-
} catch {}
|
|
2061
|
-
return null;
|
|
2062
|
-
}
|
|
2063
2117
|
async function resolvePackageExports(pkgDir, subPath, pkgJson) {
|
|
2064
2118
|
const exports = pkgJson.exports;
|
|
2065
2119
|
if (exports) {
|
|
@@ -2093,7 +2147,7 @@ function createMcxPlugin(opt, output) {
|
|
|
2093
2147
|
if (i.dir.startsWith(".") || i.root) {
|
|
2094
2148
|
if (imp) {
|
|
2095
2149
|
const baseDir = path.dirname(imp);
|
|
2096
|
-
const resolved = await
|
|
2150
|
+
const resolved = await resolveFileAsync(path.join(baseDir, id));
|
|
2097
2151
|
if (resolved) return resolved;
|
|
2098
2152
|
}
|
|
2099
2153
|
return null;
|
|
@@ -2118,9 +2172,9 @@ function createMcxPlugin(opt, output) {
|
|
|
2118
2172
|
if (subPath) {
|
|
2119
2173
|
const fromExports = await resolvePackageExports(d, subPath, pkgJson);
|
|
2120
2174
|
if (fromExports) return fromExports;
|
|
2121
|
-
const fromDist = await
|
|
2175
|
+
const fromDist = await resolveFileAsync(path.join(d, "./dist", subPath));
|
|
2122
2176
|
if (fromDist) return fromDist;
|
|
2123
|
-
const fromRoot = await
|
|
2177
|
+
const fromRoot = await resolveFileAsync(path.join(d, subPath));
|
|
2124
2178
|
if (fromRoot) return fromRoot;
|
|
2125
2179
|
return null;
|
|
2126
2180
|
}
|
|
@@ -2146,31 +2200,60 @@ function createMcxPlugin(opt, output) {
|
|
|
2146
2200
|
}
|
|
2147
2201
|
compileData.setFilePath(id);
|
|
2148
2202
|
return {
|
|
2149
|
-
code: await transform(compileData, cache, id, this, opt, output),
|
|
2150
|
-
|
|
2203
|
+
code: await transform(compileData, cache, id, this, opt, output, moduleResolver),
|
|
2204
|
+
...opt.sourcemap ? { map: magic.generateMap({
|
|
2151
2205
|
hires: true,
|
|
2152
2206
|
source: id
|
|
2153
|
-
}) :
|
|
2207
|
+
}) } : {}
|
|
2154
2208
|
};
|
|
2155
|
-
}
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
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({
|
|
2161
2214
|
hires: true,
|
|
2162
2215
|
source: id
|
|
2163
|
-
}) :
|
|
2216
|
+
}) } : {}
|
|
2164
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
|
+
}
|
|
2165
2237
|
return null;
|
|
2166
2238
|
},
|
|
2167
2239
|
async buildEnd() {
|
|
2168
2240
|
cache.clear();
|
|
2241
|
+
moduleResolver?.clear();
|
|
2169
2242
|
await generateItemTextureJson(output);
|
|
2170
2243
|
clearCachedOptions();
|
|
2171
2244
|
},
|
|
2172
2245
|
buildStart() {
|
|
2173
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
|
+
});
|
|
2174
2257
|
}
|
|
2175
2258
|
};
|
|
2176
2259
|
}
|