@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/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 === "form") {
1065
- const formType = detectFormType(name);
1066
- if (formType === "invalid") {
1067
- internalCtx.rollupContext.error(`[${tagName}]: don't support tag: ${name}`, el.loc ? {
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
- /** Extract root identifiers from an expression for dependency tracking */
1145
- function extractIdentifiers(expr) {
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
- const body = dotAccess(expr, ctx);
1166
- const evalFn = t.arrowFunctionExpression([ctx], body);
1167
- const deps = extractIdentifiers(expr).map((id) => {
1168
- const c = t.identifier("ctx");
1169
- return t.arrowFunctionExpression([c], dotAccess(id, c));
1170
- });
1171
- return t.newExpression(t.identifier("Computation"), [evalFn, t.arrayExpression(deps)]);
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
- * - t.stringLiteral for pure static text
1176
- * - t.NewExpression (Computation) for content with {{ }} interpolation
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
- const evalFn = t.arrowFunctionExpression([ctx], tpl);
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
- constructor(filePath = "<repl>", module = "cjs", pluginContext) {
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 restrictedRequire = new Proxy(originalRequire, { apply(target, thisArg, args) {
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: restrictedRequire,
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, (data, setData) => {
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 createErrorProxy(err, id) {
1851
- if (err instanceof Error) return {
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(createErrorProxy(err, id));
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 tryResolvePath(path.join(baseDir, id));
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 tryResolvePath(path.join(d, "./dist", subPath));
2175
+ const fromDist = await resolveFileAsync(path.join(d, "./dist", subPath));
1996
2176
  if (fromDist) return fromDist;
1997
- const fromRoot = await tryResolvePath(path.join(d, subPath));
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
- map: opt.sourcemap ? magic.generateMap({
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
- }) : void 0
2207
+ }) } : {}
2028
2208
  };
2029
- } else if (tsRegex.test(id)) return {
2030
- code: ts.transpileModule(code, {
2031
- compilerOptions: tsconfig.options,
2032
- fileName: id
2033
- }).outputText,
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
- }) : void 0
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
  }