@mbler/mcx-core 0.1.3-rc.6 → 0.1.3-rc.9

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 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 { Plugin, TransformPluginContext } from "rollup";
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: TransformPluginContext;
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
- constructor(filePath?: string, module?: 'esm' | 'cjs', pluginContext?: Record<string, string | null | boolean | number> | undefined);
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: TransformPluginContext, opt: CompileOpt, output: transformCtx['output']): Promise<string>;
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
- if (!raw.includes("{{ ")) return t.stringLiteral(raw);
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
- * - t.stringLiteral for pure static text
1302
- * - t.NewExpression (Computation) for content with {{ }} interpolation
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
- const evalFn = t.arrowFunctionExpression([ctx], tpl);
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
- constructor(filePath = "<repl>", module = "cjs", pluginContext) {
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 restrictedRequire = new Proxy(originalRequire, { apply(target, thisArg, args) {
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: restrictedRequire,
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, (data, setData) => {
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 createErrorProxy(err, id) {
1977
- if (err instanceof Error) return {
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(createErrorProxy(err, id));
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 tryResolvePath(path.join(baseDir, id));
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 tryResolvePath(path.join(d, "./dist", subPath));
2175
+ const fromDist = await resolveFileAsync(path.join(d, "./dist", subPath));
2122
2176
  if (fromDist) return fromDist;
2123
- const fromRoot = await tryResolvePath(path.join(d, subPath));
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
- map: opt.sourcemap ? magic.generateMap({
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
- }) : void 0
2207
+ }) } : {}
2154
2208
  };
2155
- } else if (tsRegex.test(id)) return {
2156
- code: ts.transpileModule(code, {
2157
- compilerOptions: tsconfig.options,
2158
- fileName: id
2159
- }).outputText,
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
- }) : void 0
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
  }