@ankhorage/doctor 0.14.9 → 0.14.11

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,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.14.11
4
+
5
+ ### Patch Changes
6
+
7
+ - 508cced: Allow capability catalogs to statically read named schema exports from declared, installed public `@ankhorage/contracts/*` subpaths without executing package code.
8
+
9
+ ## 0.14.10
10
+
11
+ ### Patch Changes
12
+
13
+ - 5c44485: Update dependencies: `@ankhorage/supabase-auth`.
14
+
3
15
  ## 0.14.9
4
16
 
5
17
  ### Patch Changes
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  # @ankhorage/doctor
5
5
 
6
- ![license: MIT](././paradox/badges/license.svg) ![npm: v0.14.9](././paradox/badges/npm.svg) ![runtime: bun](././paradox/badges/runtime.svg) ![typescript: strict](././paradox/badges/typescript.svg) ![eslint: checked](././paradox/badges/eslint.svg) ![prettier: checked](././paradox/badges/prettier.svg) ![build: checked](././paradox/badges/build.svg) ![tests: checked](././paradox/badges/tests.svg) ![paradox: warnings](././paradox/badges/docs.svg)
6
+ ![license: MIT](././paradox/badges/license.svg) ![npm: v0.14.11](././paradox/badges/npm.svg) ![runtime: bun](././paradox/badges/runtime.svg) ![typescript: strict](././paradox/badges/typescript.svg) ![eslint: checked](././paradox/badges/eslint.svg) ![prettier: checked](././paradox/badges/prettier.svg) ![build: checked](././paradox/badges/build.svg) ![tests: checked](././paradox/badges/tests.svg) ![paradox: warnings](././paradox/badges/docs.svg)
7
7
 
8
8
  Executable Ankh provider and standalone CLI for lightweight repo and package compliance diagnostics.
9
9
 
@@ -1 +1 @@
1
- {"version":3,"file":"capabilityCatalogAst.d.ts","sourceRoot":"","sources":["../src/capabilityCatalogAst.ts"],"names":[],"mappings":"AAUA,sFAAsF;AACtF,wBAAsB,yBAAyB,CAC7C,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,OAAO,CAAC,CAElB"}
1
+ {"version":3,"file":"capabilityCatalogAst.d.ts","sourceRoot":"","sources":["../src/capabilityCatalogAst.ts"],"names":[],"mappings":"AAYA,sFAAsF;AACtF,wBAAsB,yBAAyB,CAC7C,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,OAAO,CAAC,CAElB"}
@@ -1,6 +1,7 @@
1
1
  import { promises as fs } from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import * as ts from 'typescript';
4
+ import { resolveContractsCatalogImportAsync } from './capabilityCatalogContractsImport.js';
4
5
  /*** Evaluate one named catalog export from the supported static TypeScript subset. */
