@nudojs/core 1.5.0 → 1.6.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.
@@ -25,6 +25,7 @@ import {
25
25
  joinAbs,
26
26
  le,
27
27
  lit,
28
+ litKeyString,
28
29
  litValue,
29
30
  locateContractParam,
30
31
  lt,
@@ -45,7 +46,7 @@ import {
45
46
  withEvalBudgetOverride,
46
47
  withExecPhi,
47
48
  withFnBudgetOverride
48
- } from "./chunk-W2MP6REI.js";
49
+ } from "./chunk-LZJC7X5J.js";
49
50
 
50
51
  // src/algebra/directive-scan.ts
51
52
  function cleanDirectiveLine(raw, kind) {
@@ -432,12 +433,19 @@ function parseNudoImportPayload(payload) {
432
433
  if (s === "") return void 0;
433
434
  const named = s.match(/^\{([^}]+)\}\s*from\s*["']([^"']+)["']$/);
434
435
  if (named) {
435
- const names = named[1].split("\n").map((line) => line.replace(/^\s*\/\/\/?\s?/, "").trim()).join("\n").split(",").map((x) => x.trim()).filter(Boolean).map((x) => x.split(/\s+as\s+/).pop().trim());
436
- return { names, spec: named[2] };
436
+ const names = [];
437
+ const importedOfLocal = {};
438
+ for (const x of named[1].split("\n").map((line) => line.replace(/^\s*\/\/\/?\s?/, "").trim()).join("\n").split(",").map((x2) => x2.trim()).filter(Boolean)) {
439
+ const seg = x.split(/\s+as\s+/);
440
+ const local = seg[seg.length - 1].trim();
441
+ names.push(local);
442
+ if (seg.length > 1) importedOfLocal[local] = seg[0].trim();
443
+ }
444
+ return { names, importedOfLocal, spec: named[2] };
437
445
  }
438
446
  const ns = s.match(/^\*\s+as\s+(\w+)\s+from\s*["']([^"']+)["']$/);
439
447
  if (ns) {
440
- return { names: [`*${ns[1]}`], spec: ns[2] };
448
+ return { names: [`*${ns[1]}`], importedOfLocal: {}, spec: ns[2] };
441
449
  }
442
450
  if (/^[\w$]+\s+from\b/.test(s) || /^[\w$]+\s*,/.test(s)) return "malformed-default";
443
451
  return "malformed";
@@ -448,7 +456,7 @@ function fileDirectiveVisibleText(source) {
448
456
  }
449
457
  function extractFileEnvNames(source) {
450
458
  const text = fileDirectiveVisibleText(source);
451
- const re = new RegExp(`${LINE_COMMENT_PREFIX}\\s*@nudo:env\\s+([^\\n*]+)`, "g");
459
+ const re = new RegExp(`${LINE_COMMENT_PREFIX}[ \\t]*@nudo:env[ \\t]+([^\\n*]+)`, "g");
452
460
  const out = [];
453
461
  let m;
454
462
  while (m = re.exec(text)) {
@@ -459,7 +467,7 @@ function extractFileEnvNames(source) {
459
467
  function extractMockModuleRecords(source) {
460
468
  const text = fileDirectiveVisibleText(source);
461
469
  const re = new RegExp(
462
- `${LINE_COMMENT_PREFIX}\\s*@nudo:mock-module\\s+([^\\n]+)`,
470
+ `${LINE_COMMENT_PREFIX}[ \\t]*@nudo:mock-module[ \\t]+([^\\n]+)`,
463
471
  "g"
464
472
  );
465
473
  const out = [];
@@ -552,7 +560,7 @@ function extractBalancedParens(text, startIdx) {
552
560
  }
553
561
  return null;
554
562
  }
555
- var CASE_NAME_REGEX = /(?:^|\n)[ \t]*(?:\*[ \t]*|\/\/\/?\s*)?@nudo:case\s+"([^"]+)"\s*\(/g;
563
+ var CASE_NAME_REGEX = /(?:^|\n)[ \t]*(?:\*[ \t]*|\/[ \t]*)?@nudo:case[ \t]+"([^"\n]+)"[ \t]*\(/g;
556
564
  function extractCaseExpectedExpr(text, afterParen) {
557
565
  const lines = text.slice(afterParen).split("\n");
558
566
  for (let i = 0; i < lines.length; i++) {
@@ -1248,11 +1256,7 @@ function throwConstraintToKinds(c) {
1248
1256
  }
1249
1257
 
1250
1258
  // src/algebra/refine.ts
1251
- function extractNudoImports(source) {
1252
- const out = [];
1253
- for (const rec of extractNudoImportRecords(source)) {
1254
- out.push({ names: rec.names, spec: rec.spec });
1255
- }
1259
+ function diagnoseMalformedNudoImports(source) {
1256
1260
  for (const bad of scanMalformedNudoImports(source)) {
1257
1261
  if (bad === "malformed-default") {
1258
1262
  collectDiag({
@@ -1266,7 +1270,13 @@ function extractNudoImports(source) {
1266
1270
  });
1267
1271
  }
1268
1272
  }
1269
- return out;
1273
+ }
1274
+ function extractNudoImports(source) {
1275
+ diagnoseMalformedNudoImports(source);
1276
+ return extractNudoImportRecords(source).map((rec) => ({
1277
+ names: rec.names,
1278
+ spec: rec.spec
1279
+ }));
1270
1280
  }
1271
1281
  var refineDiagCollector = null;
1272
1282
  var refineDiagSeq = 0;
@@ -1376,6 +1386,21 @@ function rewriteSidecarSource(src, fromFile) {
1376
1386
  cuts.push({ start: stmt.start, end: decl.start, text: "" });
1377
1387
  continue;
1378
1388
  }
1389
+ if (!stmt.source) {
1390
+ let aliasPairs = false;
1391
+ for (const spec of stmt.specifiers) {
1392
+ if (spec.type !== "ExportSpecifier") continue;
1393
+ if (spec.local.type !== "Identifier") continue;
1394
+ const key = spec.exported.type === "Identifier" ? spec.exported.name : spec.exported.value;
1395
+ if (key === void 0) continue;
1396
+ exportPairs.push({ key, expr: spec.local.name });
1397
+ aliasPairs = true;
1398
+ }
1399
+ if (aliasPairs) {
1400
+ cuts.push({ start: stmt.start, end: stmt.end, text: "" });
1401
+ continue;
1402
+ }
1403
+ }
1379
1404
  badExport("'export { \u2026 }' (list / re-export)");
1380
1405
  if (stmt.start != null && stmt.end != null) {
1381
1406
  cuts.push({ start: stmt.start, end: stmt.end, text: "" });
@@ -1540,14 +1565,15 @@ function execSidecar(src, opts, chain, preloaded) {
1540
1565
  });
1541
1566
  prologue.push(`var ${n.local} = __nudoInjects;`);
1542
1567
  } else if (n.imported !== void 0) {
1543
- if (!(n.imported in sidecarInjects)) {
1568
+ const hasOwnInject = Object.hasOwn(sidecarInjects, n.imported);
1569
+ if (!hasOwnInject) {
1544
1570
  collectDiag({
1545
1571
  code: "nudo:interface-load",
1546
1572
  message: `sidecar import '{ ${n.imported} }' from '${imp.spec}' is not an injected builder`,
1547
1573
  file: fromFile
1548
1574
  });
1549
- }
1550
- if (n.local !== n.imported || !(n.imported in sidecarInjects)) {
1575
+ prologue.push(`var ${n.local} = undefined;`);
1576
+ } else if (n.local !== n.imported) {
1551
1577
  prologue.push(`var ${n.local} = __nudoInjects[${JSON.stringify(n.imported)}];`);
1552
1578
  }
1553
1579
  } else {
@@ -1616,21 +1642,23 @@ function execSidecar(src, opts, chain, preloaded) {
1616
1642
  if (n.ns) {
1617
1643
  deps[n.local] = depExports;
1618
1644
  } else if (n.imported !== void 0) {
1619
- if (!(n.imported in depExports)) {
1645
+ if (Object.hasOwn(depExports, n.imported)) {
1646
+ deps[n.local] = depExports[n.imported];
1647
+ } else {
1620
1648
  collectDiag({
1621
1649
  code: "nudo:interface-load",
1622
1650
  message: `sidecar '${imp.spec}' has no export '${n.imported}'`,
1623
1651
  file: fromFile
1624
1652
  });
1653
+ deps[n.local] = void 0;
1625
1654
  }
1626
- deps[n.local] = depExports[n.imported];
1627
1655
  } else {
1628
1656
  collectDiag({
1629
1657
  code: "nudo:interface-load",
1630
1658
  message: `sidecar default import '${n.local}' from '${imp.spec}' has no default export (sidecars export named constraints only)`,
1631
1659
  file: fromFile
1632
1660
  });
1633
- deps[n.local] = depExports.default;
1661
+ deps[n.local] = Object.hasOwn(depExports, "default") ? depExports.default : void 0;
1634
1662
  }
1635
1663
  }
1636
1664
  }
@@ -1738,7 +1766,8 @@ function resetNudoModuleExecCache() {
1738
1766
  }
1739
1767
  function collectConstraints(source, opts) {
1740
1768
  const map = /* @__PURE__ */ new Map();
1741
- const imports = extractNudoImports(source);
1769
+ diagnoseMalformedNudoImports(source);
1770
+ const imports = extractNudoImportRecords(source);
1742
1771
  for (const imp of imports) {
1743
1772
  if (!opts.loadModule || !opts.fromFile) {
1744
1773
  collectDiag({
@@ -1793,19 +1822,20 @@ function collectConstraints(source, opts) {
1793
1822
  }
1794
1823
  continue;
1795
1824
  }
1796
- const v2 = exports[name];
1825
+ const imported = imp.importedOfLocal[name] ?? name;
1826
+ const v2 = Object.hasOwn(exports, imported) ? exports[imported] : void 0;
1797
1827
  if (isNudoConstraint(v2)) {
1798
1828
  map.set(name, v2);
1799
1829
  } else if (v2 === void 0) {
1800
1830
  collectDiag({
1801
1831
  code: "nudo:interface-load",
1802
- message: `sidecar '${imp.spec}' has no export '${name}'`,
1832
+ message: `sidecar '${imp.spec}' has no export '${imported}'`,
1803
1833
  file: opts.fromFile
1804
1834
  });
1805
1835
  } else {
1806
1836
  collectDiag({
1807
1837
  code: "nudo:interface-load",
1808
- message: `sidecar '${imp.spec}' export '${name}' is not a Nudo constraint`,
1838
+ message: `sidecar '${imp.spec}' export '${imported}' is not a Nudo constraint`,
1809
1839
  file: opts.fromFile
1810
1840
  });
1811
1841
  }
@@ -1836,7 +1866,13 @@ function extractRefinesFromSource(source, fnName, opts = {}) {
1836
1866
  const [, param, cName] = m;
1837
1867
  if (param === "return") continue;
1838
1868
  const c = constraints.get(cName);
1839
- if (!c) continue;
1869
+ if (!c) {
1870
+ collectDiag({
1871
+ code: "nudo:contract-syntax",
1872
+ message: `Unknown constraint name '${cName}' in @nudo:contract (expected a name bound by @nudo:import)`
1873
+ });
1874
+ continue;
1875
+ }
1840
1876
  out.push({
1841
1877
  param,
1842
1878
  pred: instantiateConstraint(c, param),
@@ -1873,7 +1909,13 @@ function extractRefineReturnFromSource(source, fnName, opts = {}) {
1873
1909
  }
1874
1910
  const cName = m[1];
1875
1911
  const c = constraints.get(cName);
1876
- if (!c) continue;
1912
+ if (!c) {
1913
+ collectDiag({
1914
+ code: "nudo:contract-syntax",
1915
+ message: `Unknown constraint name '${cName}' in @nudo:contract return (expected a name bound by @nudo:import)`
1916
+ });
1917
+ continue;
1918
+ }
1877
1919
  return { name: cName, constraint: c };
1878
1920
  }
1879
1921
  }
@@ -1950,7 +1992,9 @@ function localNamedExports(source) {
1950
1992
  const identName = (n) => {
1951
1993
  if (!n) return void 0;
1952
1994
  if (n.type === "Identifier" && typeof n.name === "string") return n.name;
1953
- if (n.type === "Literal" && typeof n.value === "string") return n.value;
1995
+ if ((n.type === "StringLiteral" || n.type === "Literal") && typeof n.value === "string") {
1996
+ return n.value;
1997
+ }
1954
1998
  return void 0;
1955
1999
  };
1956
2000
  const localClasses = /* @__PURE__ */ new Map();
@@ -2098,6 +2142,25 @@ function localNamedExports(source) {
2098
2142
  }
2099
2143
  return out;
2100
2144
  }
2145
+ function exportedNameOfLocal(source, localName) {
2146
+ let ast;
2147
+ try {
2148
+ ast = parseSource(source, { errorRecovery: true });
2149
+ } catch {
2150
+ return void 0;
2151
+ }
2152
+ for (const stmt of ast.program.body) {
2153
+ if (stmt.type !== "ExportNamedDeclaration" || stmt.source) continue;
2154
+ for (const spec of stmt.specifiers) {
2155
+ if (spec.type !== "ExportSpecifier") continue;
2156
+ if (spec.local.type !== "Identifier" || spec.local.name !== localName) continue;
2157
+ const name = spec.exported.type === "Identifier" ? spec.exported.name : spec.exported.value;
2158
+ if (name === void 0 || name === localName || name === "default") continue;
2159
+ return name;
2160
+ }
2161
+ }
2162
+ return void 0;
2163
+ }
2101
2164
  function generatedExportNames(sidecarSrc) {
2102
2165
  const out = /* @__PURE__ */ new Set();
2103
2166
  let ast;
@@ -2111,8 +2174,18 @@ function generatedExportNames(sidecarSrc) {
2111
2174
  const stmt = stmts[i];
2112
2175
  if (stmt.type !== "ExportNamedDeclaration") continue;
2113
2176
  if (stmt.source) continue;
2177
+ if (stmt.start == null) continue;
2114
2178
  const d = stmt.declaration;
2115
- if (!d || stmt.start == null) continue;
2179
+ if (!d) {
2180
+ if (regionHasGeneratedMarker(stmts, i, sidecarSrc)) {
2181
+ for (const spec of stmt.specifiers) {
2182
+ if (spec.type !== "ExportSpecifier") continue;
2183
+ const name = spec.exported.type === "Identifier" ? spec.exported.name : spec.exported.value;
2184
+ if (name !== void 0) out.add(name);
2185
+ }
2186
+ }
2187
+ continue;
2188
+ }
2116
2189
  const names = [];
2117
2190
  if (d.type === "VariableDeclaration") {
2118
2191
  for (const decl of d.declarations) {
@@ -2183,6 +2256,8 @@ function sidecarMayBind(sidecarNames, fnName, source) {
2183
2256
  if (!sidecarNames) return true;
2184
2257
  if (sidecarNames.size === 0) return true;
2185
2258
  if (sidecarNames.has(fnName)) return true;
2259
+ const aliasExport = exportedNameOfLocal(source, fnName);
2260
+ if (aliasExport !== void 0 && sidecarNames.has(aliasExport)) return true;
2186
2261
  if (sidecarNames.has("default") && isDefaultExportLocal(source, fnName)) return true;
2187
2262
  if (fnName.includes(".")) {
2188
2263
  const [cls, method] = fnName.split(".", 2);
@@ -2253,20 +2328,26 @@ function loadSidecarBinding(source, fnName, opts) {
2253
2328
  }
2254
2329
  return { ok: false };
2255
2330
  }
2256
- let binding = exports[fnName];
2331
+ let binding = Object.hasOwn(exports, fnName) ? exports[fnName] : void 0;
2332
+ if (binding === void 0) {
2333
+ const aliasExport2 = exportedNameOfLocal(source, fnName);
2334
+ if (aliasExport2 !== void 0 && Object.hasOwn(exports, aliasExport2)) {
2335
+ binding = exports[aliasExport2];
2336
+ }
2337
+ }
2257
2338
  if (binding === void 0 && exports.default !== void 0 && isDefaultExportLocal(source, fnName)) {
2258
2339
  binding = exports.default;
2259
2340
  }
2260
2341
  if (binding === void 0 && fnName.includes(".")) {
2261
2342
  const [cls, method] = fnName.split(".", 2);
2262
- binding = exports[`${cls}_${method}`];
2343
+ binding = Object.hasOwn(exports, `${cls}_${method}`) ? exports[`${cls}_${method}`] : void 0;
2263
2344
  if (binding === void 0) {
2264
- const bag = exports[cls];
2345
+ const bag = Object.hasOwn(exports, cls) ? exports[cls] : void 0;
2265
2346
  if (bag && typeof bag === "object" && !isNudoConstraint(bag)) {
2266
- binding = bag[method];
2347
+ binding = Object.hasOwn(bag, method) ? bag[method] : void 0;
2267
2348
  }
2268
2349
  }
2269
- if (binding === void 0 && method !== void 0 && exports[method] !== void 0) {
2350
+ if (binding === void 0 && method !== void 0 && Object.hasOwn(exports, method)) {
2270
2351
  collectDiag2({
2271
2352
  code: "nudo:interface-load",
2272
2353
  message: `sidecar key '${method}' does not bind '${fnName}' \u2014 use '${cls}.${method}', '${cls}_${method}', or nested { ${cls}: { ${method}: \u2026 } }`,
@@ -2292,7 +2373,8 @@ function loadSidecarBinding(source, fnName, opts) {
2292
2373
  return { ok: false };
2293
2374
  }
2294
2375
  const generatedNames = generatedExportNames(sidecarSrc);
2295
- const isGenerated = generatedNames.has(fnName) || (fnName.includes(".") ? (() => {
2376
+ const aliasExport = exportedNameOfLocal(source, fnName);
2377
+ const isGenerated = generatedNames.has(fnName) || (aliasExport !== void 0 ? generatedNames.has(aliasExport) : false) || (fnName.includes(".") ? (() => {
2296
2378
  const [cls, method] = fnName.split(".", 2);
2297
2379
  return generatedNames.has(`${cls}_${method}`) || generatedNames.has(cls);
2298
2380
  })() : false);
@@ -2943,7 +3025,7 @@ function loadModuleDepsFingerprint(source, loadModule, fromFile) {
2943
3025
  function termKey(t, rename) {
2944
3026
  switch (t.op) {
2945
3027
  case "lit":
2946
- return `L:${typeof t.value}:${String(t.value)}`;
3028
+ return `L:${typeof t.value}:${litKeyString(t.value)}`;
2947
3029
  case "var":
2948
3030
  return `V:${rename?.get(t.id) ?? t.id}`;
2949
3031
  case "app":
@@ -3050,6 +3132,9 @@ function collectPredVars(p, acc) {
3050
3132
  case "typeof":
3051
3133
  collectTermVars(p.t, acc);
3052
3134
  return;
3135
+ case "assumeFinite":
3136
+ collectTermVars(p.t, acc);
3137
+ return;
3053
3138
  }
3054
3139
  }
3055
3140
  function collectAbsVars(a, acc, seen) {
@@ -5789,6 +5874,7 @@ export {
5789
5874
  takeInterfaceDiags,
5790
5875
  takeInterfaceDiagsSince,
5791
5876
  localNamedExports,
5877
+ exportedNameOfLocal,
5792
5878
  generatedExportNames,
5793
5879
  resetSidecarLoadFailureCache,
5794
5880
  effectiveInterface,