@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 +12 -0
- package/README.md +1 -1
- package/dist/capabilityCatalogAst.d.ts.map +1 -1
- package/dist/capabilityCatalogAst.js +16 -11
- package/dist/capabilityCatalogAst.js.map +1 -1
- package/dist/capabilityCatalogContractsImport.d.ts +8 -0
- package/dist/capabilityCatalogContractsImport.d.ts.map +1 -0
- package/dist/capabilityCatalogContractsImport.js +69 -0
- package/dist/capabilityCatalogContractsImport.js.map +1 -0
- package/package.json +4 -4
- package/src/capabilityCatalogAst.ts +43 -12
- package/src/capabilityCatalogContractsImport.ts +95 -0
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
|
-
         
|
|
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":"
|
|
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,
|
|
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
|
|
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
|
|
178
|
-
return this.resolver.resolveAsync(
|
|
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
|
|
210
|
+
/*** Resolve an allowed static import without executing its target package. */
|
|
210
211
|
async function resolveImportPathAsync(packageRoot, fromPath, specifier) {
|
|
211
|
-
if (
|
|
212
|
-
|
|
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":"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","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.
|
|
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.
|
|
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.
|
|
145
|
-
"@ankhorage/paradox": "^0.3.
|
|
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(
|
|
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, () =>
|
|
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(
|
|
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,
|
|
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
|
|
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
|
|
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(
|
|
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
|
-
|
|
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<
|
|
270
|
-
if (
|
|
271
|
-
|
|
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}`))
|
|
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
|
+
}
|