@neat.is/core 0.9.6-dev.20260826 → 0.9.6

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.
@@ -20,7 +20,7 @@ import {
20
20
  startStalenessLoop,
21
21
  touchLastSeen,
22
22
  writeAtomically
23
- } from "./chunk-DGAI4VOE.js";
23
+ } from "./chunk-XOGTJVUM.js";
24
24
  import {
25
25
  assertBindAuthority,
26
26
  buildOtelReceiver,
@@ -891,4 +891,4 @@ export {
891
891
  resolveHost,
892
892
  startDaemon
893
893
  };
894
- //# sourceMappingURL=chunk-4SLKQNG7.js.map
894
+ //# sourceMappingURL=chunk-XYAZOGEX.js.map
package/dist/cli.cjs CHANGED
@@ -10782,27 +10782,72 @@ function walk2(node, visit) {
10782
10782
  if (child) walk2(child, visit);
10783
10783
  }
10784
10784
  }
10785
- function reconstructUrl(node) {
10786
- if (node.type === "string") {
10785
+ function resolveStaticString(node, constMap, depth = 0) {
10786
+ if (!node || depth > 4) return null;
10787
+ if (node.type === "string") return stringText(node);
10788
+ if (node.type === "template_string") {
10789
+ let out = "";
10790
+ let sawSub = false;
10787
10791
  for (let i = 0; i < node.namedChildCount; i++) {
10788
10792
  const child = node.namedChild(i);
10789
- if (child?.type === "string_fragment") return child.text;
10793
+ if (!child) continue;
10794
+ if (child.type === "string_fragment") out += child.text;
10795
+ else if (child.type === "template_substitution") sawSub = true;
10790
10796
  }
10791
- return "";
10797
+ return sawSub ? null : out;
10798
+ }
10799
+ if (node.type === "identifier") return constMap.get(node.text) ?? null;
10800
+ if (node.type === "binary_expression") {
10801
+ const left = resolveStaticString(node.childForFieldName("left"), constMap, depth + 1);
10802
+ if (left !== null) return left;
10803
+ return resolveStaticString(node.childForFieldName("right"), constMap, depth + 1);
10804
+ }
10805
+ if (node.type === "parenthesized_expression") {
10806
+ return resolveStaticString(node.namedChild(0), constMap, depth + 1);
10807
+ }
10808
+ return null;
10809
+ }
10810
+ function collectStaticStringBindings(root) {
10811
+ const map = /* @__PURE__ */ new Map();
10812
+ walk2(root, (node) => {
10813
+ if (node.type !== "variable_declarator") return;
10814
+ const name = node.childForFieldName("name");
10815
+ if (!name || name.type !== "identifier") return;
10816
+ const resolved = resolveStaticString(node.childForFieldName("value"), map);
10817
+ if (resolved !== null) map.set(name.text, resolved);
10818
+ });
10819
+ return map;
10820
+ }
10821
+ function reconstructUrl(node, constMap) {
10822
+ if (node.type === "string") {
10823
+ const s = stringText(node);
10824
+ return s === null ? null : { url: s, approximate: false };
10792
10825
  }
10793
10826
  if (node.type === "template_string") {
10794
10827
  let out = "";
10828
+ let approximate = false;
10829
+ let sawPart = false;
10795
10830
  for (let i = 0; i < node.namedChildCount; i++) {
10796
10831
  const child = node.namedChild(i);
10797
10832
  if (!child) continue;
10798
- if (child.type === "string_fragment") out += child.text;
10799
- else if (child.type === "template_substitution") out += ":param";
10833
+ if (child.type === "string_fragment") {
10834
+ out += child.text;
10835
+ sawPart = true;
10836
+ } else if (child.type === "template_substitution") {
10837
+ sawPart = true;
10838
+ const resolved = resolveStaticString(child.namedChild(0), constMap);
10839
+ if (resolved !== null) out += resolved;
10840
+ else {
10841
+ out += ":param";
10842
+ approximate = true;
10843
+ }
10844
+ }
10800
10845
  }
10801
- if (out.length === 0) {
10846
+ if (!sawPart) {
10802
10847
  const raw = node.text;
10803
- return raw.length >= 2 ? raw.slice(1, -1) : "";
10848
+ return { url: raw.length >= 2 ? raw.slice(1, -1) : "", approximate: false };
10804
10849
  }
10805
- return out;
10850
+ return { url: out, approximate };
10806
10851
  }
10807
10852
  return null;
10808
10853
  }
@@ -10856,23 +10901,57 @@ function matchHost(urlStr, knownHosts) {
10856
10901
  }
10857
10902
  return null;
10858
10903
  }
10904
+ function hostSlotUnresolved(url) {
10905
+ const schemeRel = url.indexOf("//");
10906
+ let authority;
10907
+ if (schemeRel >= 0) {
10908
+ const rest = url.slice(schemeRel + 2);
10909
+ const slash = rest.indexOf("/");
10910
+ authority = slash >= 0 ? rest.slice(0, slash) : rest;
10911
+ } else {
10912
+ const slash = url.indexOf("/");
10913
+ authority = slash >= 0 ? url.slice(0, slash) : url;
10914
+ }
10915
+ return authority.length === 0 || authority.includes(":param");
10916
+ }
10917
+ function pathHasLiteralAnchor(pathTemplate) {
10918
+ const segs = normalizePathTemplate(pathTemplate).split("/").filter((s) => s.length > 0);
10919
+ if (segs.length === 0) return false;
10920
+ return segs.some((s) => s !== ":param");
10921
+ }
10859
10922
  function clientCallSitesFromSource(source, parser, knownHosts) {
10860
10923
  const tree = parseSource5(parser, source);
10861
10924
  const out = [];
10925
+ const constMap = collectStaticStringBindings(tree.rootNode);
10862
10926
  const push = (urlNode, method, callNode) => {
10863
- const urlStr = reconstructUrl(urlNode);
10864
- if (!urlStr) return;
10865
- const host = matchHost(urlStr, knownHosts);
10866
- if (!host) return;
10867
- const p = pathOf(urlStr);
10868
- if (p === null) return;
10927
+ const rec = reconstructUrl(urlNode, constMap);
10928
+ if (!rec) return;
10869
10929
  const line = callNode.startPosition.row + 1;
10930
+ const host = matchHost(rec.url, knownHosts);
10931
+ if (host === null) {
10932
+ if (rec.approximate && hostSlotUnresolved(rec.url)) {
10933
+ out.push({
10934
+ host: null,
10935
+ method,
10936
+ pathTemplate: "",
10937
+ line,
10938
+ snippet: snippet(source, line),
10939
+ approximate: true,
10940
+ reason: "base URL interpolation could not be resolved statically"
10941
+ });
10942
+ }
10943
+ return;
10944
+ }
10945
+ const p = pathOf(rec.url);
10946
+ if (p === null) return;
10870
10947
  out.push({
10871
10948
  host,
10872
10949
  method,
10873
10950
  pathTemplate: p,
10874
10951
  line,
10875
- snippet: snippet(source, line)
10952
+ snippet: snippet(source, line),
10953
+ approximate: rec.approximate,
10954
+ reason: rec.approximate ? "path segment interpolation could not be resolved statically" : void 0
10876
10955
  });
10877
10956
  };
10878
10957
  walk2(tree.rootNode, (node) => {
@@ -10968,6 +11047,35 @@ async function addRouteCallEdges(graph, services) {
10968
11047
  if (sites.length === 0) continue;
10969
11048
  const relFile = toPosix(import_node_path39.default.relative(service.dir, file.path));
10970
11049
  for (const site of sites) {
11050
+ if (site.host === null) {
11051
+ const dedupKey2 = `${relFile}|unresolved-host`;
11052
+ if (seen.has(dedupKey2)) continue;
11053
+ seen.add(dedupKey2);
11054
+ const { fileNodeId: fileNodeId2, nodesAdded: n2, edgesAdded: e2 } = ensureFileNode(
11055
+ graph,
11056
+ service.pkg.name,
11057
+ service.node.id,
11058
+ relFile
11059
+ );
11060
+ nodesAdded += n2;
11061
+ edgesAdded += e2;
11062
+ noteExtractedDropped({
11063
+ source: fileNodeId2,
11064
+ target: "route:unresolved",
11065
+ type: import_types27.EdgeType.CALLS,
11066
+ confidence: (0, import_types27.confidenceForExtracted)("reconstructed-approximate"),
11067
+ confidenceKind: "reconstructed-approximate",
11068
+ evidence: {
11069
+ file: relFile,
11070
+ line: site.line,
11071
+ snippet: site.snippet,
11072
+ method: site.method,
11073
+ approximate: true,
11074
+ reason: site.reason
11075
+ }
11076
+ });
11077
+ continue;
11078
+ }
10971
11079
  const serverServiceId = hostToNodeId.get(site.host);
10972
11080
  if (!serverServiceId || serverServiceId === service.node.id) continue;
10973
11081
  const entries = routeIndex.get(serverServiceId);
@@ -10986,13 +11094,16 @@ async function addRouteCallEdges(graph, services) {
10986
11094
  );
10987
11095
  nodesAdded += n;
10988
11096
  edgesAdded += e;
10989
- const confidence = (0, import_types27.confidenceForExtracted)("verified-call-site");
11097
+ const anchored = pathHasLiteralAnchor(site.pathTemplate);
11098
+ const confidenceKind = site.approximate && !anchored ? "reconstructed-approximate" : "verified-call-site";
11099
+ const confidence = (0, import_types27.confidenceForExtracted)(confidenceKind);
10990
11100
  const ev = {
10991
11101
  file: relFile,
10992
11102
  line: site.line,
10993
11103
  snippet: site.snippet,
10994
11104
  method: site.method ?? match.method,
10995
- pathTemplate: site.pathTemplate
11105
+ pathTemplate: site.pathTemplate,
11106
+ ...confidenceKind === "reconstructed-approximate" ? { approximate: true, reason: site.reason } : {}
10996
11107
  };
10997
11108
  if (!(0, import_types27.passesExtractedFloor)(confidence)) {
10998
11109
  noteExtractedDropped({
@@ -11000,7 +11111,7 @@ async function addRouteCallEdges(graph, services) {
11000
11111
  target: match.routeNodeId,
11001
11112
  type: import_types27.EdgeType.CALLS,
11002
11113
  confidence,
11003
- confidenceKind: "verified-call-site",
11114
+ confidenceKind,
11004
11115
  evidence: ev
11005
11116
  });
11006
11117
  continue;