@neat.is/core 0.9.5 → 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.
package/dist/neatd.js CHANGED
@@ -2,11 +2,11 @@
2
2
  import {
3
3
  reconcileDaemonRecordSync,
4
4
  startDaemon
5
- } from "./chunk-4SLKQNG7.js";
5
+ } from "./chunk-XYAZOGEX.js";
6
6
  import {
7
7
  listProjects,
8
8
  registryPath
9
- } from "./chunk-DGAI4VOE.js";
9
+ } from "./chunk-XOGTJVUM.js";
10
10
  import {
11
11
  BindAuthorityError,
12
12
  __require
package/dist/server.cjs CHANGED
@@ -11513,27 +11513,72 @@ function walk2(node, visit) {
11513
11513
  if (child) walk2(child, visit);
11514
11514
  }
11515
11515
  }
11516
- function reconstructUrl(node) {
11517
- if (node.type === "string") {
11516
+ function resolveStaticString(node, constMap, depth = 0) {
11517
+ if (!node || depth > 4) return null;
11518
+ if (node.type === "string") return stringText(node);
11519
+ if (node.type === "template_string") {
11520
+ let out = "";
11521
+ let sawSub = false;
11518
11522
  for (let i = 0; i < node.namedChildCount; i++) {
11519
11523
  const child = node.namedChild(i);
11520
- if (child?.type === "string_fragment") return child.text;
11524
+ if (!child) continue;
11525
+ if (child.type === "string_fragment") out += child.text;
11526
+ else if (child.type === "template_substitution") sawSub = true;
11521
11527
  }
11522
- return "";
11528
+ return sawSub ? null : out;
11529
+ }
11530
+ if (node.type === "identifier") return constMap.get(node.text) ?? null;
11531
+ if (node.type === "binary_expression") {
11532
+ const left = resolveStaticString(node.childForFieldName("left"), constMap, depth + 1);
11533
+ if (left !== null) return left;
11534
+ return resolveStaticString(node.childForFieldName("right"), constMap, depth + 1);
11535
+ }
11536
+ if (node.type === "parenthesized_expression") {
11537
+ return resolveStaticString(node.namedChild(0), constMap, depth + 1);
11538
+ }
11539
+ return null;
11540
+ }
11541
+ function collectStaticStringBindings(root) {
11542
+ const map = /* @__PURE__ */ new Map();
11543
+ walk2(root, (node) => {
11544
+ if (node.type !== "variable_declarator") return;
11545
+ const name = node.childForFieldName("name");
11546
+ if (!name || name.type !== "identifier") return;
11547
+ const resolved = resolveStaticString(node.childForFieldName("value"), map);
11548
+ if (resolved !== null) map.set(name.text, resolved);
11549
+ });
11550
+ return map;
11551
+ }
11552
+ function reconstructUrl(node, constMap) {
11553
+ if (node.type === "string") {
11554
+ const s = stringText(node);
11555
+ return s === null ? null : { url: s, approximate: false };
11523
11556
  }
11524
11557
  if (node.type === "template_string") {
11525
11558
  let out = "";
11559
+ let approximate = false;
11560
+ let sawPart = false;
11526
11561
  for (let i = 0; i < node.namedChildCount; i++) {
11527
11562
  const child = node.namedChild(i);
11528
11563
  if (!child) continue;
11529
- if (child.type === "string_fragment") out += child.text;
11530
- else if (child.type === "template_substitution") out += ":param";
11564
+ if (child.type === "string_fragment") {
11565
+ out += child.text;
11566
+ sawPart = true;
11567
+ } else if (child.type === "template_substitution") {
11568
+ sawPart = true;
11569
+ const resolved = resolveStaticString(child.namedChild(0), constMap);
11570
+ if (resolved !== null) out += resolved;
11571
+ else {
11572
+ out += ":param";
11573
+ approximate = true;
11574
+ }
11575
+ }
11531
11576
  }
11532
- if (out.length === 0) {
11577
+ if (!sawPart) {
11533
11578
  const raw = node.text;
11534
- return raw.length >= 2 ? raw.slice(1, -1) : "";
11579
+ return { url: raw.length >= 2 ? raw.slice(1, -1) : "", approximate: false };
11535
11580
  }
11536
- return out;
11581
+ return { url: out, approximate };
11537
11582
  }
11538
11583
  return null;
11539
11584
  }
@@ -11587,23 +11632,57 @@ function matchHost(urlStr, knownHosts) {
11587
11632
  }
11588
11633
  return null;
11589
11634
  }
11635
+ function hostSlotUnresolved(url) {
11636
+ const schemeRel = url.indexOf("//");
11637
+ let authority;
11638
+ if (schemeRel >= 0) {
11639
+ const rest = url.slice(schemeRel + 2);
11640
+ const slash = rest.indexOf("/");
11641
+ authority = slash >= 0 ? rest.slice(0, slash) : rest;
11642
+ } else {
11643
+ const slash = url.indexOf("/");
11644
+ authority = slash >= 0 ? url.slice(0, slash) : url;
11645
+ }
11646
+ return authority.length === 0 || authority.includes(":param");
11647
+ }
11648
+ function pathHasLiteralAnchor(pathTemplate) {
11649
+ const segs = normalizePathTemplate(pathTemplate).split("/").filter((s) => s.length > 0);
11650
+ if (segs.length === 0) return false;
11651
+ return segs.some((s) => s !== ":param");
11652
+ }
11590
11653
  function clientCallSitesFromSource(source, parser, knownHosts) {
11591
11654
  const tree = parseSource5(parser, source);
11592
11655
  const out = [];
11656
+ const constMap = collectStaticStringBindings(tree.rootNode);
11593
11657
  const push = (urlNode, method, callNode) => {
11594
- const urlStr = reconstructUrl(urlNode);
11595
- if (!urlStr) return;
11596
- const host = matchHost(urlStr, knownHosts);
11597
- if (!host) return;
11598
- const p = pathOf(urlStr);
11599
- if (p === null) return;
11658
+ const rec = reconstructUrl(urlNode, constMap);
11659
+ if (!rec) return;
11600
11660
  const line = callNode.startPosition.row + 1;
11661
+ const host = matchHost(rec.url, knownHosts);
11662
+ if (host === null) {
11663
+ if (rec.approximate && hostSlotUnresolved(rec.url)) {
11664
+ out.push({
11665
+ host: null,
11666
+ method,
11667
+ pathTemplate: "",
11668
+ line,
11669
+ snippet: snippet(source, line),
11670
+ approximate: true,
11671
+ reason: "base URL interpolation could not be resolved statically"
11672
+ });
11673
+ }
11674
+ return;
11675
+ }
11676
+ const p = pathOf(rec.url);
11677
+ if (p === null) return;
11601
11678
  out.push({
11602
11679
  host,
11603
11680
  method,
11604
11681
  pathTemplate: p,
11605
11682
  line,
11606
- snippet: snippet(source, line)
11683
+ snippet: snippet(source, line),
11684
+ approximate: rec.approximate,
11685
+ reason: rec.approximate ? "path segment interpolation could not be resolved statically" : void 0
11607
11686
  });
11608
11687
  };
11609
11688
  walk2(tree.rootNode, (node) => {
@@ -11699,6 +11778,35 @@ async function addRouteCallEdges(graph, services) {
11699
11778
  if (sites.length === 0) continue;
11700
11779
  const relFile = toPosix(import_node_path40.default.relative(service.dir, file.path));
11701
11780
  for (const site of sites) {
11781
+ if (site.host === null) {
11782
+ const dedupKey2 = `${relFile}|unresolved-host`;
11783
+ if (seen.has(dedupKey2)) continue;
11784
+ seen.add(dedupKey2);
11785
+ const { fileNodeId: fileNodeId2, nodesAdded: n2, edgesAdded: e2 } = ensureFileNode(
11786
+ graph,
11787
+ service.pkg.name,
11788
+ service.node.id,
11789
+ relFile
11790
+ );
11791
+ nodesAdded += n2;
11792
+ edgesAdded += e2;
11793
+ noteExtractedDropped({
11794
+ source: fileNodeId2,
11795
+ target: "route:unresolved",
11796
+ type: import_types28.EdgeType.CALLS,
11797
+ confidence: (0, import_types28.confidenceForExtracted)("reconstructed-approximate"),
11798
+ confidenceKind: "reconstructed-approximate",
11799
+ evidence: {
11800
+ file: relFile,
11801
+ line: site.line,
11802
+ snippet: site.snippet,
11803
+ method: site.method,
11804
+ approximate: true,
11805
+ reason: site.reason
11806
+ }
11807
+ });
11808
+ continue;
11809
+ }
11702
11810
  const serverServiceId = hostToNodeId.get(site.host);
11703
11811
  if (!serverServiceId || serverServiceId === service.node.id) continue;
11704
11812
  const entries = routeIndex.get(serverServiceId);
@@ -11717,13 +11825,16 @@ async function addRouteCallEdges(graph, services) {
11717
11825
  );
11718
11826
  nodesAdded += n;
11719
11827
  edgesAdded += e;
11720
- const confidence = (0, import_types28.confidenceForExtracted)("verified-call-site");
11828
+ const anchored = pathHasLiteralAnchor(site.pathTemplate);
11829
+ const confidenceKind = site.approximate && !anchored ? "reconstructed-approximate" : "verified-call-site";
11830
+ const confidence = (0, import_types28.confidenceForExtracted)(confidenceKind);
11721
11831
  const ev = {
11722
11832
  file: relFile,
11723
11833
  line: site.line,
11724
11834
  snippet: site.snippet,
11725
11835
  method: site.method ?? match.method,
11726
- pathTemplate: site.pathTemplate
11836
+ pathTemplate: site.pathTemplate,
11837
+ ...confidenceKind === "reconstructed-approximate" ? { approximate: true, reason: site.reason } : {}
11727
11838
  };
11728
11839
  if (!(0, import_types28.passesExtractedFloor)(confidence)) {
11729
11840
  noteExtractedDropped({
@@ -11731,7 +11842,7 @@ async function addRouteCallEdges(graph, services) {
11731
11842
  target: match.routeNodeId,
11732
11843
  type: import_types28.EdgeType.CALLS,
11733
11844
  confidence,
11734
- confidenceKind: "verified-call-site",
11845
+ confidenceKind,
11735
11846
  evidence: ev
11736
11847
  });
11737
11848
  continue;