@ankhorage/doctor 0.14.11 → 0.14.12

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.
@@ -1,18 +1,21 @@
1
1
  import { promises as fs } from 'node:fs';
2
- import path from 'node:path';
3
2
  import * as ts from 'typescript';
4
- import { resolveContractsCatalogImportAsync } from './capabilityCatalogContractsImport.js';
3
+ import { findImportBinding, findStaticDeclaration, hasExportModifier, isConstDeclaration, unwrapExpression, } from './capabilityCatalogAstSource.js';
4
+ import { resolveImportPathAsync, resolveLocalImportPathAsync } from './capabilityCatalogImport.js';
5
+ import { isStaticArray, isStaticRecord, readStaticArray, readStaticProperty, } from './capabilityCatalogStaticValue.js';
5
6
  /*** Evaluate one named catalog export from the supported static TypeScript subset. */
6
- export async function capabilityCatalogAstAsync(packageRoot, modulePath, exportName) {
7
- return new StaticCatalogResolver(packageRoot).resolveAsync(modulePath, exportName);
7
+ export async function capabilityCatalogAstAsync(packageRoot, modulePath, exportName, materializedCatalog) {
8
+ return new StaticCatalogResolver(packageRoot, materializedCatalog).resolveAsync(modulePath, exportName);
8
9
  }
9
10
  /*** Resolve static local imports and expressions without loading target modules. */
10
11
  class StaticCatalogResolver {
11
12
  packageRoot;
12
13
  #symbols = new Map();
13
14
  #activeSymbols = [];
14
- constructor(packageRoot) {
15
+ materializedCatalog;
16
+ constructor(packageRoot, materializedCatalog) {
15
17
  this.packageRoot = packageRoot;
18
+ this.materializedCatalog = readStaticArray(materializedCatalog);
16
19
  }
17
20
  /*** Resolve a named local export without importing or running its module. */
18
21
  async resolveAsync(modulePath, exportName, moduleRoot = this.packageRoot) {
@@ -65,6 +68,8 @@ class StaticCatalogResolver {
65
68
  return null;
66
69
  if (ts.isIdentifier(node))
67
70
  return environment.resolveAsync(node.text);
71
+ if (ts.isPropertyAccessExpression(node))
72
+ return this.propertyAccessAsync(node, environment);
68
73
  if (ts.isArrayLiteralExpression(node))
69
74
  return this.arrayAsync(node, environment);
70
75
  if (ts.isObjectLiteralExpression(node))
@@ -75,6 +80,20 @@ class StaticCatalogResolver {
75
80
  return this.mapAsync(node, environment);
76
81
  throw new Error(`Unsupported static capability expression: ${node.getText()}.`);
77
82
  }
83
+ /*** Evaluate one static object property while preserving dynamic-expression diagnostics. */
84
+ async propertyAccessAsync(node, environment) {
85
+ try {
86
+ return readStaticProperty(await this.evaluateAsync(node.expression, environment), node.name.text, node.getText());
87
+ }
88
+ catch (error) {
89
+ if (error instanceof Error &&
90
+ error.message.startsWith('Unsupported dynamic capability value:'))
91
+ throw new Error(`Unsupported static capability expression: ${node.getText()}.`, {
92
+ cause: error,
93
+ });
94
+ throw error;
95
+ }
96
+ }
78
97
  /*** Evaluate a static array literal. */
79
98
  arrayAsync(node, environment) {
80
99
  return this.evaluateElementsAsync(node.elements, environment);
@@ -131,10 +150,21 @@ class StaticCatalogResolver {
131
150
  /*** Evaluate static array elements in source order. */
132
151
  async evaluateElementsAsync(elements, environment) {
133
152
  const result = [];
134
- for (const element of elements) {
135
- if (ts.isSpreadElement(element))
136
- throw new Error('Catalog array spreads are not supported.');
137
- result.push(await this.evaluateAsync(element, environment));
153
+ for (const [index, element] of elements.entries()) {
154
+ if (ts.isSpreadElement(element)) {
155
+ if (await environment.isPackageLocalDerivedCallAsync(element.expression)) {
156
+ if (index !== elements.length - 1 || this.materializedCatalog === null)
157
+ throw new Error('Derived catalog function spreads must be trailing and have materialized package metadata.');
158
+ result.push(...this.materializedCatalog.slice(result.length));
159
+ continue;
160
+ }
161
+ const spread = await this.evaluateAsync(element.expression, environment);
162
+ if (!isStaticArray(spread))
163
+ throw new Error('Catalog array spreads must resolve to static arrays.');
164
+ result.push(...spread);
165
+ }
166
+ else
167
+ result.push(await this.evaluateAsync(element, environment));
138
168
  }
139
169
  return result;
140
170
  }
@@ -178,83 +208,24 @@ class StaticCatalogScope {
178
208
  const resolvedImport = await resolveImportPathAsync(this.packageRoot, this.modulePath, imported.moduleSpecifier.text);
179
209
  return this.resolver.resolveAsync(resolvedImport.path, binding.propertyName?.text ?? binding.name.text, resolvedImport.packageRoot);
180
210
  }
211
+ /*** Detect one zero-argument function imported from a package-local source module. */
212
+ async isPackageLocalDerivedCallAsync(expression) {
213
+ const node = unwrapExpression(expression);
214
+ if (!ts.isCallExpression(node) ||
215
+ node.arguments.length !== 0 ||
216
+ !ts.isIdentifier(node.expression))
217
+ return false;
218
+ const imported = findImportBinding(this.source, node.expression.text);
219
+ if (imported === undefined ||
220
+ !ts.isStringLiteral(imported.moduleSpecifier) ||
221
+ !imported.moduleSpecifier.text.startsWith('.'))
222
+ return false;
223
+ await resolveLocalImportPathAsync(this.packageRoot, this.modulePath, imported.moduleSpecifier.text);
224
+ return true;
225
+ }
181
226
  /*** Add a static callback parameter without evaluating unrelated module symbols. */
182
227
  withValue(name, value) {
183
228
  return new StaticCatalogScope(this.resolver, this.source, this.modulePath, this.packageRoot, new Map([...this.values, [name, value]]));
184
229
  }
185
230
  }
186
- /*** Find the static top-level declaration that owns a local identifier. */
187
- function findStaticDeclaration(source, name) {
188
- return source.statements
189
- .filter((statement) => ts.isVariableStatement(statement))
190
- .filter((statement) => isConstDeclaration(statement.declarationList))
191
- .flatMap((statement) => statement.declarationList.declarations)
192
- .find((declaration) => ts.isIdentifier(declaration.name) && declaration.name.text === name);
193
- }
194
- /*** Find the import declaration that introduces a referenced local identifier. */
195
- function findImportBinding(source, name) {
196
- return source.statements
197
- .filter((statement) => ts.isImportDeclaration(statement))
198
- .find((statement) => {
199
- const clause = statement.importClause;
200
- return (clause?.name?.text === name ||
201
- (clause?.namedBindings !== undefined &&
202
- ts.isNamedImports(clause.namedBindings) &&
203
- clause.namedBindings.elements.some((element) => element.name.text === name)));
204
- });
205
- }
206
- /*** Determine whether a declaration list is immutable static catalog input. */
207
- function isConstDeclaration(list) {
208
- return (list.flags & ts.NodeFlags.Const) !== 0;
209
- }
210
- /*** Resolve an allowed static import without executing its target package. */
211
- async function resolveImportPathAsync(packageRoot, fromPath, specifier) {
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) {
218
- const candidate = path.resolve(path.dirname(fromPath), specifier);
219
- if (!isInsidePackage(packageRoot, candidate) && candidate !== packageRoot)
220
- throw new Error('Capability catalogs may not import outside their package.');
221
- for (const extension of ['', '.ts', '.tsx', '.js', '.mjs', '/index.ts'])
222
- if (await isFileAsync(`${candidate}${extension}`))
223
- return { packageRoot, path: `${candidate}${extension}` };
224
- throw new Error(`Unable to resolve static capability import ${specifier}.`);
225
- }
226
- /*** Unwrap TypeScript syntax which does not alter a runtime value. */
227
- function unwrapExpression(expression) {
228
- return ts.isAsExpression(expression) ||
229
- ts.isSatisfiesExpression(expression) ||
230
- ts.isParenthesizedExpression(expression)
231
- ? unwrapExpression(expression.expression)
232
- : expression;
233
- }
234
- /*** Narrow a static value to a descriptor-shaped record. */
235
- function isStaticRecord(value) {
236
- return typeof value === 'object' && value !== null && !Array.isArray(value);
237
- }
238
- /*** Narrow a static value to an array. */
239
- function isStaticArray(value) {
240
- return Array.isArray(value);
241
- }
242
- /*** Detect an exported variable statement. */
243
- function hasExportModifier(statement) {
244
- return (statement.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword) ?? false);
245
- }
246
- /*** Check whether a resolved path remains within the inspected package root. */
247
- function isInsidePackage(packageRoot, candidate) {
248
- const relativePath = path.relative(packageRoot, candidate);
249
- return relativePath !== '' && !relativePath.startsWith(`..${path.sep}`) && relativePath !== '..';
250
- }
251
- /*** Check whether one candidate is a regular file. */
252
- async function isFileAsync(candidate) {
253
- try {
254
- return (await fs.stat(candidate)).isFile();
255
- }
256
- catch {
257
- return false;
258
- }
259
- }
260
231
  //# sourceMappingURL=capabilityCatalogAst.js.map
@@ -1 +1 @@
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"]}
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';\n\nimport * as ts from 'typescript';\n\nimport {\n findImportBinding,\n findStaticDeclaration,\n hasExportModifier,\n isConstDeclaration,\n unwrapExpression,\n} from './capabilityCatalogAstSource.js';\nimport { resolveImportPathAsync, resolveLocalImportPathAsync } from './capabilityCatalogImport.js';\nimport {\n isStaticArray,\n isStaticRecord,\n readStaticArray,\n readStaticProperty,\n type StaticRecord,\n type StaticValue,\n} from './capabilityCatalogStaticValue.js';\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 materializedCatalog?: unknown,\n): Promise<unknown> {\n return new StaticCatalogResolver(packageRoot, materializedCatalog).resolveAsync(\n modulePath,\n exportName,\n );\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 private readonly materializedCatalog: readonly StaticValue[] | null;\n\n constructor(\n private readonly packageRoot: string,\n materializedCatalog?: unknown,\n ) {\n this.materializedCatalog = readStaticArray(materializedCatalog);\n }\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.isPropertyAccessExpression(node)) return this.propertyAccessAsync(node, environment);\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 one static object property while preserving dynamic-expression diagnostics. */\n async propertyAccessAsync(\n node: ts.PropertyAccessExpression,\n environment: StaticCatalogScope,\n ): Promise<StaticValue> {\n try {\n return readStaticProperty(\n await this.evaluateAsync(node.expression, environment),\n node.name.text,\n node.getText(),\n );\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.startsWith('Unsupported dynamic capability value:')\n )\n throw new Error(`Unsupported static capability expression: ${node.getText()}.`, {\n cause: error,\n });\n throw error;\n }\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 [index, element] of elements.entries()) {\n if (ts.isSpreadElement(element)) {\n if (await environment.isPackageLocalDerivedCallAsync(element.expression)) {\n if (index !== elements.length - 1 || this.materializedCatalog === null)\n throw new Error(\n 'Derived catalog function spreads must be trailing and have materialized package metadata.',\n );\n result.push(...this.materializedCatalog.slice(result.length));\n continue;\n }\n const spread = await this.evaluateAsync(element.expression, environment);\n if (!isStaticArray(spread))\n throw new Error('Catalog array spreads must resolve to static arrays.');\n result.push(...spread);\n } else 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 /*** Detect one zero-argument function imported from a package-local source module. */\n async isPackageLocalDerivedCallAsync(expression: ts.Expression): Promise<boolean> {\n const node = unwrapExpression(expression);\n if (\n !ts.isCallExpression(node) ||\n node.arguments.length !== 0 ||\n !ts.isIdentifier(node.expression)\n )\n return false;\n const imported = findImportBinding(this.source, node.expression.text);\n if (\n imported === undefined ||\n !ts.isStringLiteral(imported.moduleSpecifier) ||\n !imported.moduleSpecifier.text.startsWith('.')\n )\n return false;\n await resolveLocalImportPathAsync(\n this.packageRoot,\n this.modulePath,\n imported.moduleSpecifier.text,\n );\n return true;\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"]}
@@ -0,0 +1,12 @@
1
+ import * as ts from 'typescript';
2
+ /*** Find the static top-level declaration that owns a local identifier. */
3
+ export declare function findStaticDeclaration(source: ts.SourceFile, name: string): ts.VariableDeclaration | undefined;
4
+ /*** Find the import declaration that introduces a referenced local identifier. */
5
+ export declare function findImportBinding(source: ts.SourceFile, name: string): ts.ImportDeclaration | undefined;
6
+ /*** Determine whether a declaration list is immutable static catalog input. */
7
+ export declare function isConstDeclaration(list: ts.VariableDeclarationList): boolean;
8
+ /*** Unwrap TypeScript syntax which does not alter a runtime value. */
9
+ export declare function unwrapExpression(expression: ts.Expression): ts.Expression;
10
+ /*** Detect an exported variable statement. */
11
+ export declare function hasExportModifier(statement: ts.VariableStatement): boolean;
12
+ //# sourceMappingURL=capabilityCatalogAstSource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilityCatalogAstSource.d.ts","sourceRoot":"","sources":["../src/capabilityCatalogAstSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAEjC,2EAA2E;AAC3E,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,EAAE,CAAC,UAAU,EACrB,IAAI,EAAE,MAAM,GACX,EAAE,CAAC,mBAAmB,GAAG,SAAS,CAMpC;AAED,kFAAkF;AAClF,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,EAAE,CAAC,UAAU,EACrB,IAAI,EAAE,MAAM,GACX,EAAE,CAAC,iBAAiB,GAAG,SAAS,CAYlC;AAED,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,EAAE,CAAC,uBAAuB,GAAG,OAAO,CAE5E;AAED,sEAAsE;AACtE,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,GAAG,EAAE,CAAC,UAAU,CAMzE;AAED,8CAA8C;AAC9C,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,EAAE,CAAC,iBAAiB,GAAG,OAAO,CAI1E"}
@@ -0,0 +1,38 @@
1
+ import * as ts from 'typescript';
2
+ /*** Find the static top-level declaration that owns a local identifier. */
3
+ export function findStaticDeclaration(source, name) {
4
+ return source.statements
5
+ .filter((statement) => ts.isVariableStatement(statement))
6
+ .filter((statement) => isConstDeclaration(statement.declarationList))
7
+ .flatMap((statement) => statement.declarationList.declarations)
8
+ .find((declaration) => ts.isIdentifier(declaration.name) && declaration.name.text === name);
9
+ }
10
+ /*** Find the import declaration that introduces a referenced local identifier. */
11
+ export function findImportBinding(source, name) {
12
+ return source.statements
13
+ .filter((statement) => ts.isImportDeclaration(statement))
14
+ .find((statement) => {
15
+ const clause = statement.importClause;
16
+ return (clause?.name?.text === name ||
17
+ (clause?.namedBindings !== undefined &&
18
+ ts.isNamedImports(clause.namedBindings) &&
19
+ clause.namedBindings.elements.some((element) => element.name.text === name)));
20
+ });
21
+ }
22
+ /*** Determine whether a declaration list is immutable static catalog input. */
23
+ export function isConstDeclaration(list) {
24
+ return (list.flags & ts.NodeFlags.Const) !== 0;
25
+ }
26
+ /*** Unwrap TypeScript syntax which does not alter a runtime value. */
27
+ export function unwrapExpression(expression) {
28
+ return ts.isAsExpression(expression) ||
29
+ ts.isSatisfiesExpression(expression) ||
30
+ ts.isParenthesizedExpression(expression)
31
+ ? unwrapExpression(expression.expression)
32
+ : expression;
33
+ }
34
+ /*** Detect an exported variable statement. */
35
+ export function hasExportModifier(statement) {
36
+ return (statement.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword) ?? false);
37
+ }
38
+ //# sourceMappingURL=capabilityCatalogAstSource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilityCatalogAstSource.js","sourceRoot":"","sources":["../src/capabilityCatalogAstSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAEjC,2EAA2E;AAC3E,MAAM,UAAU,qBAAqB,CACnC,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,MAAM,UAAU,iBAAiB,CAC/B,MAAqB,EACrB,IAAY;IAEZ,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,MAAM,UAAU,kBAAkB,CAAC,IAAgC;IACjE,OAAO,CAAC,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AACjD,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,gBAAgB,CAAC,UAAyB;IACxD,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,8CAA8C;AAC9C,MAAM,UAAU,iBAAiB,CAAC,SAA+B;IAC/D,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","sourcesContent":["import * as ts from 'typescript';\n\n/*** Find the static top-level declaration that owns a local identifier. */\nexport function 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. */\nexport function findImportBinding(\n source: ts.SourceFile,\n name: string,\n): 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. */\nexport function isConstDeclaration(list: ts.VariableDeclarationList): boolean {\n return (list.flags & ts.NodeFlags.Const) !== 0;\n}\n\n/*** Unwrap TypeScript syntax which does not alter a runtime value. */\nexport function 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/*** Detect an exported variable statement. */\nexport function hasExportModifier(statement: ts.VariableStatement): boolean {\n return (\n statement.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword) ?? false\n );\n}\n"]}
@@ -0,0 +1,9 @@
1
+ export interface ResolvedStaticImport {
2
+ readonly packageRoot: string;
3
+ readonly path: string;
4
+ }
5
+ /*** Resolve an allowed static import without executing its target package. */
6
+ export declare function resolveImportPathAsync(packageRoot: string, fromPath: string, specifier: string): Promise<ResolvedStaticImport>;
7
+ /*** Resolve a relative static import that remains within its owning package. */
8
+ export declare function resolveLocalImportPathAsync(packageRoot: string, fromPath: string, specifier: string): Promise<ResolvedStaticImport>;
9
+ //# sourceMappingURL=capabilityCatalogImport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilityCatalogImport.d.ts","sourceRoot":"","sources":["../src/capabilityCatalogImport.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,8EAA8E;AAC9E,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,oBAAoB,CAAC,CAI/B;AAED,gFAAgF;AAChF,wBAAsB,2BAA2B,CAC/C,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,oBAAoB,CAAC,CAQ/B"}
@@ -0,0 +1,34 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { resolveContractsCatalogImportAsync } from './capabilityCatalogContractsImport.js';
4
+ /*** Resolve an allowed static import without executing its target package. */
5
+ export async function resolveImportPathAsync(packageRoot, fromPath, specifier) {
6
+ if (specifier.startsWith('.'))
7
+ return resolveLocalImportPathAsync(packageRoot, fromPath, specifier);
8
+ return resolveContractsCatalogImportAsync(packageRoot, fromPath, specifier);
9
+ }
10
+ /*** Resolve a relative static import that remains within its owning package. */
11
+ export async function resolveLocalImportPathAsync(packageRoot, fromPath, specifier) {
12
+ const candidate = path.resolve(path.dirname(fromPath), specifier);
13
+ if (!isInsidePackage(packageRoot, candidate) && candidate !== packageRoot)
14
+ throw new Error('Capability catalogs may not import outside their package.');
15
+ for (const extension of ['', '.ts', '.tsx', '.js', '.mjs', '/index.ts'])
16
+ if (await isFileAsync(`${candidate}${extension}`))
17
+ return { packageRoot, path: `${candidate}${extension}` };
18
+ throw new Error(`Unable to resolve static capability import ${specifier}.`);
19
+ }
20
+ /*** Check whether a resolved path remains within the inspected package root. */
21
+ function isInsidePackage(packageRoot, candidate) {
22
+ const relativePath = path.relative(packageRoot, candidate);
23
+ return relativePath !== '' && !relativePath.startsWith(`..${path.sep}`) && relativePath !== '..';
24
+ }
25
+ /*** Check whether one candidate is a regular file. */
26
+ async function isFileAsync(candidate) {
27
+ try {
28
+ return (await fs.stat(candidate)).isFile();
29
+ }
30
+ catch {
31
+ return false;
32
+ }
33
+ }
34
+ //# sourceMappingURL=capabilityCatalogImport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilityCatalogImport.js","sourceRoot":"","sources":["../src/capabilityCatalogImport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,kCAAkC,EAAE,MAAM,uCAAuC,CAAC;AAO3F,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,WAAmB,EACnB,QAAgB,EAChB,SAAiB;IAEjB,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC;QAC3B,OAAO,2BAA2B,CAAC,WAAW,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;IACvE,OAAO,kCAAkC,CAAC,WAAW,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;AAC9E,CAAC;AAED,gFAAgF;AAChF,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,WAAmB,EACnB,QAAgB,EAChB,SAAiB;IAEjB,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;YAC/C,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,SAAS,GAAG,SAAS,EAAE,EAAE,CAAC;IAC7D,MAAM,IAAI,KAAK,CAAC,8CAA8C,SAAS,GAAG,CAAC,CAAC;AAC9E,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 { resolveContractsCatalogImportAsync } from './capabilityCatalogContractsImport.js';\n\nexport interface ResolvedStaticImport {\n readonly packageRoot: string;\n readonly path: string;\n}\n\n/*** Resolve an allowed static import without executing its target package. */\nexport async 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. */\nexport async 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/*** 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,13 @@
1
+ export type StaticValue = string | number | boolean | null | readonly StaticValue[] | StaticRecord;
2
+ export interface StaticRecord {
3
+ readonly [key: string]: StaticValue;
4
+ }
5
+ /*** Narrow a static value to a descriptor-shaped record. */
6
+ export declare function isStaticRecord(value: StaticValue): value is StaticRecord;
7
+ /*** Narrow a static value to an array. */
8
+ export declare function isStaticArray(value: StaticValue): value is readonly StaticValue[];
9
+ /*** Read one property from a statically resolved object. */
10
+ export declare function readStaticProperty(value: StaticValue, key: string, expression: string): StaticValue;
11
+ /*** Read one JSON-compatible array as static catalog materialization input. */
12
+ export declare function readStaticArray(value: unknown): readonly StaticValue[] | null;
13
+ //# sourceMappingURL=capabilityCatalogStaticValue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilityCatalogStaticValue.d.ts","sourceRoot":"","sources":["../src/capabilityCatalogStaticValue.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,WAAW,EAAE,GAAG,YAAY,CAAC;AAEnG,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW,CAAC;CACrC;AAED,4DAA4D;AAC5D,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,KAAK,IAAI,YAAY,CAExE;AAED,0CAA0C;AAC1C,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,KAAK,IAAI,SAAS,WAAW,EAAE,CAEjF;AAED,4DAA4D;AAC5D,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,WAAW,EAClB,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,GACjB,WAAW,CAOb;AAED,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,WAAW,EAAE,GAAG,IAAI,CAE7E"}
@@ -0,0 +1,35 @@
1
+ /*** Narrow a static value to a descriptor-shaped record. */
2
+ export function isStaticRecord(value) {
3
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
4
+ }
5
+ /*** Narrow a static value to an array. */
6
+ export function isStaticArray(value) {
7
+ return Array.isArray(value);
8
+ }
9
+ /*** Read one property from a statically resolved object. */
10
+ export function readStaticProperty(value, key, expression) {
11
+ const property = isStaticRecord(value)
12
+ ? Object.entries(value).find(([propertyKey]) => propertyKey === key)?.[1]
13
+ : undefined;
14
+ if (property === undefined)
15
+ throw new Error(`Unsupported static capability property access: ${expression}.`);
16
+ return property;
17
+ }
18
+ /*** Read one JSON-compatible array as static catalog materialization input. */
19
+ export function readStaticArray(value) {
20
+ return Array.isArray(value) && value.every(isStaticValue) ? value : null;
21
+ }
22
+ /*** Narrow untrusted JSON-compatible input to the static evaluator value model. */
23
+ function isStaticValue(value) {
24
+ if (value === null ||
25
+ typeof value === 'string' ||
26
+ typeof value === 'number' ||
27
+ typeof value === 'boolean')
28
+ return true;
29
+ if (Array.isArray(value))
30
+ return value.every(isStaticValue);
31
+ if (typeof value !== 'object')
32
+ return false;
33
+ return Object.values(value).every(isStaticValue);
34
+ }
35
+ //# sourceMappingURL=capabilityCatalogStaticValue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilityCatalogStaticValue.js","sourceRoot":"","sources":["../src/capabilityCatalogStaticValue.ts"],"names":[],"mappings":"AAMA,4DAA4D;AAC5D,MAAM,UAAU,cAAc,CAAC,KAAkB;IAC/C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,0CAA0C;AAC1C,MAAM,UAAU,aAAa,CAAC,KAAkB;IAC9C,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9B,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,kBAAkB,CAChC,KAAkB,EAClB,GAAW,EACX,UAAkB;IAElB,MAAM,QAAQ,GAAG,cAAc,CAAC,KAAK,CAAC;QACpC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,EAAE,CAAC,WAAW,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QACzE,CAAC,CAAC,SAAS,CAAC;IACd,IAAI,QAAQ,KAAK,SAAS;QACxB,MAAM,IAAI,KAAK,CAAC,kDAAkD,UAAU,GAAG,CAAC,CAAC;IACnF,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3E,CAAC;AAED,mFAAmF;AACnF,SAAS,aAAa,CAAC,KAAc;IACnC,IACE,KAAK,KAAK,IAAI;QACd,OAAO,KAAK,KAAK,QAAQ;QACzB,OAAO,KAAK,KAAK,QAAQ;QACzB,OAAO,KAAK,KAAK,SAAS;QAE1B,OAAO,IAAI,CAAC;IACd,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IAC5D,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;AACnD,CAAC","sourcesContent":["export type StaticValue = string | number | boolean | null | readonly StaticValue[] | StaticRecord;\n\nexport interface StaticRecord {\n readonly [key: string]: StaticValue;\n}\n\n/*** Narrow a static value to a descriptor-shaped record. */\nexport function 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. */\nexport function isStaticArray(value: StaticValue): value is readonly StaticValue[] {\n return Array.isArray(value);\n}\n\n/*** Read one property from a statically resolved object. */\nexport function readStaticProperty(\n value: StaticValue,\n key: string,\n expression: string,\n): StaticValue {\n const property = isStaticRecord(value)\n ? Object.entries(value).find(([propertyKey]) => propertyKey === key)?.[1]\n : undefined;\n if (property === undefined)\n throw new Error(`Unsupported static capability property access: ${expression}.`);\n return property;\n}\n\n/*** Read one JSON-compatible array as static catalog materialization input. */\nexport function readStaticArray(value: unknown): readonly StaticValue[] | null {\n return Array.isArray(value) && value.every(isStaticValue) ? value : null;\n}\n\n/*** Narrow untrusted JSON-compatible input to the static evaluator value model. */\nfunction isStaticValue(value: unknown): value is StaticValue {\n if (\n value === null ||\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n )\n return true;\n if (Array.isArray(value)) return value.every(isStaticValue);\n if (typeof value !== 'object') return false;\n return Object.values(value).every(isStaticValue);\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ankhorage/doctor",
3
- "version": "0.14.11",
3
+ "version": "0.14.12",
4
4
  "description": "Executable Ankh provider and standalone CLI for lightweight repo and package compliance diagnostics.",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -141,7 +141,7 @@
141
141
  },
142
142
  "devDependencies": {
143
143
  "@ankhorage/ankh": "^0.13.0",
144
- "@ankhorage/devtools": "^2.3.10",
144
+ "@ankhorage/devtools": "^2.3.11",
145
145
  "@ankhorage/paradox": "^0.3.3",
146
146
  "@types/bun": "^1.4.2",
147
147
  "@types/node": "^26.6.5",
package/src/analysis.ts CHANGED
@@ -57,6 +57,7 @@ export interface DoctorAnalysisResult {
57
57
 
58
58
  interface ProviderInspectionResult {
59
59
  readonly capabilities: readonly Capability[];
60
+ readonly capabilitiesValid: boolean;
60
61
  readonly commandCapabilities: readonly string[];
61
62
  readonly commandPaths: readonly string[];
62
63
  readonly handlerPaths: readonly string[];
@@ -568,7 +569,11 @@ async function validateAnkhMetadataAndProvider(request: {
568
569
  }): Promise<DoctorDiagnostic[]> {
569
570
  const diagnostics: DoctorDiagnostic[] = [];
570
571
  const metadata = request.packageJson.ankh;
571
- const catalog = await readCapabilityCatalogAsync(request.targetPath, request.packageJson.exports);
572
+ const catalog = await readCapabilityCatalogAsync(
573
+ request.targetPath,
574
+ request.packageJson.exports,
575
+ isRecord(metadata) ? metadata.capabilities : undefined,
576
+ );
572
577
  const providerPackage =
573
578
  (isRecord(metadata) && isNonEmptyString(metadata.provider)) ||
574
579
  (await isProviderPackage(request.targetPath));
@@ -714,13 +719,25 @@ async function validateAnkhMetadataAndProvider(request: {
714
719
 
715
720
  const providerCapabilities = inspection.result.capabilities;
716
721
  const commandCapabilities = uniqueSortedStrings(inspection.result.commandCapabilities);
717
-
718
- if (!areCapabilityCatalogsEqual(metadataCapabilities, providerCapabilities)) {
722
+ const providerCapabilitiesMatch =
723
+ inspection.result.capabilitiesValid &&
724
+ (catalog.capabilities === null
725
+ ? catalog.path === null &&
726
+ areCapabilityCatalogsEqual(metadataCapabilities, providerCapabilities)
727
+ : providerCapabilities.every((providerCapability) =>
728
+ catalog.capabilities.some((catalogCapability) =>
729
+ areCapabilityCatalogsEqual([providerCapability], [catalogCapability]),
730
+ ),
731
+ ));
732
+
733
+ if (!providerCapabilitiesMatch) {
719
734
  diagnostics.push(
720
735
  createDiagnostic({
721
736
  code: 'field-invalid',
722
737
  message:
723
- 'package.json.ankh capabilities must match the implemented provider capability descriptors exactly.',
738
+ catalog.capabilities === null && catalog.path === null
739
+ ? 'package.json.ankh capabilities must match the implemented provider capability descriptors exactly.'
740
+ : 'Provider capabilities must be valid, unique descriptors contained identically in the canonical public CAPABILITIES catalog.',
724
741
  path: request.packageJsonPath,
725
742
  profile: request.profile,
726
743
  ruleId: 'package.ankh.capabilities.match-provider',
@@ -806,6 +823,7 @@ async function inspectProviderSource(request: {
806
823
  };
807
824
  }
808
825
 
826
+ const capabilitiesValid = isCapabilityCatalog(provider.capabilities);
809
827
  const capabilities = readCapabilities(provider.capabilities);
810
828
  const commands = Array.isArray(provider.commands) ? provider.commands : [];
811
829
  const handlers = Array.isArray(provider.handlers) ? provider.handlers : [];
@@ -829,6 +847,7 @@ async function inspectProviderSource(request: {
829
847
  diagnostic: null,
830
848
  result: {
831
849
  capabilities,
850
+ capabilitiesValid,
832
851
  commandCapabilities,
833
852
  commandPaths,
834
853
  handlerPaths,
@@ -18,12 +18,18 @@ type CatalogResolution =
18
18
  export async function readCapabilityCatalogAsync(
19
19
  packageRoot: string,
20
20
  packageExports: unknown,
21
+ materializedCapabilities?: unknown,
21
22
  ): Promise<CatalogResolution> {
22
23
  const catalogPath = path.resolve(packageRoot, CAPABILITIES_SOURCE_PATH);
23
24
  if (!(await isFileAsync(catalogPath))) return { capabilities: null, path: null, reason: null };
24
25
  try {
25
26
  capabilityCatalogExports(packageRoot, packageExports, catalogPath);
26
- const values = await capabilityCatalogAstAsync(packageRoot, catalogPath, 'CAPABILITIES');
27
+ const values = await capabilityCatalogAstAsync(
28
+ packageRoot,
29
+ catalogPath,
30
+ 'CAPABILITIES',
31
+ materializedCapabilities,
32
+ );
27
33
  if (!Array.isArray(values))
28
34
  throw new Error(`${CAPABILITIES_SOURCE_PATH} must export CAPABILITIES as an array.`);
29
35
  const capabilities = parseCapabilityCatalog(values);