@saptools/service-flow 0.1.57 → 0.1.58

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.58
4
+
5
+ - Completed RC5 with a deterministic link-phase workspace pass that resolves package-import symbol calls to uniquely matching exported symbols in uniquely identified indexed sibling packages, including package subpath imports and receiver-qualified member calls.
6
+ - Kept external packages, same-repository imports, missing or non-exported names, unsafe aliases/default imports, deeper member chains, duplicate package mappings, and duplicate exported targets fail-closed as unresolved or ambiguous.
7
+ - Recomputed owned package-import rows on every link without a schema, edge, trace-engine, or CLI output change, preserving bounded evidence and cross-package `local_symbol_call` trace descent across repeated link and force-index/relink runs.
8
+
3
9
  ## 0.1.57
4
10
 
5
11
  - Made local executable symbol-call resolution import-binding-aware: relative helper shadowing now bypasses same-file methods (RC1), namespace members resolve within their imported module (RC2), duplicate exports use fail-closed path disambiguation while barrels remain ambiguous (RC3), and singleton-accessor chains reach non-exported instance methods in the imported class module (RC4).
@@ -5277,12 +5277,160 @@ function isRecord3(value) {
5277
5277
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
5278
5278
  }
5279
5279
 
5280
+ // src/linker/003-package-import-symbol-resolver.ts
5281
+ var unresolvedRepositoryReason = "Package import target resolution requires a post-publication workspace pass";
5282
+ var unresolvedSymbolReason = "Sibling package indexed but no matching exported symbol; the target may be a re-export, barrel, type-only export, or unindexed Receiver.member";
5283
+ var ambiguousSymbolReason = "Multiple exported sibling-package symbol targets matched exactly";
5284
+ var stripExt2 = (value) => value.replace(/\.(ts|tsx|js|jsx|cds)$/, "");
5285
+ function push(map, key, id) {
5286
+ const existing = map.get(key);
5287
+ if (existing) existing.push(id);
5288
+ else map.set(key, [id]);
5289
+ }
5290
+ function nullableString2(value) {
5291
+ return typeof value === "string" ? value : void 0;
5292
+ }
5293
+ function evidenceObject(value) {
5294
+ if (typeof value !== "string" || value.length === 0) return {};
5295
+ try {
5296
+ const parsed = JSON.parse(value);
5297
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
5298
+ } catch {
5299
+ return {};
5300
+ }
5301
+ }
5302
+ function repoByPackageName(db, workspaceId) {
5303
+ const result = /* @__PURE__ */ new Map();
5304
+ const rows2 = db.prepare(`SELECT id,package_name packageName FROM repositories
5305
+ WHERE workspace_id=? AND package_name IS NOT NULL ORDER BY package_name,id`).all(workspaceId);
5306
+ for (const row of rows2) {
5307
+ const packageName = nullableString2(row.packageName);
5308
+ if (!packageName || typeof row.id !== "number") continue;
5309
+ result.set(packageName, result.has(packageName) ? null : row.id);
5310
+ }
5311
+ return result;
5312
+ }
5313
+ function packagePrefix(importSource) {
5314
+ const parts = importSource.split("/");
5315
+ if (importSource.startsWith("@")) return parts.length >= 2 ? parts.slice(0, 2).join("/") : importSource;
5316
+ return parts[0] ?? importSource;
5317
+ }
5318
+ function packageRepoId(repos, importSource) {
5319
+ const packageName = repos.has(importSource) ? importSource : packagePrefix(importSource);
5320
+ return repos.get(packageName) ?? null;
5321
+ }
5322
+ function emptyRepoExports() {
5323
+ return { publicName: /* @__PURE__ */ new Map(), qualified: /* @__PURE__ */ new Map(), fileById: /* @__PURE__ */ new Map() };
5324
+ }
5325
+ function exportsByRepo(db, workspaceId) {
5326
+ const result = /* @__PURE__ */ new Map();
5327
+ const rows2 = db.prepare(`SELECT s.id,s.repo_id repoId,s.name,s.exported_name exportedName,
5328
+ s.qualified_name qualifiedName,s.source_file sourceFile
5329
+ FROM symbols s JOIN repositories r ON r.id=s.repo_id
5330
+ WHERE r.workspace_id=? AND s.exported=1 ORDER BY s.repo_id,s.id`).all(workspaceId);
5331
+ for (const row of rows2) addExportRow(result, row);
5332
+ return result;
5333
+ }
5334
+ function addExportRow(result, row) {
5335
+ if (typeof row.id !== "number" || typeof row.repoId !== "number") return;
5336
+ const exports = result.get(row.repoId) ?? emptyRepoExports();
5337
+ result.set(row.repoId, exports);
5338
+ const publicName = nullableString2(row.exportedName) ?? nullableString2(row.name);
5339
+ const qualifiedName = nullableString2(row.qualifiedName);
5340
+ const sourceFile = nullableString2(row.sourceFile);
5341
+ if (publicName) push(exports.publicName, publicName, row.id);
5342
+ if (qualifiedName) push(exports.qualified, qualifiedName, row.id);
5343
+ if (sourceFile) exports.fileById.set(row.id, stripExt2(sourceFile));
5344
+ }
5345
+ function packageCallRows(db, workspaceId) {
5346
+ const rows2 = db.prepare(`SELECT sc.id,sc.repo_id callerRepoId,
5347
+ sc.callee_expression calleeExpression,sc.import_source importSource,
5348
+ sc.evidence_json evidenceJson
5349
+ FROM symbol_calls sc JOIN repositories r ON r.id=sc.repo_id
5350
+ WHERE r.workspace_id=? AND sc.import_source IS NOT NULL
5351
+ AND sc.import_source NOT LIKE './%' AND sc.import_source NOT LIKE '../%'
5352
+ AND json_extract(sc.evidence_json,'$.relation')='package_import'
5353
+ AND json_extract(sc.evidence_json,'$.candidateStrategy') IN
5354
+ ('package_import_unresolved','package_import_workspace_resolved','package_import_ambiguous')
5355
+ ORDER BY sc.id`).all(workspaceId);
5356
+ return rows2.flatMap((row) => packageCallRow(row));
5357
+ }
5358
+ function packageCallRow(row) {
5359
+ const calleeExpression = nullableString2(row.calleeExpression);
5360
+ const importSource = nullableString2(row.importSource);
5361
+ if (typeof row.id !== "number" || typeof row.callerRepoId !== "number" || !calleeExpression || !importSource) return [];
5362
+ return [{
5363
+ id: row.id,
5364
+ callerRepoId: row.callerRepoId,
5365
+ calleeExpression,
5366
+ importSource,
5367
+ evidence: evidenceObject(row.evidenceJson)
5368
+ }];
5369
+ }
5370
+ function candidatesForCall(call, exports) {
5371
+ if (!exports) return [];
5372
+ const dotCount = [...call.calleeExpression].filter((character) => character === ".").length;
5373
+ if (dotCount === 0) {
5374
+ const targetName = nullableString2(call.evidence.targetName);
5375
+ return targetName ? exports.publicName.get(targetName) ?? [] : [];
5376
+ }
5377
+ return dotCount === 1 ? exports.qualified.get(call.calleeExpression) ?? [] : [];
5378
+ }
5379
+ function resolvePackageCall(call, repos, exports) {
5380
+ const targetRepoId = packageRepoId(repos, call.importSource);
5381
+ if (targetRepoId === null || targetRepoId === call.callerRepoId) return unresolvedResolution(unresolvedRepositoryReason);
5382
+ const repoExports = exports.get(targetRepoId);
5383
+ const candidates2 = candidatesForCall(call, repoExports);
5384
+ const [id] = candidates2;
5385
+ if (candidates2.length === 1 && id !== void 0) {
5386
+ return {
5387
+ id,
5388
+ status: "resolved",
5389
+ reason: null,
5390
+ strategy: "package_import_workspace_resolved",
5391
+ candidateCount: 1,
5392
+ resolvedModulePath: repoExports?.fileById.get(id)
5393
+ };
5394
+ }
5395
+ if (candidates2.length > 1) {
5396
+ return { id: null, status: "ambiguous", reason: ambiguousSymbolReason, strategy: "package_import_ambiguous", candidateCount: candidates2.length };
5397
+ }
5398
+ return unresolvedResolution(unresolvedSymbolReason);
5399
+ }
5400
+ function unresolvedResolution(reason) {
5401
+ return { id: null, status: "unresolved", reason, strategy: "package_import_unresolved", candidateCount: 0 };
5402
+ }
5403
+ function resolutionEvidence(call, resolution) {
5404
+ const evidence = {
5405
+ ...call.evidence,
5406
+ candidateStrategy: resolution.strategy,
5407
+ candidateCount: resolution.candidateCount
5408
+ };
5409
+ if (resolution.resolvedModulePath) evidence.resolvedModulePath = resolution.resolvedModulePath;
5410
+ else delete evidence.resolvedModulePath;
5411
+ return JSON.stringify(evidence);
5412
+ }
5413
+ function linkPackageImportSymbolCalls(db, workspaceId) {
5414
+ const repos = repoByPackageName(db, workspaceId);
5415
+ const exports = exportsByRepo(db, workspaceId);
5416
+ const update = db.prepare(`UPDATE symbol_calls SET callee_symbol_id=?,status=?,
5417
+ unresolved_reason=?,evidence_json=? WHERE id=?`);
5418
+ const summary = { resolved: 0, ambiguous: 0, unresolved: 0 };
5419
+ for (const call of packageCallRows(db, workspaceId)) {
5420
+ const resolution = resolvePackageCall(call, repos, exports);
5421
+ update.run(resolution.id, resolution.status, resolution.reason, resolutionEvidence(call, resolution), call.id);
5422
+ summary[resolution.status] += 1;
5423
+ }
5424
+ return summary;
5425
+ }
5426
+
5280
5427
  // src/linker/cross-repo-linker.ts
5281
5428
  function linkWorkspace(db, workspaceId, vars = {}) {
5282
5429
  return db.transaction(() => {
5283
5430
  const generation = nextGraphGeneration(db, workspaceId);
5284
5431
  db.prepare("DELETE FROM graph_edges WHERE workspace_id=?").run(workspaceId);
5285
5432
  const deps = linkHelperPackages(db, workspaceId, generation);
5433
+ linkPackageImportSymbolCalls(db, workspaceId);
5286
5434
  const impl = linkImplementations(db, workspaceId, generation);
5287
5435
  const callSummary = linkCalls(db, workspaceId, vars, generation);
5288
5436
  db.prepare("UPDATE repositories SET graph_generation=?, graph_stale_reason=NULL, graph_stale_at=NULL WHERE workspace_id=?").run(generation, workspaceId);
@@ -8544,4 +8692,4 @@ export {
8544
8692
  selectorRepoAmbiguousDiagnostic,
8545
8693
  trace
8546
8694
  };
8547
- //# sourceMappingURL=chunk-DCOFNDKS.js.map
8695
+ //# sourceMappingURL=chunk-CRSSXWQ2.js.map