@tilua/compiler 2.3.0 → 3.0.0

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.
@@ -21,10 +21,10 @@ var nil = () => ({ type: "NilLiteral", ...span() });
21
21
  var boolean = (value) => ({ type: "BooleanLiteral", value, ...span() });
22
22
  var number = (value, raw = String(value)) => ({ type: "NumberLiteral", value, raw, ...span() });
23
23
  var string = (value) => ({ type: "StringLiteral", value, raw: "", ...span() });
24
- var member = (object, property) => isLuauName(property) ? { type: "MemberExpression", object, property: identifier(property), ...span() } : index(object, string(property));
25
- var index = (object, key) => ({ type: "IndexExpression", object, index: key, ...span() });
24
+ var member = (object2, property) => isLuauName(property) ? { type: "MemberExpression", object: object2, property: identifier(property), ...span() } : index(object2, string(property));
25
+ var index = (object2, key) => ({ type: "IndexExpression", object: object2, index: key, ...span() });
26
26
  var call = (callee, args) => ({ type: "CallExpression", callee, arguments: args, ...span() });
27
- var methodCall = (object, method, args) => ({ type: "MethodCallExpression", object, method: identifier(method), arguments: args, ...span() });
27
+ var methodCall = (object2, method, args) => ({ type: "MethodCallExpression", object: object2, method: identifier(method), arguments: args, ...span() });
28
28
  var functionExpression = (func) => ({ type: "FunctionExpression", func, ...span() });
29
29
  var binary = (operator, left, right) => ({ type: "BinaryExpression", operator, left, right, ...span() });
30
30
  var unary = (operator, argument) => ({ type: "UnaryExpression", operator, argument, ...span() });
@@ -140,6 +140,62 @@ var Names = class _Names {
140
140
  }
141
141
  };
142
142
 
143
+ // src/language.ts
144
+ import { readFileSync } from "fs";
145
+ var read = (name) => readFileSync(new URL(`../runtime/${name}`, import.meta.url), "utf8");
146
+ var implemented = (source) => new Set([...source.matchAll(/function __NAME__\.(\w+)/g)].map((m) => m[1]));
147
+ var array = read("array.luau");
148
+ var string2 = read("string.luau");
149
+ var object = read("object.luau");
150
+ var arrayMethods = implemented(array);
151
+ var stringMethods = implemented(string2);
152
+ var objectMethods = implemented(object);
153
+ function every(type, is, seen = /* @__PURE__ */ new Set()) {
154
+ if (!type || seen.has(type)) return false;
155
+ seen.add(type);
156
+ if (type.kind === "union") {
157
+ return type.types.filter((m) => !(m.kind === "primitive" && m.name === "nil")).every((m) => every(m, is, seen));
158
+ }
159
+ if (type.kind === "typeParam") return every(type.constraint, is, seen);
160
+ return is(type);
161
+ }
162
+ var isArray = (type) => every(type, (t) => t.kind === "array" || t.kind === "tuple");
163
+ var isString = (type) => every(type, (t) => t.kind === "primitive" && t.name === "string" || t.kind === "literal" && t.base === "string" || t.kind === "templateLiteral");
164
+ function objectKeys(type) {
165
+ const members = type?.kind === "union" ? type.types : type ? [type] : [];
166
+ const orders = [];
167
+ let open = false;
168
+ for (const member2 of members) {
169
+ const keys = [];
170
+ for (const part of member2.kind === "intersection" ? member2.types : [member2]) {
171
+ if (part.kind !== "object") continue;
172
+ for (const key of part.properties.keys()) if (!keys.includes(key)) keys.push(key);
173
+ if (part.indexer) open = true;
174
+ }
175
+ orders.push(keys);
176
+ }
177
+ const order = JSON.stringify(orders[0] ?? []);
178
+ const known = orders.length && orders.every((keys) => JSON.stringify(keys) === order) ? `{ ${orders[0].map((key) => JSON.stringify(key)).join(", ")} }` : "nil";
179
+ return { known, open: String(open) };
180
+ }
181
+ var plugin = {
182
+ runtime: { array, string: string2, object },
183
+ methodCall({ method, receiver, use }) {
184
+ if (isString(receiver)) {
185
+ return stringMethods.has(method) ? { callee: `${use("string")}.${method}` } : void 0;
186
+ }
187
+ if (isArray(receiver)) {
188
+ return arrayMethods.has(method) ? { callee: `${use("array")}.${method}` } : void 0;
189
+ }
190
+ if (objectMethods.has(method)) {
191
+ const keys = objectKeys(receiver);
192
+ return { callee: `${use("object")}.${method}`, prepend: [keys.known, keys.open] };
193
+ }
194
+ return void 0;
195
+ }
196
+ };
197
+ var languageLowering = { plugin, from: "tilua" };
198
+
143
199
  // src/lower.ts