5
6
  export async function capabilityCatalogAstAsync(packageRoot, modulePath, exportName) {
6
7
  return new StaticCatalogResolver(packageRoot).resolveAsync(modulePath, exportName);
@@ -14,9 +15,9 @@ class StaticCatalogResolver {
14
15
  this.packageRoot = packageRoot;
15
16
  }
16
17
  /*** Resolve a named local export without importing or running its module. */
17
- async resolveAsync(modulePath, exportName) {
18
+ async resolveAsync(modulePath, exportName, moduleRoot = this.packageRoot) {
18
19
  const key = `${modulePath}:${exportName}`;
19
- return this.resolveSymbolAsync(key, () => this.resolveUncachedAsync(modulePath, exportName));
20
+ return this.resolveSymbolAsync(key, () => this.resolveUncachedAsync(modulePath, exportName, moduleRoot));
20
21
  }
21
22
  /*** Resolve one local symbol while detecting recursive static references. */
22
23
  async resolveSymbolAsync(key, resolveAsync) {
@@ -37,7 +38,7 @@ class StaticCatalogResolver {
37
38
  }
38
39
  }
39
40
  /*** Find and evaluate the declaration owning one exported static value. */
40
- async resolveUncachedAsync(modulePath, exportName) {
41
+ async resolveUncachedAsync(modulePath, exportName, moduleRoot) {
41
42
  const source = ts.createSourceFile(modulePath, await fs.readFile(modulePath, 'utf8'), ts.ScriptTarget.ESNext, true);
42
43
  const declaration = source.statements
43
44
  .filter((statement) => ts.isVariableStatement(statement))
@@ -47,7 +48,7 @@ class StaticCatalogResolver {
47
48
  .find((value) => ts.isIdentifier(value.name) && value.name.text === exportName);
48
49
  if (declaration?.initializer === undefined)
49
50
  throw new Error(`Unable to find static export ${exportName} in ${modulePath}.`);
50
- return this.evaluateAsync(declaration.initializer, new StaticCatalogScope(this, source, modulePath, this.packageRoot));
51
+ return this.evaluateAsync(declaration.initializer, new StaticCatalogScope(this, source, modulePath, moduleRoot));
51
52
  }
52
53
  /*** Evaluate an allowed static expression. */
53
54
  async evaluateAsync(expression, environment) {
@@ -152,7 +153,7 @@ class StaticCatalogScope {
152
153
  this.packageRoot = packageRoot;
153
154
  this.values = values;
154
155
  }
155
- /*** Resolve a local constant or named local import when it is referenced. */
156
+ /*** Resolve a local constant or an allowed named static package import. */
156
157
  async resolveAsync(name) {
157
158
  const value = this.values.get(name);
158
159
  if (value !== undefined)
@@ -174,8 +175,8 @@ class StaticCatalogScope {
174
175
  const binding = bindings.elements.find((element) => !element.isTypeOnly && element.name.text === name);
175
176
  if (binding === undefined)
176
177
  throw new Error(`Unsupported dynamic capability value: ${name}.`);
177
- const importPath = await resolveImportPathAsync(this.packageRoot, this.modulePath, imported.moduleSpecifier.text);
178
- return this.resolver.resolveAsync(importPath, binding.propertyName?.text ?? binding.name.text);
178
+ const resolvedImport = await resolveImportPathAsync(this.packageRoot, this.modulePath, imported.moduleSpecifier.text);
179
+ return this.resolver.resolveAsync(resolvedImport.path, binding.propertyName?.text ?? binding.name.text, resolvedImport.packageRoot);
179
180
  }
180
181
  /*** Add a static callback parameter without evaluating unrelated module symbols. */
181
182
  withValue(name, value) {
@@ -206,16 +207,20 @@ function findImportBinding(source, name) {
206
207
  function isConstDeclaration(list) {
207
208
  return (list.flags & ts.NodeFlags.Const) !== 0;
208
209
  }
209
- /*** Resolve a local import to one source file inside the inspected package. */
210
+ /*** Resolve an allowed static import without executing its target package. */
210
211
  async function resolveImportPathAsync(packageRoot, fromPath, specifier) {
211
- if (!specifier.startsWith('.'))
212
- throw new Error('Capability catalogs may import only local static metadata.');
212
+ if (specifier.startsWith('.'))
213
+ return resolveLocalImportPathAsync(packageRoot, fromPath, specifier);
214
+ return resolveContractsCatalogImportAsync(packageRoot, fromPath, specifier);
215
+ }
216
+ /*** Resolve a relative static import that remains within its owning package. */
217
+ async function resolveLocalImportPathAsync(packageRoot, fromPath, specifier) {
213
218
  const candidate = path.resolve(path.dirname(fromPath), specifier);
214
219
  if (!isInsidePackage(packageRoot, candidate) && candidate !== packageRoot)
215
220
  throw new Error('Capability catalogs may not import outside their package.');
216
221
  for (const extension of ['', '.ts', '.tsx', '.js', '.mjs', '/index.ts'])
217
222
  if (await isFileAsync(`${candidate}${extension}`))
218
- return `${candidate}${extension}`;
223
+ return { packageRoot, path: `${candidate}${extension}` };
219
224
  throw new Error(`Unable to resolve static capability import ${specifier}.`);
220
225
  }
221
226
  /*** Unwrap TypeScript syntax which does not alter a runtime value. */
@@ -1 +1 @@
1
- {"version":3,"file":"capabilityCatalogAst.js","sourceRoot":"","sources":["../src/capabilityCatalogAst.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAOjC,sFAAsF;AACtF,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,WAAmB,EACnB,UAAkB,EAClB,UAAkB;IAElB,OAAO,IAAI,qBAAqB,CAAC,WAAW,CAAC,CAAC,YAAY,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;AACrF,CAAC;AAED,oFAAoF;AACpF,MAAM,qBAAqB;IAII;IAHpB,QAAQ,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC1C,cAAc,GAAa,EAAE,CAAC;IAEvC,YAA6B,WAAmB;QAAnB,gBAAW,GAAX,WAAW,CAAQ;IAAG,CAAC;IAEpD,6EAA6E;IAC7E,KAAK,CAAC,YAAY,CAAC,UAAkB,EAAE,UAAkB;QACvD,MAAM,GAAG,GAAG,GAAG,UAAU,IAAI,UAAU,EAAE,CAAC;QAC1C,OAAO,IAAI,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,oBAAoB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC;IAC/F,CAAC;IAED,6EAA6E;IAC7E,KAAK,CAAC,kBAAkB,CACtB,GAAW,EACX,YAAwC;QAExC,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACtC,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,MAAM,CAAC;QACxC,MAAM,UAAU,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACpD,IAAI,UAAU,IAAI,CAAC;YACjB,MAAM,IAAI,KAAK,CACb,uCAAuC,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CACvG,CAAC;QACJ,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,YAAY,EAAE,CAAC;YACnC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YAC9B,OAAO,KAAK,CAAC;QACf,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,2EAA2E;IAC3E,KAAK,CAAC,oBAAoB,CAAC,UAAkB,EAAE,UAAkB;QAC/D,MAAM,MAAM,GAAG,EAAE,CAAC,gBAAgB,CAChC,UAAU,EACV,MAAM,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,EACrC,EAAE,CAAC,YAAY,CAAC,MAAM,EACtB,IAAI,CACL,CAAC;QACF,MAAM,WAAW,GAAG,MAAM,CAAC,UAAU;aAClC,MAAM,CAAC,CAAC,SAAS,EAAqC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC;aAC3F,MAAM,CAAC,iBAAiB,CAAC;aACzB,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,kBAAkB,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;aACpE,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,eAAe,CAAC,YAAY,CAAC;aAC9D,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC;QAClF,IAAI,WAAW,EAAE,WAAW,KAAK,SAAS;YACxC,MAAM,IAAI,KAAK,CAAC,gCAAgC,UAAU,OAAO,UAAU,GAAG,CAAC,CAAC;QAClF,OAAO,IAAI,CAAC,aAAa,CACvB,WAAW,CAAC,WAAW,EACvB,IAAI,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,WAAW,CAAC,CACnE,CAAC;IACJ,CAAC;IAED,8CAA8C;IAC9C,KAAK,CAAC,aAAa,CACjB,UAAyB,EACzB,WAA+B;QAE/B,MAAM,IAAI,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAC1C,IAAI,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,+BAA+B,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC,IAAI,CAAC;QAC3F,IAAI,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC;YAAE,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxD,IAAI,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,WAAW;YAAE,OAAO,IAAI,CAAC;QACzD,IAAI,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,YAAY;YAAE,OAAO,KAAK,CAAC;QAC3D,IAAI,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,WAAW;YAAE,OAAO,IAAI,CAAC;QACzD,IAAI,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC;YAAE,OAAO,WAAW,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtE,IAAI,EAAE,CAAC,wBAAwB,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QACjF,IAAI,EAAE,CAAC,yBAAyB,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QACnF,IAAI,EAAE,CAAC,oBAAoB,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QAChF,IAAI,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QACvE,MAAM,IAAI,KAAK,CAAC,6CAA6C,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAClF,CAAC;IAED,wCAAwC;IACxC,UAAU,CACR,IAA+B,EAC/B,WAA+B;QAE/B,OAAO,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAChE,CAAC;IAED,iEAAiE;IACjE,KAAK,CAAC,WAAW,CACf,IAAgC,EAChC,WAA+B;QAE/B,MAAM,MAAM,GAAgC,EAAE,CAAC;QAC/C,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACvC,IAAI,EAAE,CAAC,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACpC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;gBACzE,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC;oBACxB,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;gBAC3E,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YAC/B,CAAC;iBAAM,IACL,EAAE,CAAC,oBAAoB,CAAC,QAAQ,CAAC;gBACjC,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;gBAErE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;iBACtF,IAAI,EAAE,CAAC,6BAA6B,CAAC,QAAQ,CAAC;gBACjD,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,MAAM,WAAW,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;;gBAC7E,MAAM,IAAI,KAAK,CAAC,2CAA2C,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACzF,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,iFAAiF;IACjF,KAAK,CAAC,aAAa,CACjB,IAA2B,EAC3B,WAA+B;QAE/B,IAAI,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;QAC3B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACtC,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;YAC7E,IAAI,OAAO,aAAa,KAAK,QAAQ,IAAI,aAAa,KAAK,IAAI;gBAC7D,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;YACrF,KAAK,IAAI,GAAG,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAClD,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,yEAAyE;IACzE,KAAK,CAAC,QAAQ,CACZ,IAAuB,EACvB,WAA+B;QAE/B,IAAI,CAAC,EAAE,CAAC,0BAA0B,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,KAAK;YACxF,MAAM,IAAI,KAAK,CAAC,uCAAuC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAC5E,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;QACjF,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACtC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,QAAQ,KAAK,SAAS,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC,QAAQ,CAAC;YACnF,MAAM,IAAI,KAAK,CAAC,sCAAsC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAC3E,MAAM,SAAS,GAAG,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5C,MAAM,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC;QAC1B,IAAI,SAAS,KAAK,SAAS,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC;YACvF,MAAM,IAAI,KAAK,CAAC,+CAA+C,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACxF,MAAM,aAAa,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;QAC1C,MAAM,MAAM,GAAkB,EAAE,CAAC;QACjC,KAAK,MAAM,KAAK,IAAI,MAAM;YACxB,MAAM,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,WAAW,CAAC,SAAS,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;QAC3F,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,uDAAuD;IACvD,KAAK,CAAC,qBAAqB,CACzB,QAAwD,EACxD,WAA+B;QAE/B,MAAM,MAAM,GAAkB,EAAE,CAAC;QACjC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,IAAI,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;YAC7F,MAAM,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC;QAC9D,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAED,kFAAkF;AAClF,MAAM,kBAAkB;IAEH;IACA;IACA;IACA;IACA;IALnB,YACmB,QAA+B,EAC/B,MAAqB,EACrB,UAAkB,EAClB,WAAmB,EACnB,SAA2C,IAAI,GAAG,EAAE;QAJpD,aAAQ,GAAR,QAAQ,CAAuB;QAC/B,WAAM,GAAN,MAAM,CAAe;QACrB,eAAU,GAAV,UAAU,CAAQ;QAClB,gBAAW,GAAX,WAAW,CAAQ;QACnB,WAAM,GAAN,MAAM,CAA8C;IACpE,CAAC;IAEJ,6EAA6E;IAC7E,KAAK,CAAC,YAAY,CAAC,IAAY;QAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;QACtC,MAAM,WAAW,GAAG,qBAAqB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC7D,MAAM,WAAW,GAAG,WAAW,EAAE,WAAW,CAAC;QAC7C,IAAI,WAAW,KAAK,SAAS;YAC3B,OAAO,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,EAAE,EAAE,GAAG,EAAE,CACzE,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,CAC/C,CAAC;QACJ,MAAM,QAAQ,GAAG,iBAAiB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACtD,IAAI,QAAQ,KAAK,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,IAAI,GAAG,CAAC,CAAC;QAC9F,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC,QAAQ,CAAC,eAAe,CAAC;YAC/C,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;QACjF,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,EAAE,aAAa,CAAC;QACtD,IAAI,QAAQ,CAAC,YAAY,EAAE,UAAU,IAAI,QAAQ,KAAK,SAAS;YAC7D,MAAM,IAAI,KAAK,CAAC,yCAAyC,IAAI,GAAG,CAAC,CAAC;QACpE,IAAI,CAAC,EAAE,CAAC,cAAc,CAAC,QAAQ,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;QACjF,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CACpC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAC/D,CAAC;QACF,IAAI,OAAO,KAAK,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,IAAI,GAAG,CAAC,CAAC;QAC7F,MAAM,UAAU,GAAG,MAAM,sBAAsB,CAC7C,IAAI,CAAC,WAAW,EAChB,IAAI,CAAC,UAAU,EACf,QAAQ,CAAC,eAAe,CAAC,IAAI,CAC9B,CAAC;QACF,OAAO,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,YAAY,EAAE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjG,CAAC;IAED,oFAAoF;IACpF,SAAS,CAAC,IAAY,EAAE,KAAkB;QACxC,OAAO,IAAI,kBAAkB,CAC3B,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,WAAW,EAChB,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CACzC,CAAC;IACJ,CAAC;CACF;AAED,2EAA2E;AAC3E,SAAS,qBAAqB,CAC5B,MAAqB,EACrB,IAAY;IAEZ,OAAO,MAAM,CAAC,UAAU;SACrB,MAAM,CAAC,CAAC,SAAS,EAAqC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC;SAC3F,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,kBAAkB,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;SACpE,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,eAAe,CAAC,YAAY,CAAC;SAC9D,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AAChG,CAAC;AAED,kFAAkF;AAClF,SAAS,iBAAiB,CAAC,MAAqB,EAAE,IAAY;IAC5D,OAAO,MAAM,CAAC,UAAU;SACrB,MAAM,CAAC,CAAC,SAAS,EAAqC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC;SAC3F,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE;QAClB,MAAM,MAAM,GAAG,SAAS,CAAC,YAAY,CAAC;QACtC,OAAO,CACL,MAAM,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI;YAC3B,CAAC,MAAM,EAAE,aAAa,KAAK,SAAS;gBAClC,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,aAAa,CAAC;gBACvC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAC/E,CAAC;IACJ,CAAC,CAAC,CAAC;AACP,CAAC;AAED,+EAA+E;AAC/E,SAAS,kBAAkB,CAAC,IAAgC;IAC1D,OAAO,CAAC,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AACjD,CAAC;AAED,+EAA+E;AAC/E,KAAK,UAAU,sBAAsB,CACnC,WAAmB,EACnB,QAAgB,EAChB,SAAiB;IAEjB,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;IAChF,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC,CAAC;IAClE,IAAI,CAAC,eAAe,CAAC,WAAW,EAAE,SAAS,CAAC,IAAI,SAAS,KAAK,WAAW;QACvE,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;IAC/E,KAAK,MAAM,SAAS,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC;QACrE,IAAI,MAAM,WAAW,CAAC,GAAG,SAAS,GAAG,SAAS,EAAE,CAAC;YAAE,OAAO,GAAG,SAAS,GAAG,SAAS,EAAE,CAAC;IACvF,MAAM,IAAI,KAAK,CAAC,8CAA8C,SAAS,GAAG,CAAC,CAAC;AAC9E,CAAC;AAED,sEAAsE;AACtE,SAAS,gBAAgB,CAAC,UAAyB;IACjD,OAAO,EAAE,CAAC,cAAc,CAAC,UAAU,CAAC;QAClC,EAAE,CAAC,qBAAqB,CAAC,UAAU,CAAC;QACpC,EAAE,CAAC,yBAAyB,CAAC,UAAU,CAAC;QACxC,CAAC,CAAC,gBAAgB,CAAC,UAAU,CAAC,UAAU,CAAC;QACzC,CAAC,CAAC,UAAU,CAAC;AACjB,CAAC;AAED,4DAA4D;AAC5D,SAAS,cAAc,CAAC,KAAkB;IACxC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,0CAA0C;AAC1C,SAAS,aAAa,CAAC,KAAkB;IACvC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9B,CAAC;AAED,8CAA8C;AAC9C,SAAS,iBAAiB,CAAC,SAA+B;IACxD,OAAO,CACL,SAAS,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,IAAI,KAAK,CAChG,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,SAAS,eAAe,CAAC,WAAmB,EAAE,SAAiB;IAC7D,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAC3D,OAAO,YAAY,KAAK,EAAE,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,YAAY,KAAK,IAAI,CAAC;AACnG,CAAC;AAED,sDAAsD;AACtD,KAAK,UAAU,WAAW,CAAC,SAAiB;IAC1C,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC","sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\n\nimport * as ts from 'typescript';\n\ntype StaticValue = string | number | boolean | null | readonly StaticValue[] | StaticRecord;\ninterface StaticRecord {\n readonly [key: string]: StaticValue;\n}\n\n/*** Evaluate one named catalog export from the supported static TypeScript subset. */\nexport async function capabilityCatalogAstAsync(\n packageRoot: string,\n modulePath: string,\n exportName: string,\n): Promise<unknown> {\n return new StaticCatalogResolver(packageRoot).resolveAsync(modulePath, exportName);\n}\n\n/*** Resolve static local imports and expressions without loading target modules. */\nclass StaticCatalogResolver {\n readonly #symbols = new Map<string, StaticValue>();\n readonly #activeSymbols: string[] = [];\n\n constructor(private readonly packageRoot: string) {}\n\n /*** Resolve a named local export without importing or running its module. */\n async resolveAsync(modulePath: string, exportName: string): Promise<StaticValue> {\n const key = `${modulePath}:${exportName}`;\n return this.resolveSymbolAsync(key, () => this.resolveUncachedAsync(modulePath, exportName));\n }\n\n /*** Resolve one local symbol while detecting recursive static references. */\n async resolveSymbolAsync(\n key: string,\n resolveAsync: () => Promise<StaticValue>,\n ): Promise<StaticValue> {\n const cached = this.#symbols.get(key);\n if (cached !== undefined) return cached;\n const cycleStart = this.#activeSymbols.indexOf(key);\n if (cycleStart >= 0)\n throw new Error(\n `Cyclic static capability reference: ${[...this.#activeSymbols.slice(cycleStart), key].join(' -> ')}.`,\n );\n this.#activeSymbols.push(key);\n try {\n const value = await resolveAsync();\n this.#symbols.set(key, value);\n return value;\n } finally {\n this.#activeSymbols.pop();\n }\n }\n\n /*** Find and evaluate the declaration owning one exported static value. */\n async resolveUncachedAsync(modulePath: string, exportName: string): Promise<StaticValue> {\n const source = ts.createSourceFile(\n modulePath,\n await fs.readFile(modulePath, 'utf8'),\n ts.ScriptTarget.ESNext,\n true,\n );\n const declaration = source.statements\n .filter((statement): statement is ts.VariableStatement => ts.isVariableStatement(statement))\n .filter(hasExportModifier)\n .filter((statement) => isConstDeclaration(statement.declarationList))\n .flatMap((statement) => statement.declarationList.declarations)\n .find((value) => ts.isIdentifier(value.name) && value.name.text === exportName);\n if (declaration?.initializer === undefined)\n throw new Error(`Unable to find static export ${exportName} in ${modulePath}.`);\n return this.evaluateAsync(\n declaration.initializer,\n new StaticCatalogScope(this, source, modulePath, this.packageRoot),\n );\n }\n\n /*** Evaluate an allowed static expression. */\n async evaluateAsync(\n expression: ts.Expression,\n environment: StaticCatalogScope,\n ): Promise<StaticValue> {\n const node = unwrapExpression(expression);\n if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) return node.text;\n if (ts.isNumericLiteral(node)) return Number(node.text);\n if (node.kind === ts.SyntaxKind.TrueKeyword) return true;\n if (node.kind === ts.SyntaxKind.FalseKeyword) return false;\n if (node.kind === ts.SyntaxKind.NullKeyword) return null;\n if (ts.isIdentifier(node)) return environment.resolveAsync(node.text);\n if (ts.isArrayLiteralExpression(node)) return this.arrayAsync(node, environment);\n if (ts.isObjectLiteralExpression(node)) return this.objectAsync(node, environment);\n if (ts.isTemplateExpression(node)) return this.templateAsync(node, environment);\n if (ts.isCallExpression(node)) return this.mapAsync(node, environment);\n throw new Error(`Unsupported static capability expression: ${node.getText()}.`);\n }\n\n /*** Evaluate a static array literal. */\n arrayAsync(\n node: ts.ArrayLiteralExpression,\n environment: StaticCatalogScope,\n ): Promise<readonly StaticValue[]> {\n return this.evaluateElementsAsync(node.elements, environment);\n }\n\n /*** Evaluate static object properties and descriptor spreads. */\n async objectAsync(\n node: ts.ObjectLiteralExpression,\n environment: StaticCatalogScope,\n ): Promise<StaticRecord> {\n const result: Record<string, StaticValue> = {};\n for (const property of node.properties) {\n if (ts.isSpreadAssignment(property)) {\n const value = await this.evaluateAsync(property.expression, environment);\n if (!isStaticRecord(value))\n throw new Error('Capability descriptor spreads must be static objects.');\n Object.assign(result, value);\n } else if (\n ts.isPropertyAssignment(property) &&\n (ts.isIdentifier(property.name) || ts.isStringLiteral(property.name))\n )\n result[property.name.text] = await this.evaluateAsync(property.initializer, environment);\n else if (ts.isShorthandPropertyAssignment(property))\n result[property.name.text] = await environment.resolveAsync(property.name.text);\n else throw new Error(`Unsupported static capability property: ${property.getText()}.`);\n }\n return result;\n }\n\n /*** Evaluate a template literal whose substitutions are scalar static values. */\n async templateAsync(\n node: ts.TemplateExpression,\n environment: StaticCatalogScope,\n ): Promise<string> {\n let value = node.head.text;\n for (const span of node.templateSpans) {\n const interpolation = await this.evaluateAsync(span.expression, environment);\n if (typeof interpolation === 'object' && interpolation !== null)\n throw new Error('Capability templates may interpolate only static scalar values.');\n value += `${interpolation}${span.literal.text}`;\n }\n return value;\n }\n\n /*** Evaluate Array.map with a single static arrow-function parameter. */\n async mapAsync(\n node: ts.CallExpression,\n environment: StaticCatalogScope,\n ): Promise<readonly StaticValue[]> {\n if (!ts.isPropertyAccessExpression(node.expression) || node.expression.name.text !== 'map')\n throw new Error(`Unsupported static capability call: ${node.getText()}.`);\n const values = await this.evaluateAsync(node.expression.expression, environment);\n const callback = node.arguments.at(0);\n if (!isStaticArray(values) || callback === undefined || !ts.isArrowFunction(callback))\n throw new Error(`Unsupported static capability map: ${node.getText()}.`);\n const parameter = callback.parameters.at(0);\n const { body } = callback;\n if (parameter === undefined || !ts.isIdentifier(parameter.name) || !ts.isExpression(body))\n throw new Error(`Unsupported static capability map callback: ${callback.getText()}.`);\n const parameterName = parameter.name.text;\n const result: StaticValue[] = [];\n for (const value of values)\n result.push(await this.evaluateAsync(body, environment.withValue(parameterName, value)));\n return result;\n }\n\n /*** Evaluate static array elements in source order. */\n async evaluateElementsAsync(\n elements: ts.NodeArray<ts.Expression | ts.SpreadElement>,\n environment: StaticCatalogScope,\n ): Promise<readonly StaticValue[]> {\n const result: StaticValue[] = [];\n for (const element of elements) {\n if (ts.isSpreadElement(element)) throw new Error('Catalog array spreads are not supported.');\n result.push(await this.evaluateAsync(element, environment));\n }\n return result;\n }\n}\n\n/*** Resolve only static symbols reached from the requested catalog expression. */\nclass StaticCatalogScope {\n constructor(\n private readonly resolver: StaticCatalogResolver,\n private readonly source: ts.SourceFile,\n private readonly modulePath: string,\n private readonly packageRoot: string,\n private readonly values: ReadonlyMap<string, StaticValue> = new Map(),\n ) {}\n\n /*** Resolve a local constant or named local import when it is referenced. */\n async resolveAsync(name: string): Promise<StaticValue> {\n const value = this.values.get(name);\n if (value !== undefined) return value;\n const declaration = findStaticDeclaration(this.source, name);\n const initializer = declaration?.initializer;\n if (initializer !== undefined)\n return this.resolver.resolveSymbolAsync(`${this.modulePath}:${name}`, () =>\n this.resolver.evaluateAsync(initializer, this),\n );\n const imported = findImportBinding(this.source, name);\n if (imported === undefined) throw new Error(`Unsupported dynamic capability value: ${name}.`);\n if (!ts.isStringLiteral(imported.moduleSpecifier))\n throw new Error('Capability catalogs support only named local value imports.');\n const bindings = imported.importClause?.namedBindings;\n if (imported.importClause?.isTypeOnly || bindings === undefined)\n throw new Error(`Unsupported dynamic capability value: ${name}.`);\n if (!ts.isNamedImports(bindings))\n throw new Error('Capability catalogs support only named local value imports.');\n const binding = bindings.elements.find(\n (element) => !element.isTypeOnly && element.name.text === name,\n );\n if (binding === undefined) throw new Error(`Unsupported dynamic capability value: ${name}.`);\n const importPath = await resolveImportPathAsync(\n this.packageRoot,\n this.modulePath,\n imported.moduleSpecifier.text,\n );\n return this.resolver.resolveAsync(importPath, binding.propertyName?.text ?? binding.name.text);\n }\n\n /*** Add a static callback parameter without evaluating unrelated module symbols. */\n withValue(name: string, value: StaticValue): StaticCatalogScope {\n return new StaticCatalogScope(\n this.resolver,\n this.source,\n this.modulePath,\n this.packageRoot,\n new Map([...this.values, [name, value]]),\n );\n }\n}\n\n/*** Find the static top-level declaration that owns a local identifier. */\nfunction findStaticDeclaration(\n source: ts.SourceFile,\n name: string,\n): ts.VariableDeclaration | undefined {\n return source.statements\n .filter((statement): statement is ts.VariableStatement => ts.isVariableStatement(statement))\n .filter((statement) => isConstDeclaration(statement.declarationList))\n .flatMap((statement) => statement.declarationList.declarations)\n .find((declaration) => ts.isIdentifier(declaration.name) && declaration.name.text === name);\n}\n\n/*** Find the import declaration that introduces a referenced local identifier. */\nfunction findImportBinding(source: ts.SourceFile, name: string): ts.ImportDeclaration | undefined {\n return source.statements\n .filter((statement): statement is ts.ImportDeclaration => ts.isImportDeclaration(statement))\n .find((statement) => {\n const clause = statement.importClause;\n return (\n clause?.name?.text === name ||\n (clause?.namedBindings !== undefined &&\n ts.isNamedImports(clause.namedBindings) &&\n clause.namedBindings.elements.some((element) => element.name.text === name))\n );\n });\n}\n\n/*** Determine whether a declaration list is immutable static catalog input. */\nfunction isConstDeclaration(list: ts.VariableDeclarationList): boolean {\n return (list.flags & ts.NodeFlags.Const) !== 0;\n}\n\n/*** Resolve a local import to one source file inside the inspected package. */\nasync function resolveImportPathAsync(\n packageRoot: string,\n fromPath: string,\n specifier: string,\n): Promise<string> {\n if (!specifier.startsWith('.'))\n throw new Error('Capability catalogs may import only local static metadata.');\n const candidate = path.resolve(path.dirname(fromPath), specifier);\n if (!isInsidePackage(packageRoot, candidate) && candidate !== packageRoot)\n throw new Error('Capability catalogs may not import outside their package.');\n for (const extension of ['', '.ts', '.tsx', '.js', '.mjs', '/index.ts'])\n if (await isFileAsync(`${candidate}${extension}`)) return `${candidate}${extension}`;\n throw new Error(`Unable to resolve static capability import ${specifier}.`);\n}\n\n/*** Unwrap TypeScript syntax which does not alter a runtime value. */\nfunction unwrapExpression(expression: ts.Expression): ts.Expression {\n return ts.isAsExpression(expression) ||\n ts.isSatisfiesExpression(expression) ||\n ts.isParenthesizedExpression(expression)\n ? unwrapExpression(expression.expression)\n : expression;\n}\n\n/*** Narrow a static value to a descriptor-shaped record. */\nfunction isStaticRecord(value: StaticValue): value is StaticRecord {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/*** Narrow a static value to an array. */\nfunction isStaticArray(value: StaticValue): value is readonly StaticValue[] {\n return Array.isArray(value);\n}\n\n/*** Detect an exported variable statement. */\nfunction hasExportModifier(statement: ts.VariableStatement): boolean {\n return (\n statement.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword) ?? false\n );\n}\n\n/*** Check whether a resolved path remains within the inspected package root. */\nfunction isInsidePackage(packageRoot: string, candidate: string): boolean {\n const relativePath = path.relative(packageRoot, candidate);\n return relativePath !== '' && !relativePath.startsWith(`..${path.sep}`) && relativePath !== '..';\n}\n\n/*** Check whether one candidate is a regular file. */\nasync function isFileAsync(candidate: string): Promise<boolean> {\n try {\n return (await fs.stat(candidate)).isFile();\n } catch {\n return false;\n }\n}\n"]}
1
+ {"version":3,"file":"capabilityCatalogAst.js","sourceRoot":"","sources":["../src/capabilityCatalogAst.ts"],"names":[],"mappings":"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","sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\n\nimport * as ts from 'typescript';\n\nimport { resolveContractsCatalogImportAsync } from './capabilityCatalogContractsImport.js';\n\ntype StaticValue = string | number | boolean | null | readonly StaticValue[] | StaticRecord;\ninterface StaticRecord {\n readonly [key: string]: StaticValue;\n}\n\n/*** Evaluate one named catalog export from the supported static TypeScript subset. */\nexport async function capabilityCatalogAstAsync(\n packageRoot: string,\n modulePath: string,\n exportName: string,\n): Promise<unknown> {\n return new StaticCatalogResolver(packageRoot).resolveAsync(modulePath, exportName);\n}\n\n/*** Resolve static local imports and expressions without loading target modules. */\nclass StaticCatalogResolver {\n readonly #symbols = new Map<string, StaticValue>();\n readonly #activeSymbols: string[] = [];\n\n constructor(private readonly packageRoot: string) {}\n\n /*** Resolve a named local export without importing or running its module. */\n async resolveAsync(\n modulePath: string,\n exportName: string,\n moduleRoot = this.packageRoot,\n ): Promise<StaticValue> {\n const key = `${modulePath}:${exportName}`;\n return this.resolveSymbolAsync(key, () =>\n this.resolveUncachedAsync(modulePath, exportName, moduleRoot),\n );\n }\n\n /*** Resolve one local symbol while detecting recursive static references. */\n async resolveSymbolAsync(\n key: string,\n resolveAsync: () => Promise<StaticValue>,\n ): Promise<StaticValue> {\n const cached = this.#symbols.get(key);\n if (cached !== undefined) return cached;\n const cycleStart = this.#activeSymbols.indexOf(key);\n if (cycleStart >= 0)\n throw new Error(\n `Cyclic static capability reference: ${[...this.#activeSymbols.slice(cycleStart), key].join(' -> ')}.`,\n );\n this.#activeSymbols.push(key);\n try {\n const value = await resolveAsync();\n this.#symbols.set(key, value);\n return value;\n } finally {\n this.#activeSymbols.pop();\n }\n }\n\n /*** Find and evaluate the declaration owning one exported static value. */\n async resolveUncachedAsync(\n modulePath: string,\n exportName: string,\n moduleRoot: string,\n ): Promise<StaticValue> {\n const source = ts.createSourceFile(\n modulePath,\n await fs.readFile(modulePath, 'utf8'),\n ts.ScriptTarget.ESNext,\n true,\n );\n const declaration = source.statements\n .filter((statement): statement is ts.VariableStatement => ts.isVariableStatement(statement))\n .filter(hasExportModifier)\n .filter((statement) => isConstDeclaration(statement.declarationList))\n .flatMap((statement) => statement.declarationList.declarations)\n .find((value) => ts.isIdentifier(value.name) && value.name.text === exportName);\n if (declaration?.initializer === undefined)\n throw new Error(`Unable to find static export ${exportName} in ${modulePath}.`);\n return this.evaluateAsync(\n declaration.initializer,\n new StaticCatalogScope(this, source, modulePath, moduleRoot),\n );\n }\n\n /*** Evaluate an allowed static expression. */\n async evaluateAsync(\n expression: ts.Expression,\n environment: StaticCatalogScope,\n ): Promise<StaticValue> {\n const node = unwrapExpression(expression);\n if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) return node.text;\n if (ts.isNumericLiteral(node)) return Number(node.text);\n if (node.kind === ts.SyntaxKind.TrueKeyword) return true;\n if (node.kind === ts.SyntaxKind.FalseKeyword) return false;\n if (node.kind === ts.SyntaxKind.NullKeyword) return null;\n if (ts.isIdentifier(node)) return environment.resolveAsync(node.text);\n if (ts.isArrayLiteralExpression(node)) return this.arrayAsync(node, environment);\n if (ts.isObjectLiteralExpression(node)) return this.objectAsync(node, environment);\n if (ts.isTemplateExpression(node)) return this.templateAsync(node, environment);\n if (ts.isCallExpression(node)) return this.mapAsync(node, environment);\n throw new Error(`Unsupported static capability expression: ${node.getText()}.`);\n }\n\n /*** Evaluate a static array literal. */\n arrayAsync(\n node: ts.ArrayLiteralExpression,\n environment: StaticCatalogScope,\n ): Promise<readonly StaticValue[]> {\n return this.evaluateElementsAsync(node.elements, environment);\n }\n\n /*** Evaluate static object properties and descriptor spreads. */\n async objectAsync(\n node: ts.ObjectLiteralExpression,\n environment: StaticCatalogScope,\n ): Promise<StaticRecord> {\n const result: Record<string, StaticValue> = {};\n for (const property of node.properties) {\n if (ts.isSpreadAssignment(property)) {\n const value = await this.evaluateAsync(property.expression, environment);\n if (!isStaticRecord(value))\n throw new Error('Capability descriptor spreads must be static objects.');\n Object.assign(result, value);\n } else if (\n ts.isPropertyAssignment(property) &&\n (ts.isIdentifier(property.name) || ts.isStringLiteral(property.name))\n )\n result[property.name.text] = await this.evaluateAsync(property.initializer, environment);\n else if (ts.isShorthandPropertyAssignment(property))\n result[property.name.text] = await environment.resolveAsync(property.name.text);\n else throw new Error(`Unsupported static capability property: ${property.getText()}.`);\n }\n return result;\n }\n\n /*** Evaluate a template literal whose substitutions are scalar static values. */\n async templateAsync(\n node: ts.TemplateExpression,\n environment: StaticCatalogScope,\n ): Promise<string> {\n let value = node.head.text;\n for (const span of node.templateSpans) {\n const interpolation = await this.evaluateAsync(span.expression, environment);\n if (typeof interpolation === 'object' && interpolation !== null)\n throw new Error('Capability templates may interpolate only static scalar values.');\n value += `${interpolation}${span.literal.text}`;\n }\n return value;\n }\n\n /*** Evaluate Array.map with a single static arrow-function parameter. */\n async mapAsync(\n node: ts.CallExpression,\n environment: StaticCatalogScope,\n ): Promise<readonly StaticValue[]> {\n if (!ts.isPropertyAccessExpression(node.expression) || node.expression.name.text !== 'map')\n throw new Error(`Unsupported static capability call: ${node.getText()}.`);\n const values = await this.evaluateAsync(node.expression.expression, environment);\n const callback = node.arguments.at(0);\n if (!isStaticArray(values) || callback === undefined || !ts.isArrowFunction(callback))\n throw new Error(`Unsupported static capability map: ${node.getText()}.`);\n const parameter = callback.parameters.at(0);\n const { body } = callback;\n if (parameter === undefined || !ts.isIdentifier(parameter.name) || !ts.isExpression(body))\n throw new Error(`Unsupported static capability map callback: ${callback.getText()}.`);\n const parameterName = parameter.name.text;\n const result: StaticValue[] = [];\n for (const value of values)\n result.push(await this.evaluateAsync(body, environment.withValue(parameterName, value)));\n return result;\n }\n\n /*** Evaluate static array elements in source order. */\n async evaluateElementsAsync(\n elements: ts.NodeArray<ts.Expression | ts.SpreadElement>,\n environment: StaticCatalogScope,\n ): Promise<readonly StaticValue[]> {\n const result: StaticValue[] = [];\n for (const element of elements) {\n if (ts.isSpreadElement(element)) throw new Error('Catalog array spreads are not supported.');\n result.push(await this.evaluateAsync(element, environment));\n }\n return result;\n }\n}\n\n/*** Resolve only static symbols reached from the requested catalog expression. */\nclass StaticCatalogScope {\n constructor(\n private readonly resolver: StaticCatalogResolver,\n private readonly source: ts.SourceFile,\n private readonly modulePath: string,\n private readonly packageRoot: string,\n private readonly values: ReadonlyMap<string, StaticValue> = new Map(),\n ) {}\n\n /*** Resolve a local constant or an allowed named static package import. */\n async resolveAsync(name: string): Promise<StaticValue> {\n const value = this.values.get(name);\n if (value !== undefined) return value;\n const declaration = findStaticDeclaration(this.source, name);\n const initializer = declaration?.initializer;\n if (initializer !== undefined)\n return this.resolver.resolveSymbolAsync(`${this.modulePath}:${name}`, () =>\n this.resolver.evaluateAsync(initializer, this),\n );\n const imported = findImportBinding(this.source, name);\n if (imported === undefined) throw new Error(`Unsupported dynamic capability value: ${name}.`);\n if (!ts.isStringLiteral(imported.moduleSpecifier))\n throw new Error('Capability catalogs support only named local value imports.');\n const bindings = imported.importClause?.namedBindings;\n if (imported.importClause?.isTypeOnly || bindings === undefined)\n throw new Error(`Unsupported dynamic capability value: ${name}.`);\n if (!ts.isNamedImports(bindings))\n throw new Error('Capability catalogs support only named local value imports.');\n const binding = bindings.elements.find(\n (element) => !element.isTypeOnly && element.name.text === name,\n );\n if (binding === undefined) throw new Error(`Unsupported dynamic capability value: ${name}.`);\n const resolvedImport = await resolveImportPathAsync(\n this.packageRoot,\n this.modulePath,\n imported.moduleSpecifier.text,\n );\n return this.resolver.resolveAsync(\n resolvedImport.path,\n binding.propertyName?.text ?? binding.name.text,\n resolvedImport.packageRoot,\n );\n }\n\n /*** Add a static callback parameter without evaluating unrelated module symbols. */\n withValue(name: string, value: StaticValue): StaticCatalogScope {\n return new StaticCatalogScope(\n this.resolver,\n this.source,\n this.modulePath,\n this.packageRoot,\n new Map([...this.values, [name, value]]),\n );\n }\n}\n\n/*** Find the static top-level declaration that owns a local identifier. */\nfunction findStaticDeclaration(\n source: ts.SourceFile,\n name: string,\n): ts.VariableDeclaration | undefined {\n return source.statements\n .filter((statement): statement is ts.VariableStatement => ts.isVariableStatement(statement))\n .filter((statement) => isConstDeclaration(statement.declarationList))\n .flatMap((statement) => statement.declarationList.declarations)\n .find((declaration) => ts.isIdentifier(declaration.name) && declaration.name.text === name);\n}\n\n/*** Find the import declaration that introduces a referenced local identifier. */\nfunction findImportBinding(source: ts.SourceFile, name: string): ts.ImportDeclaration | undefined {\n return source.statements\n .filter((statement): statement is ts.ImportDeclaration => ts.isImportDeclaration(statement))\n .find((statement) => {\n const clause = statement.importClause;\n return (\n clause?.name?.text === name ||\n (clause?.namedBindings !== undefined &&\n ts.isNamedImports(clause.namedBindings) &&\n clause.namedBindings.elements.some((element) => element.name.text === name))\n );\n });\n}\n\n/*** Determine whether a declaration list is immutable static catalog input. */\nfunction isConstDeclaration(list: ts.VariableDeclarationList): boolean {\n return (list.flags & ts.NodeFlags.Const) !== 0;\n}\n\ninterface ResolvedStaticImport {\n readonly packageRoot: string;\n readonly path: string;\n}\n\n/*** Resolve an allowed static import without executing its target package. */\nasync function resolveImportPathAsync(\n packageRoot: string,\n fromPath: string,\n specifier: string,\n): Promise<ResolvedStaticImport> {\n if (specifier.startsWith('.'))\n return resolveLocalImportPathAsync(packageRoot, fromPath, specifier);\n return resolveContractsCatalogImportAsync(packageRoot, fromPath, specifier);\n}\n\n/*** Resolve a relative static import that remains within its owning package. */\nasync function resolveLocalImportPathAsync(\n packageRoot: string,\n fromPath: string,\n specifier: string,\n): Promise<ResolvedStaticImport> {\n const candidate = path.resolve(path.dirname(fromPath), specifier);\n if (!isInsidePackage(packageRoot, candidate) && candidate !== packageRoot)\n throw new Error('Capability catalogs may not import outside their package.');\n for (const extension of ['', '.ts', '.tsx', '.js', '.mjs', '/index.ts'])\n if (await isFileAsync(`${candidate}${extension}`))\n return { packageRoot, path: `${candidate}${extension}` };\n throw new Error(`Unable to resolve static capability import ${specifier}.`);\n}\n\n/*** Unwrap TypeScript syntax which does not alter a runtime value. */\nfunction unwrapExpression(expression: ts.Expression): ts.Expression {\n return ts.isAsExpression(expression) ||\n ts.isSatisfiesExpression(expression) ||\n ts.isParenthesizedExpression(expression)\n ? unwrapExpression(expression.expression)\n : expression;\n}\n\n/*** Narrow a static value to a descriptor-shaped record. */\nfunction isStaticRecord(value: StaticValue): value is StaticRecord {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/*** Narrow a static value to an array. */\nfunction isStaticArray(value: StaticValue): value is readonly StaticValue[] {\n return Array.isArray(value);\n}\n\n/*** Detect an exported variable statement. */\nfunction hasExportModifier(statement: ts.VariableStatement): boolean {\n return (\n statement.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword) ?? false\n );\n}\n\n/*** Check whether a resolved path remains within the inspected package root. */\nfunction isInsidePackage(packageRoot: string, candidate: string): boolean {\n const relativePath = path.relative(packageRoot, candidate);\n return relativePath !== '' && !relativePath.startsWith(`..${path.sep}`) && relativePath !== '..';\n}\n\n/*** Check whether one candidate is a regular file. */\nasync function isFileAsync(candidate: string): Promise<boolean> {\n try {\n return (await fs.stat(candidate)).isFile();\n } catch {\n return false;\n }\n}\n"]}
@@ -0,0 +1,8 @@
1
+ interface ResolvedContractsImport {
2
+ readonly packageRoot: string;
3
+ readonly path: string;
4
+ }
5
+ /*** Resolve a declared Contracts public export without executing package code. */
6
+ export declare function resolveContractsCatalogImportAsync(packageRoot: string, fromPath: string, specifier: string): Promise<ResolvedContractsImport>;
7
+ export {};
8
+ //# sourceMappingURL=capabilityCatalogContractsImport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilityCatalogContractsImport.d.ts","sourceRoot":"","sources":["../src/capabilityCatalogContractsImport.ts"],"names":[],"mappings":"AAKA,UAAU,uBAAuB;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,kFAAkF;AAClF,wBAAsB,kCAAkC,CACtD,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,uBAAuB,CAAC,CAiBlC"}
@@ -0,0 +1,69 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import { createRequire } from 'node:module';
3
+ import path from 'node:path';
4
+ import { pathToFileURL } from 'node:url';
5
+ /*** Resolve a declared Contracts public export without executing package code. */
6
+ export async function resolveContractsCatalogImportAsync(packageRoot, fromPath, specifier) {
7
+ if (!isContractsPublicSubpath(specifier))
8
+ throw new Error('Capability catalogs may import only local metadata or Contracts public exports.');
9
+ if (!(await hasDeclaredContractsDependencyAsync(packageRoot)))
10
+ throw new Error('Capability catalogs may import Contracts metadata only from a declared dependency.');
11
+ const require = createRequire(pathToFileURL(fromPath));
12
+ const targetPath = require.resolve(specifier);
13
+ const contractsPackageRoot = await findInstalledContractsPackageRootAsync(targetPath);
14
+ if (!isInsidePackage(contractsPackageRoot, targetPath))
15
+ throw new Error('Contracts public exports must resolve within the installed Contracts package.');
16
+ return { packageRoot: contractsPackageRoot, path: targetPath };
17
+ }
18
+ /*** Find the installed Contracts package that owns a resolved public export. */
19
+ async function findInstalledContractsPackageRootAsync(targetPath) {
20
+ return findContractsPackageRootAsync(path.dirname(targetPath));
21
+ }
22
+ /*** Walk parent directories until the Contracts package manifest establishes the boundary. */
23
+ async function findContractsPackageRootAsync(candidate) {
24
+ if (candidate === path.dirname(candidate))
25
+ throw new Error('Unable to find the installed Contracts package for its public export.');
26
+ try {
27
+ const packageMetadata = JSON.parse(await fs.readFile(path.join(candidate, 'package.json'), 'utf8'));
28
+ if (isUnknownRecord(packageMetadata) && packageMetadata.name === '@ankhorage/contracts')
29
+ return candidate;
30
+ }
31
+ catch {
32
+ // Only an actual package root establishes the trusted external boundary.
33
+ }
34
+ return findContractsPackageRootAsync(path.dirname(candidate));
35
+ }
36
+ /*** Check whether a specifier names an explicitly exported Contracts subpath. */
37
+ function isContractsPublicSubpath(specifier) {
38
+ return /^@ankhorage\/contracts\/[^/]+$/.test(specifier);
39
+ }
40
+ /*** Check whether the inspected package declares its Contracts dependency. */
41
+ async function hasDeclaredContractsDependencyAsync(packageRoot) {
42
+ try {
43
+ const packageMetadata = JSON.parse(await fs.readFile(path.join(packageRoot, 'package.json'), 'utf8'));
44
+ return hasContractsDependency(packageMetadata);
45
+ }
46
+ catch {
47
+ return false;
48
+ }
49
+ }
50
+ /*** Check standard runtime dependency declarations for Contracts. */
51
+ function hasContractsDependency(packageMetadata) {
52
+ if (!isUnknownRecord(packageMetadata))
53
+ return false;
54
+ return [
55
+ packageMetadata.dependencies,
56
+ packageMetadata.optionalDependencies,
57
+ packageMetadata.peerDependencies,
58
+ ].some((dependencies) => isUnknownRecord(dependencies) && typeof dependencies['@ankhorage/contracts'] === 'string');
59
+ }
60
+ /*** Check whether a resolved export remains within its installed package. */
61
+ function isInsidePackage(packageRoot, candidate) {
62
+ const relativePath = path.relative(packageRoot, candidate);
63
+ return relativePath !== '' && !relativePath.startsWith(`..${path.sep}`) && relativePath !== '..';
64
+ }
65
+ /*** Narrow an unknown value to a record without accepting arrays. */
66
+ function isUnknownRecord(value) {
67
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
68
+ }
69
+ //# sourceMappingURL=capabilityCatalogContractsImport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilityCatalogContractsImport.js","sourceRoot":"","sources":["../src/capabilityCatalogContractsImport.ts"],"names":[],"mappings":"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","sourcesContent":["import { promises as fs } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\ninterface ResolvedContractsImport {\n readonly packageRoot: string;\n readonly path: string;\n}\n\n/*** Resolve a declared Contracts public export without executing package code. */\nexport async function resolveContractsCatalogImportAsync(\n packageRoot: string,\n fromPath: string,\n specifier: string,\n): Promise<ResolvedContractsImport> {\n if (!isContractsPublicSubpath(specifier))\n throw new Error(\n 'Capability catalogs may import only local metadata or Contracts public exports.',\n );\n if (!(await hasDeclaredContractsDependencyAsync(packageRoot)))\n throw new Error(\n 'Capability catalogs may import Contracts metadata only from a declared dependency.',\n );\n const require = createRequire(pathToFileURL(fromPath));\n const targetPath = require.resolve(specifier);\n const contractsPackageRoot = await findInstalledContractsPackageRootAsync(targetPath);\n if (!isInsidePackage(contractsPackageRoot, targetPath))\n throw new Error(\n 'Contracts public exports must resolve within the installed Contracts package.',\n );\n return { packageRoot: contractsPackageRoot, path: targetPath };\n}\n\n/*** Find the installed Contracts package that owns a resolved public export. */\nasync function findInstalledContractsPackageRootAsync(targetPath: string): Promise<string> {\n return findContractsPackageRootAsync(path.dirname(targetPath));\n}\n\n/*** Walk parent directories until the Contracts package manifest establishes the boundary. */\nasync function findContractsPackageRootAsync(candidate: string): Promise<string> {\n if (candidate === path.dirname(candidate))\n throw new Error('Unable to find the installed Contracts package for its public export.');\n try {\n const packageMetadata: unknown = JSON.parse(\n await fs.readFile(path.join(candidate, 'package.json'), 'utf8'),\n );\n if (isUnknownRecord(packageMetadata) && packageMetadata.name === '@ankhorage/contracts')\n return candidate;\n } catch {\n // Only an actual package root establishes the trusted external boundary.\n }\n return findContractsPackageRootAsync(path.dirname(candidate));\n}\n\n/*** Check whether a specifier names an explicitly exported Contracts subpath. */\nfunction isContractsPublicSubpath(specifier: string): boolean {\n return /^@ankhorage\\/contracts\\/[^/]+$/.test(specifier);\n}\n\n/*** Check whether the inspected package declares its Contracts dependency. */\nasync function hasDeclaredContractsDependencyAsync(packageRoot: string): Promise<boolean> {\n try {\n const packageMetadata: unknown = JSON.parse(\n await fs.readFile(path.join(packageRoot, 'package.json'), 'utf8'),\n );\n return hasContractsDependency(packageMetadata);\n } catch {\n return false;\n }\n}\n\n/*** Check standard runtime dependency declarations for Contracts. */\nfunction hasContractsDependency(packageMetadata: unknown): boolean {\n if (!isUnknownRecord(packageMetadata)) return false;\n return [\n packageMetadata.dependencies,\n packageMetadata.optionalDependencies,\n packageMetadata.peerDependencies,\n ].some(\n (dependencies) =>\n isUnknownRecord(dependencies) && typeof dependencies['@ankhorage/contracts'] === 'string',\n );\n}\n\n/*** Check whether a resolved export remains within its installed package. */\nfunction isInsidePackage(packageRoot: string, candidate: string): boolean {\n const relativePath = path.relative(packageRoot, candidate);\n return relativePath !== '' && !relativePath.startsWith(`..${path.sep}`) && relativePath !== '..';\n}\n\n/*** Narrow an unknown value to a record without accepting arrays. */\nfunction isUnknownRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ankhorage/doctor",
3
- "version": "0.14.9",
3
+ "version": "0.14.11",
4
4
  "description": "Executable Ankh provider and standalone CLI for lightweight repo and package compliance diagnostics.",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -136,13 +136,13 @@
136
136
  "@ankhorage/dependency-graph": "^1.3.0",
137
137
  "@ankhorage/rules-architecture": "^0.6.0",
138
138
  "@ankhorage/rules-repository": "^0.2.0",
139
- "@ankhorage/supabase-auth": "^1.2.42",
139
+ "@ankhorage/supabase-auth": "^1.2.43",
140
140
  "@ankhorage/utility": "^1.9.85"
141
141
  },
142
142
  "devDependencies": {
143
143
  "@ankhorage/ankh": "^0.13.0",
144
- "@ankhorage/devtools": "^2.3.9",
145
- "@ankhorage/paradox": "^0.3.2",
144
+ "@ankhorage/devtools": "^2.3.10",
145
+ "@ankhorage/paradox": "^0.3.3",
146
146
  "@types/bun": "^1.4.2",
147
147
  "@types/node": "^26.6.5",
148
148
  "typescript": "^6.0.3"
@@ -3,6 +3,8 @@ import path from 'node:path';
3
3
 
4
4
  import * as ts from 'typescript';
5
5
 
6
+ import { resolveContractsCatalogImportAsync } from './capabilityCatalogContractsImport.js';
7
+
6
8
  type StaticValue = string | number | boolean | null | readonly StaticValue[] | StaticRecord;
7
9
  interface StaticRecord {
8
10
  readonly [key: string]: StaticValue;
@@ -25,9 +27,15 @@ class StaticCatalogResolver {
25
27
  constructor(private readonly packageRoot: string) {}
26
28
 
27
29
  /*** Resolve a named local export without importing or running its module. */
28
- async resolveAsync(modulePath: string, exportName: string): Promise<StaticValue> {
30
+ async resolveAsync(
31
+ modulePath: string,
32
+ exportName: string,
33
+ moduleRoot = this.packageRoot,
34
+ ): Promise<StaticValue> {
29
35
  const key = `${modulePath}:${exportName}`;
30
- return this.resolveSymbolAsync(key, () => this.resolveUncachedAsync(modulePath, exportName));
36
+ return this.resolveSymbolAsync(key, () =>
37
+ this.resolveUncachedAsync(modulePath, exportName, moduleRoot),
38
+ );
31
39
  }
32
40
 
33
41
  /*** Resolve one local symbol while detecting recursive static references. */
@@ -53,7 +61,11 @@ class StaticCatalogResolver {
53
61
  }
54
62
 
55
63
  /*** Find and evaluate the declaration owning one exported static value. */
56
- async resolveUncachedAsync(modulePath: string, exportName: string): Promise<StaticValue> {
64
+ async resolveUncachedAsync(
65
+ modulePath: string,
66
+ exportName: string,
67
+ moduleRoot: string,
68
+ ): Promise<StaticValue> {
57
69
  const source = ts.createSourceFile(
58
70
  modulePath,
59
71
  await fs.readFile(modulePath, 'utf8'),
@@ -70,7 +82,7 @@ class StaticCatalogResolver {
70
82
  throw new Error(`Unable to find static export ${exportName} in ${modulePath}.`);
71
83
  return this.evaluateAsync(
72
84
  declaration.initializer,
73
- new StaticCatalogScope(this, source, modulePath, this.packageRoot),
85
+ new StaticCatalogScope(this, source, modulePath, moduleRoot),
74
86
  );
75
87
  }
76
88
 
@@ -186,7 +198,7 @@ class StaticCatalogScope {
186
198
  private readonly values: ReadonlyMap<string, StaticValue> = new Map(),
187
199
  ) {}
188
200
 
189
- /*** Resolve a local constant or named local import when it is referenced. */
201
+ /*** Resolve a local constant or an allowed named static package import. */
190
202
  async resolveAsync(name: string): Promise<StaticValue> {
191
203
  const value = this.values.get(name);
192
204
  if (value !== undefined) return value;
@@ -209,12 +221,16 @@ class StaticCatalogScope {
209
221
  (element) => !element.isTypeOnly && element.name.text === name,
210
222
  );
211
223
  if (binding === undefined) throw new Error(`Unsupported dynamic capability value: ${name}.`);
212
- const importPath = await resolveImportPathAsync(
224
+ const resolvedImport = await resolveImportPathAsync(
213
225
  this.packageRoot,
214
226
  this.modulePath,
215
227
  imported.moduleSpecifier.text,
216
228
  );
217
- return this.resolver.resolveAsync(importPath, binding.propertyName?.text ?? binding.name.text);
229
+ return this.resolver.resolveAsync(
230
+ resolvedImport.path,
231
+ binding.propertyName?.text ?? binding.name.text,
232
+ resolvedImport.packageRoot,
233
+ );
218
234
  }
219
235
 
220
236
  /*** Add a static callback parameter without evaluating unrelated module symbols. */
@@ -261,19 +277,34 @@ function isConstDeclaration(list: ts.VariableDeclarationList): boolean {
261
277
  return (list.flags & ts.NodeFlags.Const) !== 0;
262
278
  }
263
279
 
264
- /*** Resolve a local import to one source file inside the inspected package. */
280
+ interface ResolvedStaticImport {
281
+ readonly packageRoot: string;
282
+ readonly path: string;
283
+ }
284
+
285
+ /*** Resolve an allowed static import without executing its target package. */
265
286
  async function resolveImportPathAsync(
266
287
  packageRoot: string,
267
288
  fromPath: string,
268
289
  specifier: string,
269
- ): Promise<string> {
270
- if (!specifier.startsWith('.'))
271
- throw new Error('Capability catalogs may import only local static metadata.');
290
+ ): Promise<ResolvedStaticImport> {
291
+ if (specifier.startsWith('.'))
292
+ return resolveLocalImportPathAsync(packageRoot, fromPath, specifier);
293
+ return resolveContractsCatalogImportAsync(packageRoot, fromPath, specifier);
294
+ }
295
+
296
+ /*** Resolve a relative static import that remains within its owning package. */
297
+ async function resolveLocalImportPathAsync(
298
+ packageRoot: string,
299
+ fromPath: string,
300
+ specifier: string,
301
+ ): Promise<ResolvedStaticImport> {
272
302
  const candidate = path.resolve(path.dirname(fromPath), specifier);
273
303
  if (!isInsidePackage(packageRoot, candidate) && candidate !== packageRoot)
274
304
  throw new Error('Capability catalogs may not import outside their package.');
275
305
  for (const extension of ['', '.ts', '.tsx', '.js', '.mjs', '/index.ts'])
276
- if (await isFileAsync(`${candidate}${extension}`)) return `${candidate}${extension}`;
306
+ if (await isFileAsync(`${candidate}${extension}`))
307
+ return { packageRoot, path: `${candidate}${extension}` };
277
308
  throw new Error(`Unable to resolve static capability import ${specifier}.`);
278
309
  }
279
310
 
@@ -0,0 +1,95 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import { createRequire } from 'node:module';
3
+ import path from 'node:path';
4
+ import { pathToFileURL } from 'node:url';
5
+
6
+ interface ResolvedContractsImport {
7
+ readonly packageRoot: string;
8
+ readonly path: string;
9
+ }
10
+
11
+ /*** Resolve a declared Contracts public export without executing package code. */
12
+ export async function resolveContractsCatalogImportAsync(
13
+ packageRoot: string,
14
+ fromPath: string,
15
+ specifier: string,
16
+ ): Promise<ResolvedContractsImport> {
17
+ if (!isContractsPublicSubpath(specifier))
18
+ throw new Error(
19
+ 'Capability catalogs may import only local metadata or Contracts public exports.',
20
+ );
21
+ if (!(await hasDeclaredContractsDependencyAsync(packageRoot)))
22
+ throw new Error(
23
+ 'Capability catalogs may import Contracts metadata only from a declared dependency.',
24
+ );
25
+ const require = createRequire(pathToFileURL(fromPath));
26
+ const targetPath = require.resolve(specifier);
27
+ const contractsPackageRoot = await findInstalledContractsPackageRootAsync(targetPath);
28
+ if (!isInsidePackage(contractsPackageRoot, targetPath))
29
+ throw new Error(
30
+ 'Contracts public exports must resolve within the installed Contracts package.',
31
+ );
32
+ return { packageRoot: contractsPackageRoot, path: targetPath };
33
+ }
34
+
35
+ /*** Find the installed Contracts package that owns a resolved public export. */
36
+ async function findInstalledContractsPackageRootAsync(targetPath: string): Promise<string> {
37
+ return findContractsPackageRootAsync(path.dirname(targetPath));
38
+ }
39
+
40
+ /*** Walk parent directories until the Contracts package manifest establishes the boundary. */
41
+ async function findContractsPackageRootAsync(candidate: string): Promise<string> {
42
+ if (candidate === path.dirname(candidate))
43
+ throw new Error('Unable to find the installed Contracts package for its public export.');
44
+ try {
45
+ const packageMetadata: unknown = JSON.parse(
46
+ await fs.readFile(path.join(candidate, 'package.json'), 'utf8'),
47
+ );
48
+ if (isUnknownRecord(packageMetadata) && packageMetadata.name === '@ankhorage/contracts')
49
+ return candidate;
50
+ } catch {
51
+ // Only an actual package root establishes the trusted external boundary.
52
+ }
53
+ return findContractsPackageRootAsync(path.dirname(candidate));
54
+ }
55
+
56
+ /*** Check whether a specifier names an explicitly exported Contracts subpath. */
57
+ function isContractsPublicSubpath(specifier: string): boolean {
58
+ return /^@ankhorage\/contracts\/[^/]+$/.test(specifier);
59
+ }
60
+
61
+ /*** Check whether the inspected package declares its Contracts dependency. */
62
+ async function hasDeclaredContractsDependencyAsync(packageRoot: string): Promise<boolean> {
63
+ try {
64
+ const packageMetadata: unknown = JSON.parse(
65
+ await fs.readFile(path.join(packageRoot, 'package.json'), 'utf8'),
66
+ );
67
+ return hasContractsDependency(packageMetadata);
68
+ } catch {
69
+ return false;
70
+ }
71
+ }
72
+
73
+ /*** Check standard runtime dependency declarations for Contracts. */
74
+ function hasContractsDependency(packageMetadata: unknown): boolean {
75
+ if (!isUnknownRecord(packageMetadata)) return false;
76
+ return [
77
+ packageMetadata.dependencies,
78
+ packageMetadata.optionalDependencies,
79
+ packageMetadata.peerDependencies,
80
+ ].some(
81
+ (dependencies) =>
82
+ isUnknownRecord(dependencies) && typeof dependencies['@ankhorage/contracts'] === 'string',
83
+ );
84
+ }
85
+
86
+ /*** Check whether a resolved export remains within its installed package. */
87
+ function isInsidePackage(packageRoot: string, candidate: string): boolean {
88
+ const relativePath = path.relative(packageRoot, candidate);
89
+ return relativePath !== '' && !relativePath.startsWith(`..${path.sep}`) && relativePath !== '..';
90
+ }
91
+
92
+ /*** Narrow an unknown value to a record without accepting arrays. */
93
+ function isUnknownRecord(value: unknown): value is Record<string, unknown> {
94
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
95
+ }