@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.
@@ -10006,27 +10006,72 @@ function walk2(node, visit) {
10006
10006
  if (child) walk2(child, visit);
10007
10007
  }
10008
10008
  }
10009
- function reconstructUrl(node) {
10010
- if (node.type === "string") {
10009
+ function resolveStaticString(node, constMap, depth = 0) {
10010
+ if (!node || depth > 4) return null;
10011
+ if (node.type === "string") return stringText(node);
10012
+ if (node.type === "template_string") {
10013
+ let out = "";
10014
+ let sawSub = false;
10011
10015
  for (let i = 0; i < node.namedChildCount; i++) {
10012
10016
  const child = node.namedChild(i);
10013
- if (child?.type === "string_fragment") return child.text;
10017
+ if (!child) continue;
10018
+ if (child.type === "string_fragment") out += child.text;
10019
+ else if (child.type === "template_substitution") sawSub = true;
10014
10020
  }
10015
- return "";
10021
+ return sawSub ? null : out;
10022
+ }
10023
+ if (node.type === "identifier") return constMap.get(node.text) ?? null;
10024
+ if (node.type === "binary_expression") {
10025
+ const left = resolveStaticString(node.childForFieldName("left"), constMap, depth + 1);
10026
+ if (left !== null) return left;
10027
+ return resolveStaticString(node.childForFieldName("right"), constMap, depth + 1);
10028
+ }
10029
+ if (node.type === "parenthesized_expression") {
10030
+ return resolveStaticString(node.namedChild(0), constMap, depth + 1);
10031
+ }
10032
+ return null;
10033
+ }
10034
+ function collectStaticStringBindings(root) {
10035
+ const map = /* @__PURE__ */ new Map();
10036
+ walk2(root, (node) => {
10037
+ if (node.type !== "variable_declarator") return;
10038
+ const name = node.childForFieldName("name");
10039
+ if (!name || name.type !== "identifier") return;
10040
+ const resolved = resolveStaticString(node.childForFieldName("value"), map);
10041
+ if (resolved !== null) map.set(name.text, resolved);
10042
+ });
10043
+ return map;
10044
+ }
10045
+ function reconstructUrl(node, constMap) {
10046
+ if (node.type === "string") {
10047
+ const s = stringText(node);
10048
+ return s === null ? null : { url: s, approximate: false };
10016
10049
  }
10017
10050
  if (node.type === "template_string") {
10018
10051
  let out = "";
10052
+ let approximate = false;
10053
+ let sawPart = false;
10019
10054
  for (let i = 0; i < node.namedChildCount; i++) {
10020
10055
  const child = node.namedChild(i);
10021
10056
  if (!child) continue;
10022
- if (child.type === "string_fragment") out += child.text;
10023
- else if (child.type === "template_substitution") out += ":param";
10057
+ if (child.type === "string_fragment") {
10058
+ out += child.text;
10059
+ sawPart = true;
10060
+ } else if (child.type === "template_substitution") {
10061
+ sawPart = true;
10062
+ const resolved = resolveStaticString(child.namedChild(0), constMap);
10063
+ if (resolved !== null) out += resolved;
10064
+ else {
10065
+ out += ":param";
10066
+ approximate = true;
10067
+ }
10068
+ }
10024
10069
  }
10025
- if (out.length === 0) {
10070
+ if (!sawPart) {
10026
10071
  const raw = node.text;
10027
- return raw.length >= 2 ? raw.slice(1, -1) : "";
10072
+ return { url: raw.length >= 2 ? raw.slice(1, -1) : "", approximate: false };
10028
10073
  }
10029
- return out;
10074
+ return { url: out, approximate };
10030
10075
  }
10031
10076
  return null;
10032
10077
  }
@@ -10080,23 +10125,57 @@ function matchHost(urlStr, knownHosts) {
10080
10125
  }
10081
10126
  return null;
10082
10127
  }
10128
+ function hostSlotUnresolved(url) {
10129
+ const schemeRel = url.indexOf("//");
10130
+ let authority;
10131
+ if (schemeRel >= 0) {
10132
+ const rest = url.slice(schemeRel + 2);
10133
+ const slash = rest.indexOf("/");
10134
+ authority = slash >= 0 ? rest.slice(0, slash) : rest;
10135
+ } else {
10136
+ const slash = url.indexOf("/");
10137
+ authority = slash >= 0 ? url.slice(0, slash) : url;
10138
+ }
10139
+ return authority.length === 0 || authority.includes(":param");
10140
+ }
10141
+ function pathHasLiteralAnchor(pathTemplate) {
10142
+ const segs = normalizePathTemplate(pathTemplate).split("/").filter((s) => s.length > 0);
10143
+ if (segs.length === 0) return false;
10144
+ return segs.some((s) => s !== ":param");
10145
+ }
10083
10146
  function clientCallSitesFromSource(source, parser, knownHosts) {
10084
10147
  const tree = parseSource5(parser, source);
10085
10148
  const out = [];
10149
+ const constMap = collectStaticStringBindings(tree.rootNode);
10086
10150
  const push = (urlNode, method, callNode) => {
10087
- const urlStr = reconstructUrl(urlNode);
10088
- if (!urlStr) return;
10089
- const host = matchHost(urlStr, knownHosts);
10090
- if (!host) return;
10091
- const p = pathOf(urlStr);
10092
- if (p === null) return;
10151
+ const rec = reconstructUrl(urlNode, constMap);
10152
+ if (!rec) return;
10093
10153
  const line = callNode.startPosition.row + 1;
10154
+ const host = matchHost(rec.url, knownHosts);
10155
+ if (host === null) {
10156
+ if (rec.approximate && hostSlotUnresolved(rec.url)) {
10157
+ out.push({
10158
+ host: null,
10159
+ method,
10160
+ pathTemplate: "",
10161
+ line,
10162
+ snippet: snippet(source, line),
10163
+ approximate: true,
10164
+ reason: "base URL interpolation could not be resolved statically"
10165
+ });
10166
+ }
10167
+ return;
10168
+ }
10169
+ const p = pathOf(rec.url);
10170
+ if (p === null) return;
10094
10171
  out.push({
10095
10172
  host,
10096
10173
  method,
10097
10174
  pathTemplate: p,
10098
10175
  line,
10099
- snippet: snippet(source, line)
10176
+ snippet: snippet(source, line),
10177
+ approximate: rec.approximate,
10178
+ reason: rec.approximate ? "path segment interpolation could not be resolved statically" : void 0
10100
10179
  });
10101
10180
  };
10102
10181
  walk2(tree.rootNode, (node) => {
@@ -10192,6 +10271,35 @@ async function addRouteCallEdges(graph, services) {
10192
10271
  if (sites.length === 0) continue;
10193
10272
  const relFile = toPosix(path38.relative(service.dir, file.path));
10194
10273
  for (const site of sites) {
10274
+ if (site.host === null) {
10275
+ const dedupKey2 = `${relFile}|unresolved-host`;
10276
+ if (seen.has(dedupKey2)) continue;
10277
+ seen.add(dedupKey2);
10278
+ const { fileNodeId: fileNodeId2, nodesAdded: n2, edgesAdded: e2 } = ensureFileNode(
10279
+ graph,
10280
+ service.pkg.name,
10281
+ service.node.id,
10282
+ relFile
10283
+ );
10284
+ nodesAdded += n2;
10285
+ edgesAdded += e2;
10286
+ noteExtractedDropped({
10287
+ source: fileNodeId2,
10288
+ target: "route:unresolved",
10289
+ type: EdgeType14.CALLS,
10290
+ confidence: confidenceForExtracted11("reconstructed-approximate"),
10291
+ confidenceKind: "reconstructed-approximate",
10292
+ evidence: {
10293
+ file: relFile,
10294
+ line: site.line,
10295
+ snippet: site.snippet,
10296
+ method: site.method,
10297
+ approximate: true,
10298
+ reason: site.reason
10299
+ }
10300
+ });
10301
+ continue;
10302
+ }
10195
10303
  const serverServiceId = hostToNodeId.get(site.host);
10196
10304
  if (!serverServiceId || serverServiceId === service.node.id) continue;
10197
10305
  const entries = routeIndex.get(serverServiceId);
@@ -10210,13 +10318,16 @@ async function addRouteCallEdges(graph, services) {
10210
10318
  );
10211
10319
  nodesAdded += n;
10212
10320
  edgesAdded += e;
10213
- const confidence = confidenceForExtracted11("verified-call-site");
10321
+ const anchored = pathHasLiteralAnchor(site.pathTemplate);
10322
+ const confidenceKind = site.approximate && !anchored ? "reconstructed-approximate" : "verified-call-site";
10323
+ const confidence = confidenceForExtracted11(confidenceKind);
10214
10324
  const ev = {
10215
10325
  file: relFile,
10216
10326
  line: site.line,
10217
10327
  snippet: site.snippet,
10218
10328
  method: site.method ?? match.method,
10219
- pathTemplate: site.pathTemplate
10329
+ pathTemplate: site.pathTemplate,
10330
+ ...confidenceKind === "reconstructed-approximate" ? { approximate: true, reason: site.reason } : {}
10220
10331
  };
10221
10332
  if (!passesExtractedFloor2(confidence)) {
10222
10333
  noteExtractedDropped({
@@ -10224,7 +10335,7 @@ async function addRouteCallEdges(graph, services) {
10224
10335
  target: match.routeNodeId,
10225
10336
  type: EdgeType14.CALLS,
10226
10337
  confidence,
10227
- confidenceKind: "verified-call-site",
10338
+ confidenceKind,
10228
10339
  evidence: ev
10229
10340
  });
10230
10341
  continue;
@@ -22043,4 +22154,4 @@ export {
22043
22154
  deprovisionConnector,
22044
22155
  buildApi
22045
22156
  };
22046
- //# sourceMappingURL=chunk-DGAI4VOE.js.map
22157
+ //# sourceMappingURL=chunk-XOGTJVUM.js.map