144
200
  function lower(program2, scopes, options = {}) {
145
201
  return new Lowerer(program2, scopes, options).run();
@@ -323,21 +379,34 @@ var Lowerer = class {
323
379
  if (id === void 0) return node.name;
324
380
  return this.scopes.bindings.get(id)?.kind === "global" ? node.name : void 0;
325
381
  }
326
- /** What a library says `receiver:method(...)` is. The last library
327
- * loaded is asked first, so a project's own library can answer for a
328
- * method an earlier one also claims; no answer leaves an ordinary Luau
329
- * method call, which is what a value that answers to the method itself
330
- * wants (`text:upper()`). */
382
+ /** The language's own lowering, then each library's, in load order. A
383
+ * runtime is named by its lowering's place here (`loweringRuntime`). */
384
+ get lowerings() {
385
+ return this.allLowerings ??= [languageLowering, ...this.options.lowerings ?? []];
386
+ }
387
+ allLowerings;
388
+ /** What `receiver:method(...)` becomes, when Luau alone would not run it.
389
+ *
390
+ * A method the receiver's metatable gave it — the analyzer says so, and
391
+ * whose metatable it was (`methodSources`) — is asked of whoever declared
392
+ * that metatable, and only them: the language lowers its own
393
+ * (`names:filter(f)` becomes a call into its runtime), a library its own,
394
+ * and one the program declared is taken at its word. Any other method is
395
+ * a member of the receiver's own, which a library may still claim
396
+ * (`console:log`), the last library loaded first. No answer leaves an
397
+ * ordinary Luau method call: `text:upper()` reaches Lua's own. */
331
398
  loweredMethodCall(node) {
332
- const lowerings = this.options.lowerings;
333
- if (!lowerings?.some((l) => l.plugin.methodCall)) return void 0;
399
+ const lowerings = this.lowerings;
400
+ const source = this.options.types?.methodSources.get(node);
401
+ const asked = source?.origin === "language" ? [0] : source?.origin === "library" ? lowerings.flatMap((l, i) => l.library === source.library ? [i] : []) : source?.origin === "program" ? [] : lowerings.map((_, i) => i).slice(1).reverse();
402
+ if (!asked.some((i) => lowerings[i].plugin.methodCall)) return void 0;
334
403
  const receiver = this.options.types?.typeOf.get(node.object);
335
404
  const receiverGlobal = this.globalName(node.object);
336
405
  const info = this.lazyArguments(node.arguments);
337
- for (let i = lowerings.length - 1; i >= 0; i--) {
338
- const plugin = lowerings[i].plugin;
339
- if (!plugin.methodCall) continue;
340
- const answer = plugin.methodCall({
406
+ for (const i of asked) {
407
+ const plugin2 = lowerings[i].plugin;
408
+ if (!plugin2.methodCall) continue;
409
+ const answer = plugin2.methodCall({
341
410
  method: node.method.name,
342
411
  receiver,
343
412
  receiverGlobal,
@@ -360,15 +429,15 @@ var Lowerer = class {
360
429
  }
361
430
  /** What a library says a call to a global — `print(x)` — is. */
362
431
  loweredGlobalCall(node) {
363
- const lowerings = this.options.lowerings;
432
+ const lowerings = this.lowerings;
364
433
  if (!lowerings?.some((l) => l.plugin.globalCall)) return void 0;
365
434
  const name = this.globalName(node.callee);
366
435
  if (name === void 0) return void 0;
367
436
  const info = this.lazyArguments(node.arguments);
368
437
  for (let i = lowerings.length - 1; i >= 0; i--) {
369
- const plugin = lowerings[i].plugin;
370
- if (!plugin.globalCall) continue;
371
- const answer = plugin.globalCall({
438
+ const plugin2 = lowerings[i].plugin;
439
+ if (!plugin2.globalCall) continue;
440
+ const answer = plugin2.globalCall({
372
441
  name,
373
442
  at: this.callSite(node.callee),
374
443
  get arguments() {
@@ -382,7 +451,7 @@ var Lowerer = class {
382
451
  }
383
452
  /** What a library says a global read as a value — `local p = print` — is. */
384
453
  loweredGlobalValue(node) {
385
- const lowerings = this.options.lowerings;
454
+ const lowerings = this.lowerings;
386
455
  if (!lowerings?.some((l) => l.plugin.globalValue)) return void 0;
387
456
  const name = this.globalName(node);
388
457
  if (name === void 0) return void 0;
@@ -412,7 +481,7 @@ var Lowerer = class {
412
481
  try {
413
482
  return parseExpressionFromSource(source);
414
483
  } catch (error) {
415
- this.report(node, `'${this.options.lowerings[index2].from}' lowered this to Luau that does not parse: ${JSON.stringify(source)} (${error.message})`);
484
+ this.report(node, `'${this.lowerings[index2].from}' lowered this to Luau that does not parse: ${JSON.stringify(source)} (${error.message})`);
416
485
  return void 0;
417
486
  }
418
487
  }
@@ -433,8 +502,8 @@ var Lowerer = class {
433
502
  ], true)));
434
503
  }
435
504
  for (const { index: index2, runtime: runtime2, name } of this.loweringUsed) {
436
- const { plugin, from } = this.options.lowerings[index2];
437
- const source = plugin.runtime?.[runtime2];
505
+ const { plugin: plugin2, from } = this.lowerings[index2];
506
+ const source = plugin2.runtime?.[runtime2];
438
507
  if (source === void 0) {
439
508
  this.diagnostics.push({
440
509
  message: `'${from}' asked for a runtime it does not have: '${runtime2}'`,
@@ -769,6 +838,7 @@ var Lowerer = class {
769
838
  case "ExportTypeAliasStatement":
770
839
  case "DeclareStatement":
771
840
  case "DeclareClassStatement":
841
+ case "DeclareMetatableStatement":
772
842
  case "ErrorStatement":
773
843
  return [];
774
844
  case "VariableDeclaration":
@@ -846,12 +916,13 @@ var Lowerer = class {
846
916
  }];
847
917
  case "GenericForStatement": {
848
918
  const prelude = [];
919
+ const variable = declared(node.variable);
849
920
  let item;
850
- if (node.variable.type === "IdentifierPattern") {
851
- item = this.name(node.variable.name);
921
+ if (variable.type === "IdentifierPattern") {
922
+ item = this.name(variable.name);
852
923
  } else {
853
924
  item = this.names.fresh("item");
854
- prelude.push(...this.destructure(node.variable, identifier(item), "declare"));
925
+ prelude.push(...this.destructure(variable, identifier(item), "declare"));
855
926
  }
856
927
  const form = this.options.types?.loops.get(node) ?? { walks: "values", viaIter: false };
857
928
  let source = this.expression(node.iterator);
@@ -1118,7 +1189,7 @@ end
1118
1189
  * level, where every name is declared up front — nothing is declared,
1119
1190
  * only assigned. */
1120
1191
  variableDeclaration(node, mode) {
1121
- const target = node.name;
1192
+ const target = declared(node.name);
1122
1193
  if (!node.init) {
1123
1194
  const names = identifierPatterns(target);
1124
1195
  if (mode === "declare") return [local(names.map((p) => this.name(p.name)), [])];
@@ -1160,6 +1231,12 @@ end
1160
1231
  const reads = [];
1161
1232
  const after = [];
1162
1233
  const bind = (target, value, fallback) => {
1234
+ if (target.type === "MemberExpression" || target.type === "IndexExpression") {
1235
+ const reference = this.expression(target);
1236
+ reads.push({ name: "", target: reference, value, temp: false });
1237
+ if (fallback) after.push(this.defaultValue(reference, fallback));
1238
+ return;
1239
+ }
1163
1240
  if (target.type === "IdentifierPattern") {
1164
1241
  const name2 = this.name(target.name);
1165
1242
  const reference = mode === "declare" ? identifier(name2) : this.reference(target);
@@ -1232,6 +1309,11 @@ end
1232
1309
  * a temporary that a nested pattern then destructures (`then`). The
1233
1310
  * statement creating it is pushed onto `after`. */
1234
1311
  restTarget(target, initial, mode, after) {
1312
+ if (target.type === "MemberExpression" || target.type === "IndexExpression") {
1313
+ const reference = this.expression(target);
1314
+ after.push(assign([reference], [initial]));
1315
+ return { target: reference, then: [] };
1316
+ }
1235
1317
  if (target.type === "IdentifierPattern") {
1236
1318
  if (mode === "declare") {
1237
1319
  const name2 = this.name(target.name);
@@ -1357,11 +1439,11 @@ end
1357
1439
  callValues(node) {
1358
1440
  const chain = optionalChain(node);
1359
1441
  if (chain) return this.optionalChainExpression(chain);
1360
- const object = linkObject(node);
1361
- if (node.type === "CallExpression" && object.type === "Identifier") {
1362
- return this.link(node, this.reference(object));
1442
+ const object2 = linkObject(node);
1443
+ if (node.type === "CallExpression" && object2.type === "Identifier") {
1444
+ return this.link(node, this.reference(object2));
1363
1445
  }
1364
- return this.link(node, this.expression(object));
1446
+ return this.link(node, this.expression(object2));
1365
1447
  }
1366
1448
  /** A call is one value in tilua, and Luau would hand on every value one
1367
1449
  * returns in the last place of an argument list or a `return`: it is
@@ -1380,11 +1462,13 @@ end
1380
1462
  * the last value of a list expands, so the whole list is built as an
1381
1463
  * array first and that is what expands. A call written last is one
1382
1464
  * value — see `keptToOne`. */
1383
- arguments(list) {
1465
+ arguments(written) {
1466
+ const { items: list, many } = packs(written);
1384
1467
  const spreads = list.filter((a) => a.type === "SpreadElement");
1385
1468
  if (!spreads.length) {
1386
1469
  const lowered = list.map((a) => this.expression(a));
1387
- return lowered.length ? [...lowered.slice(0, -1), this.keptToOne(lowered[lowered.length - 1])] : lowered;
1470
+ const last2 = list.length - 1;
1471
+ return lowered.length && !many.has(list[last2]) ? [...lowered.slice(0, -1), this.keptToOne(lowered[last2])] : lowered;
1388
1472
  }
1389
1473
  const unpack = (value) => call(member(this.builtin("table"), "unpack"), [value]);
1390
1474
  const last = list[list.length - 1];
@@ -1398,16 +1482,16 @@ end
1398
1482
  }))];
1399
1483
  }
1400
1484
  /** One link of an access chain, read from `object`. */
1401
- link(node, object) {
1485
+ link(node, object2) {
1402
1486
  switch (node.type) {
1403
1487
  case "MemberExpression":
1404
- return member(object, node.property.name);
1488
+ return member(object2, node.property.name);
1405
1489
  case "IndexExpression":
1406
- return index(object, this.expression(node.index));
1490
+ return index(object2, this.expression(node.index));
1407
1491
  case "CallExpression": {
1408
1492
  const lowered = this.loweredGlobalCall(node);
1409
1493
  const args = this.arguments(node.arguments);
1410
- if (!lowered) return call(object, args);
1494
+ if (!lowered) return call(object2, args);
1411
1495
  return call(calleePath(lowered.callee), [...lowered.prepend, ...args]);
1412
1496
  }
1413
1497
  case "MethodCallExpression": {
@@ -1416,14 +1500,14 @@ end
1416
1500
  if (lowered) {
1417
1501
  return call(calleePath(lowered.callee), [
1418
1502
  ...lowered.prepend,
1419
- ...lowered.passReceiver ? [object] : [],
1503
+ ...lowered.passReceiver ? [object2] : [],
1420
1504
  ...args
1421
1505
  ]);
1422
1506
  }
1423
1507
  if (!isLuauName(node.method.name)) {
1424
1508
  this.report(node.method, `'${node.method.name}' is a Luau keyword and cannot be called with ':'`);
1425
1509
  }
1426
- return methodCall(object, node.method.name, args);
1510
+ return methodCall(object2, node.method.name, args);
1427
1511
  }
1428
1512
  }
1429
1513
  }
@@ -1444,8 +1528,8 @@ end
1444
1528
  }
1445
1529
  return out;
1446
1530
  }
1447
- applySegment(segment, object) {
1448
- return segment.reduce((value, link) => this.link(link, value), object);
1531
+ applySegment(segment, object2) {
1532
+ return segment.reduce((value, link) => this.link(link, value), object2);
1449
1533
  }
1450
1534
  /** `a?.b:m()` as a statement:
1451
1535
  * `do local ref = a if ref ~= nil then ref.b:m() end end` */
@@ -1521,9 +1605,9 @@ end
1521
1605
  const before = [];
1522
1606
  let target;
1523
1607
  if (node.target.type === "MemberExpression" || node.target.type === "IndexExpression") {
1524
- const object = this.expression(node.target.object);
1608
+ const object2 = this.expression(node.target.object);
1525
1609
  const objectName = this.names.fresh("target");
1526
- before.push(local([objectName], [object]));
1610
+ before.push(local([objectName], [object2]));
1527
1611
  if (node.target.type === "MemberExpression") {
1528
1612
  target = member(identifier(objectName), node.target.property.name);
1529
1613
  } else {
@@ -1645,8 +1729,9 @@ end
1645
1729
  /** `[1, ...xs, 2]`. Without a spread it is a Luau sequence; with one, the
1646
1730
  * runs of plain elements and the spread arrays are joined by `concat`. */
1647
1731
  arrayExpression(node) {
1648
- if (!node.elements.some((e) => e.type === "SpreadElement")) {
1649
- return table(node.elements.map((e) => ({ type: "TableFieldPositional", value: this.expression(e) })));
1732
+ const elements = packs(node.elements).items;
1733
+ if (!elements.some((e) => e.type === "SpreadElement")) {
1734
+ return table(elements.map((e) => ({ type: "TableFieldPositional", value: this.expression(e) })));
1650
1735
  }
1651
1736
  const parts = [];
1652
1737
  let current = [];
@@ -1658,7 +1743,7 @@ end
1658
1743
  })));
1659
1744
  current = [];
1660
1745
  };
1661
- for (const element of node.elements) {
1746
+ for (const element of elements) {
1662
1747
  if (element.type === "SpreadElement") {
1663
1748
  flush(false);
1664
1749
  parts.push(this.expression(element.argument));
@@ -1670,6 +1755,29 @@ end
1670
1755
  return call(this.helper("concat"), parts);
1671
1756
  }
1672
1757
  };
1758
+ function packs(list) {
1759
+ const items = [];
1760
+ const many = /* @__PURE__ */ new Set();
1761
+ const add = (elements) => {
1762
+ for (const element of elements) {
1763
+ if (element.type === "SpreadElement" && element.argument.type === "ArrayExpression") {
1764
+ const inner = element.argument.elements;
1765
+ add(inner);
1766
+ const last = inner[inner.length - 1];
1767
+ if (last && (last.type === "CallExpression" || last.type === "MethodCallExpression")) many.add(last);
1768
+ } else {
1769
+ items.push(element);
1770
+ }
1771
+ }
1772
+ };
1773
+ add(list);
1774
+ items.forEach((item, i) => {
1775
+ if (!many.has(item) || i === items.length - 1) return;
1776
+ many.delete(item);
1777
+ items[i] = { type: "SpreadElement", argument: { type: "ArrayExpression", elements: [item], ...spanOf(item) }, ...spanOf(item) };
1778
+ });
1779
+ return { items, many };
1780
+ }
1673
1781
  function isLink(node) {
1674
1782
  return node.type === "MemberExpression" || node.type === "IndexExpression" || node.type === "CallExpression" || node.type === "MethodCallExpression";
1675
1783
  }
@@ -1718,10 +1826,19 @@ function memberChain(e) {
1718
1826
  }
1719
1827
  return void 0;
1720
1828
  }
1829
+ function declared(target) {
1830
+ if (target.type === "MemberExpression" || target.type === "IndexExpression") {
1831
+ throw new Error("a declaration binds names, not a member or an index");
1832
+ }
1833
+ return target;
1834
+ }
1721
1835
  function identifierPatterns(target) {
1722
1836
  switch (target.type) {
1723
1837
  case "IdentifierPattern":
1724
1838
  return [target];
1839
+ case "MemberExpression":
1840
+ case "IndexExpression":
1841
+ return [];
1725
1842
  case "ObjectPattern":
1726
1843
  return [...target.properties.flatMap((p) => identifierPatterns(p.value)), ...target.rest ? identifierPatterns(target.rest) : []];
1727
1844
  case "ArrayPattern":
@@ -1871,15 +1988,15 @@ async function loadLowerings(modules) {
1871
1988
  for (const module of modules) {
1872
1989
  try {
1873
1990
  const loaded = await import(pathToFileURL(module.file).href);
1874
- const plugin = loaded.default;
1875
- if (!plugin || typeof plugin !== "object") {
1991
+ const plugin2 = loaded.default;
1992
+ if (!plugin2 || typeof plugin2 !== "object") {
1876
1993
  problems.push({
1877
1994
  file: module.file,
1878
1995
  message: `'${module.from}' lowering module has no default export`
1879
1996
  });
1880
1997
  continue;
1881
1998
  }
1882
- lowerings.push({ plugin, from: module.from });
1999
+ lowerings.push({ plugin: plugin2, from: module.from, library: module.library });
1883
2000
  } catch (error) {
1884
2001
  problems.push({
1885
2002
  file: module.file,
@@ -1891,7 +2008,7 @@ async function loadLowerings(modules) {
1891
2008
  }
1892
2009
 
1893
2010
  // src/bundle.ts
1894
- import { readFileSync, statSync } from "fs";
2011
+ import { readFileSync as readFileSync2, statSync } from "fs";
1895
2012
  import { dirname, relative, resolve as resolve2 } from "path";
1896
2013
  import {
1897
2014
  parse,
@@ -2202,7 +2319,7 @@ function parseFile(file, diagnostics, directives) {
2202
2319
  }
2203
2320
  let text;
2204
2321
  try {
2205
- text = readFileSync(file, "utf8");
2322
+ text = readFileSync2(file, "utf8");
2206
2323
  } catch {
2207
2324
  diagnostics.push({ file, message: "Cannot read file", line: 1, column: 1, category: "module" });
2208
2325
  return void 0;
@@ -2236,7 +2353,7 @@ function parsedLibrary(file) {
2236
2353
  }
2237
2354
  const cached = libraryCache.get(file);
2238
2355
  if (cached && cached.stamp === stamp) return cached.program;
2239
- const program2 = parse(readFileSync(file, "utf8"));
2356
+ const program2 = parse(readFileSync2(file, "utf8"));
2240
2357
  libraryCache.set(file, { stamp, program: program2 });
2241
2358
  return program2;
2242
2359
  }
@@ -2259,7 +2376,7 @@ function analyzeModules(modules, config) {
2259
2376
  const done = analyzed.get(file);
2260
2377
  if (done) return done;
2261
2378
  const remembered = moduleAnalyses.get(file);
2262
- if (remembered && remembered.setting === settingFor && libs.length === remembered.libs.length && remembered.libs.every((lib, i) => lib === libs[i]) && remembered.program === program2 && [...remembered.read].every(([read, stamp]) => stampOf(read) === stamp)) {
2379
+ if (remembered && remembered.setting === settingFor && libs.length === remembered.libs.length && remembered.libs.every((lib, i) => lib === libs[i]) && remembered.program === program2 && [...remembered.read].every(([read2, stamp]) => stampOf(read2) === stamp)) {
2263
2380
  analyzed.set(file, remembered.result);
2264
2381
  readWhile.set(file, remembered.read);
2265
2382
  return remembered.result;
@@ -2283,12 +2400,12 @@ function analyzeModules(modules, config) {
2283
2400
  const result = { types, diagnostics: said };
2284
2401
  if (partials === before) {
2285
2402
  analyzed.set(file, result);
2286
- const read = readWhile.get(file) ?? /* @__PURE__ */ new Map();
2403
+ const read2 = readWhile.get(file) ?? /* @__PURE__ */ new Map();
2287
2404
  const own = stampOf(file);
2288
- if (own !== void 0) read.set(file, own);
2289
- readWhile.set(file, read);
2290
- if ([...read.values()].every((stamp) => stamp !== void 0)) {
2291
- moduleAnalyses.set(file, { setting: settingFor, libs: [...libs], program: program2, read, result });
2405
+ if (own !== void 0) read2.set(file, own);
2406
+ readWhile.set(file, read2);
2407
+ if ([...read2.values()].every((stamp) => stamp !== void 0)) {
2408
+ moduleAnalyses.set(file, { setting: settingFor, libs: [...libs], program: program2, read: read2, result });
2292
2409
  }
2293
2410
  }
2294
2411
  return result;
@@ -2297,11 +2414,11 @@ function analyzeModules(modules, config) {
2297
2414
  const target = resolveModulePath(file, specifier, config);
2298
2415
  if (!target) return void 0;
2299
2416
  const noteRead = () => {
2300
- const read = readWhile.get(file) ?? /* @__PURE__ */ new Map();
2301
- readWhile.set(file, read);
2417
+ const read2 = readWhile.get(file) ?? /* @__PURE__ */ new Map();
2418
+ readWhile.set(file, read2);
2302
2419
  const stamp = stampOf(target);
2303
- if (stamp !== void 0) read.set(target, stamp);
2304
- for (const [below, belowStamp] of readWhile.get(target) ?? []) read.set(below, belowStamp);
2420
+ if (stamp !== void 0) read2.set(target, stamp);
2421
+ for (const [below, belowStamp] of readWhile.get(target) ?? []) read2.set(below, belowStamp);
2305
2422
  };
2306
2423
  if (inProgress.has(target)) {
2307
2424
  partials++;
@@ -2315,7 +2432,7 @@ function analyzeModules(modules, config) {
2315
2432
  let program2 = byFile.get(target)?.program;
2316
2433
  if (!program2) {
2317
2434
  try {
2318
- program2 = parse(readFileSync(target, "utf8"));
2435
+ program2 = parse(readFileSync2(target, "utf8"));
2319
2436
  } catch {
2320
2437
  return void 0;
2321
2438
  }