@ankhorage/doctor 0.14.10 → 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.
- package/CHANGELOG.md +12 -0
- package/README.md +1 -1
- package/dist/analysis.d.ts.map +1 -1
- package/dist/analysis.js +12 -3
- package/dist/analysis.js.map +1 -1
- package/dist/capabilityCatalog.d.ts +1 -1
- package/dist/capabilityCatalog.d.ts.map +1 -1
- package/dist/capabilityCatalog.js +2 -2
- package/dist/capabilityCatalog.js.map +1 -1
- package/dist/capabilityCatalogAst.d.ts +1 -1
- package/dist/capabilityCatalogAst.d.ts.map +1 -1
- package/dist/capabilityCatalogAst.js +61 -85
- package/dist/capabilityCatalogAst.js.map +1 -1
- package/dist/capabilityCatalogAstSource.d.ts +12 -0
- package/dist/capabilityCatalogAstSource.d.ts.map +1 -0
- package/dist/capabilityCatalogAstSource.js +38 -0
- package/dist/capabilityCatalogAstSource.js.map +1 -0
- 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/dist/capabilityCatalogImport.d.ts +9 -0
- package/dist/capabilityCatalogImport.d.ts.map +1 -0
- package/dist/capabilityCatalogImport.js +34 -0
- package/dist/capabilityCatalogImport.js.map +1 -0
- package/dist/capabilityCatalogStaticValue.d.ts +13 -0
- package/dist/capabilityCatalogStaticValue.d.ts.map +1 -0
- package/dist/capabilityCatalogStaticValue.js +35 -0
- package/dist/capabilityCatalogStaticValue.js.map +1 -0
- package/package.json +2 -2
- package/src/analysis.ts +23 -4
- package/src/capabilityCatalog.ts +7 -1
- package/src/capabilityCatalogAst.ts +113 -106
- package/src/capabilityCatalogAstSource.ts +52 -0
- package/src/capabilityCatalogContractsImport.ts +95 -0
- package/src/capabilityCatalogImport.ts +50 -0
- package/src/capabilityCatalogStaticValue.ts +48 -0
|
@@ -1,22 +1,26 @@
|
|
|
1
1
|
import { promises as fs } from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
2
|
import * as ts from 'typescript';
|
|
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';
|
|
4
6
|
/*** Evaluate one named catalog export from the supported static TypeScript subset. */
|
|
5
|
-
export async function capabilityCatalogAstAsync(packageRoot, modulePath, exportName) {
|
|
6
|
-
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);
|
|
7
9
|
}
|
|
8
10
|
/*** Resolve static local imports and expressions without loading target modules. */
|
|
9
11
|
class StaticCatalogResolver {
|
|
10
12
|
packageRoot;
|
|
11
13
|
#symbols = new Map();
|
|
12
14
|
#activeSymbols = [];
|
|
13
|
-
|
|
15
|
+
materializedCatalog;
|
|
16
|
+
constructor(packageRoot, materializedCatalog) {
|
|
14
17
|
this.packageRoot = packageRoot;
|
|
18
|
+
this.materializedCatalog = readStaticArray(materializedCatalog);
|
|
15
19
|
}
|
|
16
20
|
/*** Resolve a named local export without importing or running its module. */
|
|
17
|
-
async resolveAsync(modulePath, exportName) {
|
|
21
|
+
async resolveAsync(modulePath, exportName, moduleRoot = this.packageRoot) {
|
|
18
22
|
const key = `${modulePath}:${exportName}`;
|
|
19
|
-
return this.resolveSymbolAsync(key, () => this.resolveUncachedAsync(modulePath, exportName));
|
|
23
|
+
return this.resolveSymbolAsync(key, () => this.resolveUncachedAsync(modulePath, exportName, moduleRoot));
|
|
20
24
|
}
|
|
21
25
|
/*** Resolve one local symbol while detecting recursive static references. */
|
|
22
26
|
async resolveSymbolAsync(key, resolveAsync) {
|
|
@@ -37,7 +41,7 @@ class StaticCatalogResolver {
|
|
|
37
41
|
}
|
|
38
42
|
}
|
|
39
43
|
/*** Find and evaluate the declaration owning one exported static value. */
|
|
40
|
-
async resolveUncachedAsync(modulePath, exportName) {
|
|
44
|
+
async resolveUncachedAsync(modulePath, exportName, moduleRoot) {
|
|
41
45
|
const source = ts.createSourceFile(modulePath, await fs.readFile(modulePath, 'utf8'), ts.ScriptTarget.ESNext, true);
|
|
42
46
|
const declaration = source.statements
|
|
43
47
|
.filter((statement) => ts.isVariableStatement(statement))
|
|
@@ -47,7 +51,7 @@ class StaticCatalogResolver {
|
|
|
47
51
|
.find((value) => ts.isIdentifier(value.name) && value.name.text === exportName);
|
|
48
52
|
if (declaration?.initializer === undefined)
|
|
49
53
|
throw new Error(`Unable to find static export ${exportName} in ${modulePath}.`);
|
|
50
|
-
return this.evaluateAsync(declaration.initializer, new StaticCatalogScope(this, source, modulePath,
|
|
54
|
+
return this.evaluateAsync(declaration.initializer, new StaticCatalogScope(this, source, modulePath, moduleRoot));
|
|
51
55
|
}
|
|
52
56
|
/*** Evaluate an allowed static expression. */
|
|
53
57
|
async evaluateAsync(expression, environment) {
|
|
@@ -64,6 +68,8 @@ class StaticCatalogResolver {
|
|
|
64
68
|
return null;
|
|
65
69
|
if (ts.isIdentifier(node))
|
|
66
70
|
return environment.resolveAsync(node.text);
|
|
71
|
+
if (ts.isPropertyAccessExpression(node))
|
|
72
|
+
return this.propertyAccessAsync(node, environment);
|
|
67
73
|
if (ts.isArrayLiteralExpression(node))
|
|
68
74
|
return this.arrayAsync(node, environment);
|
|
69
75
|
if (ts.isObjectLiteralExpression(node))
|
|
@@ -74,6 +80,20 @@ class StaticCatalogResolver {
|
|
|
74
80
|
return this.mapAsync(node, environment);
|
|
75
81
|
throw new Error(`Unsupported static capability expression: ${node.getText()}.`);
|
|
76
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
|
+
}
|
|
77
97
|
/*** Evaluate a static array literal. */
|
|
78
98
|
arrayAsync(node, environment) {
|
|
79
99
|
return this.evaluateElementsAsync(node.elements, environment);
|
|
@@ -130,10 +150,21 @@ class StaticCatalogResolver {
|
|
|
130
150
|
/*** Evaluate static array elements in source order. */
|
|
131
151
|
async evaluateElementsAsync(elements, environment) {
|
|
132
152
|
const result = [];
|
|
133
|
-
for (const element of elements) {
|
|
134
|
-
if (ts.isSpreadElement(element))
|
|
135
|
-
|
|
136
|
-
|
|
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));
|
|
137
168
|
}
|
|
138
169
|
return result;
|
|
139
170
|
}
|
|
@@ -152,7 +183,7 @@ class StaticCatalogScope {
|
|
|
152
183
|
this.packageRoot = packageRoot;
|
|
153
184
|
this.values = values;
|
|
154
185
|
}
|
|
155
|
-
/*** Resolve a local constant or
|
|
186
|
+
/*** Resolve a local constant or an allowed named static package import. */
|
|
156
187
|
async resolveAsync(name) {
|
|
157
188
|
const value = this.values.get(name);
|
|
158
189
|
if (value !== undefined)
|
|
@@ -174,82 +205,27 @@ class StaticCatalogScope {
|
|
|
174
205
|
const binding = bindings.elements.find((element) => !element.isTypeOnly && element.name.text === name);
|
|
175
206
|
if (binding === undefined)
|
|
176
207
|
throw new Error(`Unsupported dynamic capability value: ${name}.`);
|
|
177
|
-
const
|
|
178
|
-
return this.resolver.resolveAsync(
|
|
208
|
+
const resolvedImport = await resolveImportPathAsync(this.packageRoot, this.modulePath, imported.moduleSpecifier.text);
|
|
209
|
+
return this.resolver.resolveAsync(resolvedImport.path, binding.propertyName?.text ?? binding.name.text, resolvedImport.packageRoot);
|
|
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;
|
|
179
225
|
}
|
|
180
226
|
/*** Add a static callback parameter without evaluating unrelated module symbols. */
|
|
181
227
|
withValue(name, value) {
|
|
182
228
|
return new StaticCatalogScope(this.resolver, this.source, this.modulePath, this.packageRoot, new Map([...this.values, [name, value]]));
|
|
183
229
|
}
|
|
184
230
|
}
|
|
185
|
-
/*** Find the static top-level declaration that owns a local identifier. */
|
|
186
|
-
function findStaticDeclaration(source, name) {
|
|
187
|
-
return source.statements
|
|
188
|
-
.filter((statement) => ts.isVariableStatement(statement))
|
|
189
|
-
.filter((statement) => isConstDeclaration(statement.declarationList))
|
|
190
|
-
.flatMap((statement) => statement.declarationList.declarations)
|
|
191
|
-
.find((declaration) => ts.isIdentifier(declaration.name) && declaration.name.text === name);
|
|
192
|
-
}
|
|
193
|
-
/*** Find the import declaration that introduces a referenced local identifier. */
|
|
194
|
-
function findImportBinding(source, name) {
|
|
195
|
-
return source.statements
|
|
196
|
-
.filter((statement) => ts.isImportDeclaration(statement))
|
|
197
|
-
.find((statement) => {
|
|
198
|
-
const clause = statement.importClause;
|
|
199
|
-
return (clause?.name?.text === name ||
|
|
200
|
-
(clause?.namedBindings !== undefined &&
|
|
201
|
-
ts.isNamedImports(clause.namedBindings) &&
|
|
202
|
-
clause.namedBindings.elements.some((element) => element.name.text === name)));
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
/*** Determine whether a declaration list is immutable static catalog input. */
|
|
206
|
-
function isConstDeclaration(list) {
|
|
207
|
-
return (list.flags & ts.NodeFlags.Const) !== 0;
|
|
208
|
-
}
|
|
209
|
-
/*** Resolve a local import to one source file inside the inspected package. */
|
|
210
|
-
async function resolveImportPathAsync(packageRoot, fromPath, specifier) {
|
|
211
|
-
if (!specifier.startsWith('.'))
|
|
212
|
-
throw new Error('Capability catalogs may import only local static metadata.');
|
|
213
|
-
const candidate = path.resolve(path.dirname(fromPath), specifier);
|
|
214
|
-
if (!isInsidePackage(packageRoot, candidate) && candidate !== packageRoot)
|
|
215
|
-
throw new Error('Capability catalogs may not import outside their package.');
|
|
216
|
-
for (const extension of ['', '.ts', '.tsx', '.js', '.mjs', '/index.ts'])
|
|
217
|
-
if (await isFileAsync(`${candidate}${extension}`))
|
|
218
|
-
return `${candidate}${extension}`;
|
|
219
|
-
throw new Error(`Unable to resolve static capability import ${specifier}.`);
|
|
220
|
-
}
|
|
221
|
-
/*** Unwrap TypeScript syntax which does not alter a runtime value. */
|
|
222
|
-
function unwrapExpression(expression) {
|
|
223
|
-
return ts.isAsExpression(expression) ||
|
|
224
|
-
ts.isSatisfiesExpression(expression) ||
|
|
225
|
-
ts.isParenthesizedExpression(expression)
|
|
226
|
-
? unwrapExpression(expression.expression)
|
|
227
|
-
: expression;
|
|
228
|
-
}
|
|
229
|
-
/*** Narrow a static value to a descriptor-shaped record. */
|
|
230
|
-
function isStaticRecord(value) {
|
|
231
|
-
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
232
|
-
}
|
|
233
|
-
/*** Narrow a static value to an array. */
|
|
234
|
-
function isStaticArray(value) {
|
|
235
|
-
return Array.isArray(value);
|
|
236
|
-
}
|
|
237
|
-
/*** Detect an exported variable statement. */
|
|
238
|
-
function hasExportModifier(statement) {
|
|
239
|
-
return (statement.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword) ?? false);
|
|
240
|
-
}
|
|
241
|
-
/*** Check whether a resolved path remains within the inspected package root. */
|
|
242
|
-
function isInsidePackage(packageRoot, candidate) {
|
|
243
|
-
const relativePath = path.relative(packageRoot, candidate);
|
|
244
|
-
return relativePath !== '' && !relativePath.startsWith(`..${path.sep}`) && relativePath !== '..';
|
|
245
|
-
}
|
|
246
|
-
/*** Check whether one candidate is a regular file. */
|
|
247
|
-
async function isFileAsync(candidate) {
|
|
248
|
-
try {
|
|
249
|
-
return (await fs.stat(candidate)).isFile();
|
|
250
|
-
}
|
|
251
|
-
catch {
|
|
252
|
-
return false;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
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\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';\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,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"]}
|
|
@@ -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
|