@twin.org/tools-core 0.0.3-next.21 → 0.0.3-next.23
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/dist/es/utils/importTypeQuerySchemaResolver.js +36 -2
- package/dist/es/utils/importTypeQuerySchemaResolver.js.map +1 -1
- package/dist/es/utils/jsDoc.js +1 -1
- package/dist/es/utils/jsDoc.js.map +1 -1
- package/dist/es/utils/jsonSchemaBuilder.js +144 -133
- package/dist/es/utils/jsonSchemaBuilder.js.map +1 -1
- package/dist/es/utils/mappedTypeSchemaResolver.js +35 -1
- package/dist/es/utils/mappedTypeSchemaResolver.js.map +1 -1
- package/dist/es/utils/objectTransformer.js +1 -1
- package/dist/es/utils/objectTransformer.js.map +1 -1
- package/dist/es/utils/resolver.js +22 -9
- package/dist/es/utils/resolver.js.map +1 -1
- package/dist/es/utils/utilityTypeSchemaMapper.js +81 -40
- package/dist/es/utils/utilityTypeSchemaMapper.js.map +1 -1
- package/dist/types/utils/importTypeQuerySchemaResolver.d.ts +35 -0
- package/dist/types/utils/jsonSchemaBuilder.d.ts +6 -82
- package/dist/types/utils/mappedTypeSchemaResolver.d.ts +35 -0
- package/dist/types/utils/resolver.d.ts +7 -1
- package/dist/types/utils/utilityTypeSchemaMapper.d.ts +60 -13
- package/docs/changelog.md +51 -0
- package/docs/reference/classes/ImportTypeQuerySchemaResolver.md +22 -0
- package/docs/reference/classes/JsonSchemaBuilder.md +12 -304
- package/docs/reference/classes/MappedTypeSchemaResolver.md +64 -0
- package/docs/reference/classes/Resolver.md +12 -1
- package/docs/reference/classes/UtilityTypeSchemaMapper.md +64 -62
- package/package.json +2 -2
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// Copyright 2026 IOTA Stiftung.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0.
|
|
3
|
-
/* eslint-disable jsdoc/require-param, jsdoc/require-returns */
|
|
4
3
|
import { Is, JsonHelper } from "@twin.org/core";
|
|
5
4
|
import * as ts from "typescript";
|
|
6
5
|
import { JsonSchemaBuilder } from "./jsonSchemaBuilder.js";
|
|
@@ -10,6 +9,11 @@ import { JsonSchemaBuilder } from "./jsonSchemaBuilder.js";
|
|
|
10
9
|
export class MappedTypeSchemaResolver {
|
|
11
10
|
/**
|
|
12
11
|
* Resolve mapped type output keys, including remapped key names via `as`.
|
|
12
|
+
* @param context The generation context.
|
|
13
|
+
* @param typeNode The mapped type node.
|
|
14
|
+
* @param mappedKeys The resolved source keys from the mapped type constraint.
|
|
15
|
+
* @param mappedTypeParameterName The mapped type parameter identifier.
|
|
16
|
+
* @returns The resolved source-to-output mapped key entries.
|
|
13
17
|
*/
|
|
14
18
|
static resolveMappedTypePropertyEntries(context, typeNode, mappedKeys, mappedTypeParameterName) {
|
|
15
19
|
if (!typeNode.nameType) {
|
|
@@ -29,6 +33,11 @@ export class MappedTypeSchemaResolver {
|
|
|
29
33
|
}
|
|
30
34
|
/**
|
|
31
35
|
* Resolve a remapped mapped-type key expression for a concrete source key.
|
|
36
|
+
* @param context The generation context.
|
|
37
|
+
* @param nameTypeNode The mapped type name remapping expression node.
|
|
38
|
+
* @param sourceKey The concrete source key currently being evaluated.
|
|
39
|
+
* @param mappedTypeParameterName The mapped type parameter identifier.
|
|
40
|
+
* @returns The remapped key, null when excluded via never, or undefined when unresolved.
|
|
32
41
|
*/
|
|
33
42
|
static resolveMappedTypeRemappedKey(context, nameTypeNode, sourceKey, mappedTypeParameterName) {
|
|
34
43
|
if (ts.isParenthesizedTypeNode(nameTypeNode)) {
|
|
@@ -95,6 +104,10 @@ export class MappedTypeSchemaResolver {
|
|
|
95
104
|
}
|
|
96
105
|
/**
|
|
97
106
|
* Evaluate whether a concrete mapped key satisfies an `extends` condition.
|
|
107
|
+
* @param context The generation context.
|
|
108
|
+
* @param sourceKey The concrete source key being evaluated.
|
|
109
|
+
* @param extendsTypeNode The extends condition type node.
|
|
110
|
+
* @returns True when the key satisfies the condition, false when it does not, otherwise undefined.
|
|
98
111
|
*/
|
|
99
112
|
static evaluateMappedKeyExtendsCondition(context, sourceKey, extendsTypeNode) {
|
|
100
113
|
if (ts.isParenthesizedTypeNode(extendsTypeNode)) {
|
|
@@ -149,6 +162,12 @@ export class MappedTypeSchemaResolver {
|
|
|
149
162
|
}
|
|
150
163
|
/**
|
|
151
164
|
* Build a conservative fallback schema for mapped types whose key remapping cannot be resolved.
|
|
165
|
+
* @param context The generation context.
|
|
166
|
+
* @param typeNode The mapped type node.
|
|
167
|
+
* @param mappedKeys The resolved source keys from the mapped type constraint.
|
|
168
|
+
* @param mappedTypeParameterName The mapped type parameter identifier.
|
|
169
|
+
* @param sourceObjectSchema The optional source object schema for property lookups.
|
|
170
|
+
* @returns The fallback mapped type schema.
|
|
152
171
|
*/
|
|
153
172
|
static buildMappedTypeFallbackSchema(context, typeNode, mappedKeys, mappedTypeParameterName, sourceObjectSchema) {
|
|
154
173
|
const additionalProperties = MappedTypeSchemaResolver.buildMappedTypeFallbackAdditionalProperties(context, typeNode, mappedKeys, mappedTypeParameterName, sourceObjectSchema);
|
|
@@ -159,6 +178,12 @@ export class MappedTypeSchemaResolver {
|
|
|
159
178
|
}
|
|
160
179
|
/**
|
|
161
180
|
* Build fallback additionalProperties for unresolved mapped key remapping.
|
|
181
|
+
* @param context The generation context.
|
|
182
|
+
* @param typeNode The mapped type node.
|
|
183
|
+
* @param mappedKeys The resolved source keys from the mapped type constraint.
|
|
184
|
+
* @param mappedTypeParameterName The mapped type parameter identifier.
|
|
185
|
+
* @param sourceObjectSchema The optional source object schema for property lookups.
|
|
186
|
+
* @returns The fallback additionalProperties schema.
|
|
162
187
|
*/
|
|
163
188
|
static buildMappedTypeFallbackAdditionalProperties(context, typeNode, mappedKeys, mappedTypeParameterName, sourceObjectSchema) {
|
|
164
189
|
const resolvedPropertySchemas = mappedKeys
|
|
@@ -180,6 +205,9 @@ export class MappedTypeSchemaResolver {
|
|
|
180
205
|
}
|
|
181
206
|
/**
|
|
182
207
|
* Merge mapped property schemas when multiple source keys remap to the same output key.
|
|
208
|
+
* @param existingSchema The existing schema already assigned to the mapped key.
|
|
209
|
+
* @param nextSchema The next schema to merge into the mapped key.
|
|
210
|
+
* @returns The merged schema.
|
|
183
211
|
*/
|
|
184
212
|
static mergeMappedTypePropertySchemas(existingSchema, nextSchema) {
|
|
185
213
|
const schemaVariants = [
|
|
@@ -199,6 +227,9 @@ export class MappedTypeSchemaResolver {
|
|
|
199
227
|
}
|
|
200
228
|
/**
|
|
201
229
|
* Resolve required remapped keys from the source object's required key set.
|
|
230
|
+
* @param mappedEntries The source-to-output mapped key entries.
|
|
231
|
+
* @param sourceObjectSchema The source object schema containing required keys.
|
|
232
|
+
* @returns The required output keys.
|
|
202
233
|
*/
|
|
203
234
|
static resolveMappedTypeSourceRequiredPropertyKeys(mappedEntries, sourceObjectSchema) {
|
|
204
235
|
if (!Is.array(sourceObjectSchema.required)) {
|
|
@@ -212,6 +243,9 @@ export class MappedTypeSchemaResolver {
|
|
|
212
243
|
}
|
|
213
244
|
/**
|
|
214
245
|
* Apply TypeScript intrinsic string remapping helpers to a key.
|
|
246
|
+
* @param intrinsicName The intrinsic helper name.
|
|
247
|
+
* @param value The input key value.
|
|
248
|
+
* @returns The remapped key value.
|
|
215
249
|
*/
|
|
216
250
|
static applyIntrinsicMappedTypeKeyRemap(intrinsicName, value) {
|
|
217
251
|
switch (intrinsicName) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mappedTypeSchemaResolver.js","sourceRoot":"","sources":["../../../src/utils/mappedTypeSchemaResolver.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n/* eslint-disable jsdoc/require-param, jsdoc/require-returns */\nimport { Is, JsonHelper } from \"@twin.org/core\";\nimport type { IJsonSchema } from \"@twin.org/tools-models\";\nimport * as ts from \"typescript\";\nimport { JsonSchemaBuilder } from \"./jsonSchemaBuilder.js\";\nimport type { ITypeScriptToSchemaContext } from \"../models/ITypeScriptToSchemaContext.js\";\n\n/**\n * Static mapped-type schema transformation helpers.\n */\nexport class MappedTypeSchemaResolver {\n\t/**\n\t * Resolve mapped type output keys, including remapped key names via `as`.\n\t */\n\tpublic static resolveMappedTypePropertyEntries(\n\t\tcontext: ITypeScriptToSchemaContext,\n\t\ttypeNode: ts.MappedTypeNode,\n\t\tmappedKeys: string[],\n\t\tmappedTypeParameterName: string\n\t): { sourceKey: string; mappedKey: string }[] | undefined {\n\t\tif (!typeNode.nameType) {\n\t\t\treturn mappedKeys.map(mappedKey => ({ sourceKey: mappedKey, mappedKey }));\n\t\t}\n\n\t\tconst mappedEntries: { sourceKey: string; mappedKey: string }[] = [];\n\n\t\tfor (const sourceKey of mappedKeys) {\n\t\t\tconst mappedKey = MappedTypeSchemaResolver.resolveMappedTypeRemappedKey(\n\t\t\t\tcontext,\n\t\t\t\ttypeNode.nameType,\n\t\t\t\tsourceKey,\n\t\t\t\tmappedTypeParameterName\n\t\t\t);\n\t\t\tif (mappedKey !== null && !Is.stringValue(mappedKey)) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tif (Is.stringValue(mappedKey)) {\n\t\t\t\tmappedEntries.push({ sourceKey, mappedKey });\n\t\t\t}\n\t\t}\n\n\t\treturn mappedEntries;\n\t}\n\n\t/**\n\t * Resolve a remapped mapped-type key expression for a concrete source key.\n\t */\n\tpublic static resolveMappedTypeRemappedKey(\n\t\tcontext: ITypeScriptToSchemaContext,\n\t\tnameTypeNode: ts.TypeNode,\n\t\tsourceKey: string,\n\t\tmappedTypeParameterName: string\n\t): string | null | undefined {\n\t\tif (ts.isParenthesizedTypeNode(nameTypeNode)) {\n\t\t\treturn MappedTypeSchemaResolver.resolveMappedTypeRemappedKey(\n\t\t\t\tcontext,\n\t\t\t\tnameTypeNode.type,\n\t\t\t\tsourceKey,\n\t\t\t\tmappedTypeParameterName\n\t\t\t);\n\t\t}\n\n\t\tif (nameTypeNode.kind === ts.SyntaxKind.NeverKeyword) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (JsonSchemaBuilder.isMappedTypeParameterReference(nameTypeNode, mappedTypeParameterName)) {\n\t\t\treturn sourceKey;\n\t\t}\n\n\t\tif (ts.isLiteralTypeNode(nameTypeNode)) {\n\t\t\tif (ts.isStringLiteral(nameTypeNode.literal) || ts.isNumericLiteral(nameTypeNode.literal)) {\n\t\t\t\treturn nameTypeNode.literal.text;\n\t\t\t}\n\t\t\tif (nameTypeNode.literal.kind === ts.SyntaxKind.TrueKeyword) {\n\t\t\t\treturn \"true\";\n\t\t\t}\n\t\t\tif (nameTypeNode.literal.kind === ts.SyntaxKind.FalseKeyword) {\n\t\t\t\treturn \"false\";\n\t\t\t}\n\t\t}\n\n\t\tif (ts.isIntersectionTypeNode(nameTypeNode)) {\n\t\t\tconst hasMappedKeyReference = nameTypeNode.types.some(type =>\n\t\t\t\tJsonSchemaBuilder.isMappedTypeParameterReference(type, mappedTypeParameterName)\n\t\t\t);\n\t\t\tconst hasStringKeyword = nameTypeNode.types.some(\n\t\t\t\ttype => type.kind === ts.SyntaxKind.StringKeyword\n\t\t\t);\n\t\t\tif (hasMappedKeyReference && hasStringKeyword) {\n\t\t\t\treturn sourceKey;\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (ts.isTemplateLiteralTypeNode(nameTypeNode)) {\n\t\t\tlet remappedKey = nameTypeNode.head.text;\n\t\t\tfor (const span of nameTypeNode.templateSpans) {\n\t\t\t\tconst spanValue = MappedTypeSchemaResolver.resolveMappedTypeRemappedKey(\n\t\t\t\t\tcontext,\n\t\t\t\t\tspan.type,\n\t\t\t\t\tsourceKey,\n\t\t\t\t\tmappedTypeParameterName\n\t\t\t\t);\n\t\t\t\tif (!Is.stringValue(spanValue)) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\tremappedKey += `${spanValue}${span.literal.text}`;\n\t\t\t}\n\n\t\t\treturn remappedKey;\n\t\t}\n\n\t\tif (ts.isTypeReferenceNode(nameTypeNode) && ts.isIdentifier(nameTypeNode.typeName)) {\n\t\t\tconst intrinsicName = nameTypeNode.typeName.text;\n\t\t\tif (nameTypeNode.typeArguments?.length === 1) {\n\t\t\t\tconst intrinsicInput = MappedTypeSchemaResolver.resolveMappedTypeRemappedKey(\n\t\t\t\t\tcontext,\n\t\t\t\t\tnameTypeNode.typeArguments[0],\n\t\t\t\t\tsourceKey,\n\t\t\t\t\tmappedTypeParameterName\n\t\t\t\t);\n\t\t\t\tif (!Is.stringValue(intrinsicInput)) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\n\t\t\t\treturn MappedTypeSchemaResolver.applyIntrinsicMappedTypeKeyRemap(\n\t\t\t\t\tintrinsicName,\n\t\t\t\t\tintrinsicInput\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (ts.isConditionalTypeNode(nameTypeNode)) {\n\t\t\tif (\n\t\t\t\t!JsonSchemaBuilder.isMappedTypeParameterReference(\n\t\t\t\t\tnameTypeNode.checkType,\n\t\t\t\t\tmappedTypeParameterName\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tconst satisfies = MappedTypeSchemaResolver.evaluateMappedKeyExtendsCondition(\n\t\t\t\tcontext,\n\t\t\t\tsourceKey,\n\t\t\t\tnameTypeNode.extendsType\n\t\t\t);\n\t\t\tif (satisfies === undefined) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tconst branchType = satisfies ? nameTypeNode.trueType : nameTypeNode.falseType;\n\t\t\treturn MappedTypeSchemaResolver.resolveMappedTypeRemappedKey(\n\t\t\t\tcontext,\n\t\t\t\tbranchType,\n\t\t\t\tsourceKey,\n\t\t\t\tmappedTypeParameterName\n\t\t\t);\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Evaluate whether a concrete mapped key satisfies an `extends` condition.\n\t */\n\tpublic static evaluateMappedKeyExtendsCondition(\n\t\tcontext: ITypeScriptToSchemaContext,\n\t\tsourceKey: string,\n\t\textendsTypeNode: ts.TypeNode\n\t): boolean | undefined {\n\t\tif (ts.isParenthesizedTypeNode(extendsTypeNode)) {\n\t\t\treturn MappedTypeSchemaResolver.evaluateMappedKeyExtendsCondition(\n\t\t\t\tcontext,\n\t\t\t\tsourceKey,\n\t\t\t\textendsTypeNode.type\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\textendsTypeNode.kind === ts.SyntaxKind.StringKeyword ||\n\t\t\textendsTypeNode.kind === ts.SyntaxKind.AnyKeyword ||\n\t\t\textendsTypeNode.kind === ts.SyntaxKind.UnknownKeyword\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (\n\t\t\textendsTypeNode.kind === ts.SyntaxKind.NeverKeyword ||\n\t\t\textendsTypeNode.kind === ts.SyntaxKind.NumberKeyword ||\n\t\t\textendsTypeNode.kind === ts.SyntaxKind.BooleanKeyword ||\n\t\t\textendsTypeNode.kind === ts.SyntaxKind.ObjectKeyword\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (ts.isLiteralTypeNode(extendsTypeNode)) {\n\t\t\tif (\n\t\t\t\tts.isStringLiteral(extendsTypeNode.literal) ||\n\t\t\t\tts.isNumericLiteral(extendsTypeNode.literal)\n\t\t\t) {\n\t\t\t\treturn sourceKey === extendsTypeNode.literal.text;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tif (ts.isUnionTypeNode(extendsTypeNode)) {\n\t\t\tlet hasUndetermined = false;\n\t\t\tfor (const memberType of extendsTypeNode.types) {\n\t\t\t\tconst result = MappedTypeSchemaResolver.evaluateMappedKeyExtendsCondition(\n\t\t\t\t\tcontext,\n\t\t\t\t\tsourceKey,\n\t\t\t\t\tmemberType\n\t\t\t\t);\n\t\t\t\tif (result === true) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tif (result === undefined) {\n\t\t\t\t\thasUndetermined = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn hasUndetermined ? undefined : false;\n\t\t}\n\n\t\tif (\n\t\t\tts.isTypeOperatorNode(extendsTypeNode) &&\n\t\t\textendsTypeNode.operator === ts.SyntaxKind.KeyOfKeyword\n\t\t) {\n\t\t\tconst keys = JsonSchemaBuilder.extractKeyofTypeKeys(context, extendsTypeNode.type);\n\t\t\tif (keys.length > 0) {\n\t\t\t\treturn keys.includes(sourceKey);\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (ts.isTypeReferenceNode(extendsTypeNode)) {\n\t\t\tconst resolved = JsonSchemaBuilder.resolveReferencedTypeNodeFromLocalDeclaration(\n\t\t\t\tcontext,\n\t\t\t\textendsTypeNode\n\t\t\t);\n\t\t\tif (resolved) {\n\t\t\t\treturn MappedTypeSchemaResolver.evaluateMappedKeyExtendsCondition(\n\t\t\t\t\tcontext,\n\t\t\t\t\tsourceKey,\n\t\t\t\t\tresolved\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Build a conservative fallback schema for mapped types whose key remapping cannot be resolved.\n\t */\n\tpublic static buildMappedTypeFallbackSchema(\n\t\tcontext: ITypeScriptToSchemaContext,\n\t\ttypeNode: ts.MappedTypeNode,\n\t\tmappedKeys: string[],\n\t\tmappedTypeParameterName: string,\n\t\tsourceObjectSchema?: IJsonSchema\n\t): IJsonSchema {\n\t\tconst additionalProperties =\n\t\t\tMappedTypeSchemaResolver.buildMappedTypeFallbackAdditionalProperties(\n\t\t\t\tcontext,\n\t\t\t\ttypeNode,\n\t\t\t\tmappedKeys,\n\t\t\t\tmappedTypeParameterName,\n\t\t\t\tsourceObjectSchema\n\t\t\t);\n\n\t\treturn {\n\t\t\ttype: \"object\",\n\t\t\tadditionalProperties: additionalProperties ?? {}\n\t\t};\n\t}\n\n\t/**\n\t * Build fallback additionalProperties for unresolved mapped key remapping.\n\t */\n\tpublic static buildMappedTypeFallbackAdditionalProperties(\n\t\tcontext: ITypeScriptToSchemaContext,\n\t\ttypeNode: ts.MappedTypeNode,\n\t\tmappedKeys: string[],\n\t\tmappedTypeParameterName: string,\n\t\tsourceObjectSchema?: IJsonSchema\n\t): IJsonSchema | undefined {\n\t\tconst resolvedPropertySchemas = mappedKeys\n\t\t\t.map(mappedKey =>\n\t\t\t\tJsonSchemaBuilder.mapMappedTypePropertySchema(\n\t\t\t\t\tcontext,\n\t\t\t\t\ttypeNode,\n\t\t\t\t\tmappedKey,\n\t\t\t\t\tmappedTypeParameterName,\n\t\t\t\t\tsourceObjectSchema\n\t\t\t\t)\n\t\t\t)\n\t\t\t.filter((mappedType): mappedType is IJsonSchema => mappedType !== undefined);\n\n\t\tif (resolvedPropertySchemas.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst uniqueSchemas = resolvedPropertySchemas.filter((schema, index, allSchemas) => {\n\t\t\tconst schemaKey = JsonHelper.canonicalize(schema);\n\t\t\treturn allSchemas.findIndex(s => JsonHelper.canonicalize(s) === schemaKey) === index;\n\t\t});\n\n\t\tif (uniqueSchemas.length === 1) {\n\t\t\treturn uniqueSchemas[0];\n\t\t}\n\n\t\treturn {\n\t\t\tanyOf: uniqueSchemas\n\t\t};\n\t}\n\n\t/**\n\t * Merge mapped property schemas when multiple source keys remap to the same output key.\n\t */\n\tpublic static mergeMappedTypePropertySchemas(\n\t\texistingSchema: IJsonSchema,\n\t\tnextSchema: IJsonSchema\n\t): IJsonSchema {\n\t\tconst schemaVariants = [\n\t\t\t...(existingSchema.anyOf ?? [existingSchema]),\n\t\t\t...(nextSchema.anyOf ?? [nextSchema])\n\t\t];\n\n\t\tconst uniqueSchemas = schemaVariants.filter((schema, index, allSchemas) => {\n\t\t\tconst schemaKey = JsonHelper.canonicalize(schema);\n\t\t\treturn allSchemas.findIndex(s => JsonHelper.canonicalize(s) === schemaKey) === index;\n\t\t});\n\n\t\tif (uniqueSchemas.length === 1) {\n\t\t\treturn uniqueSchemas[0];\n\t\t}\n\n\t\treturn {\n\t\t\tanyOf: uniqueSchemas\n\t\t};\n\t}\n\n\t/**\n\t * Resolve required remapped keys from the source object's required key set.\n\t */\n\tpublic static resolveMappedTypeSourceRequiredPropertyKeys(\n\t\tmappedEntries: { sourceKey: string; mappedKey: string }[],\n\t\tsourceObjectSchema: IJsonSchema\n\t): string[] | undefined {\n\t\tif (!Is.array<string>(sourceObjectSchema.required)) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst sourceRequiredKeys = new Set(sourceObjectSchema.required);\n\t\tconst remappedRequiredKeys = mappedEntries\n\t\t\t.filter(mappedEntry => sourceRequiredKeys.has(mappedEntry.sourceKey))\n\t\t\t.map(mappedEntry => mappedEntry.mappedKey);\n\n\t\treturn [...new Set(remappedRequiredKeys)];\n\t}\n\n\t/**\n\t * Apply TypeScript intrinsic string remapping helpers to a key.\n\t */\n\tprivate static applyIntrinsicMappedTypeKeyRemap(\n\t\tintrinsicName: string,\n\t\tvalue: string\n\t): string | undefined {\n\t\tswitch (intrinsicName) {\n\t\t\tcase \"Uppercase\":\n\t\t\t\treturn value.toUpperCase();\n\t\t\tcase \"Lowercase\":\n\t\t\t\treturn value.toLowerCase();\n\t\t\tcase \"Capitalize\":\n\t\t\t\treturn value.length > 0 ? `${value[0].toUpperCase()}${value.slice(1)}` : value;\n\t\t\tcase \"Uncapitalize\":\n\t\t\t\treturn value.length > 0 ? `${value[0].toLowerCase()}${value.slice(1)}` : value;\n\t\t\tdefault:\n\t\t\t\treturn undefined;\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"mappedTypeSchemaResolver.js","sourceRoot":"","sources":["../../../src/utils/mappedTypeSchemaResolver.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { Is, JsonHelper } from \"@twin.org/core\";\nimport type { IJsonSchema } from \"@twin.org/tools-models\";\nimport * as ts from \"typescript\";\nimport { JsonSchemaBuilder } from \"./jsonSchemaBuilder.js\";\nimport type { ITypeScriptToSchemaContext } from \"../models/ITypeScriptToSchemaContext.js\";\n\n/**\n * Static mapped-type schema transformation helpers.\n */\nexport class MappedTypeSchemaResolver {\n\t/**\n\t * Resolve mapped type output keys, including remapped key names via `as`.\n\t * @param context The generation context.\n\t * @param typeNode The mapped type node.\n\t * @param mappedKeys The resolved source keys from the mapped type constraint.\n\t * @param mappedTypeParameterName The mapped type parameter identifier.\n\t * @returns The resolved source-to-output mapped key entries.\n\t */\n\tpublic static resolveMappedTypePropertyEntries(\n\t\tcontext: ITypeScriptToSchemaContext,\n\t\ttypeNode: ts.MappedTypeNode,\n\t\tmappedKeys: string[],\n\t\tmappedTypeParameterName: string\n\t): { sourceKey: string; mappedKey: string }[] | undefined {\n\t\tif (!typeNode.nameType) {\n\t\t\treturn mappedKeys.map(mappedKey => ({ sourceKey: mappedKey, mappedKey }));\n\t\t}\n\n\t\tconst mappedEntries: { sourceKey: string; mappedKey: string }[] = [];\n\n\t\tfor (const sourceKey of mappedKeys) {\n\t\t\tconst mappedKey = MappedTypeSchemaResolver.resolveMappedTypeRemappedKey(\n\t\t\t\tcontext,\n\t\t\t\ttypeNode.nameType,\n\t\t\t\tsourceKey,\n\t\t\t\tmappedTypeParameterName\n\t\t\t);\n\t\t\tif (mappedKey !== null && !Is.stringValue(mappedKey)) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tif (Is.stringValue(mappedKey)) {\n\t\t\t\tmappedEntries.push({ sourceKey, mappedKey });\n\t\t\t}\n\t\t}\n\n\t\treturn mappedEntries;\n\t}\n\n\t/**\n\t * Resolve a remapped mapped-type key expression for a concrete source key.\n\t * @param context The generation context.\n\t * @param nameTypeNode The mapped type name remapping expression node.\n\t * @param sourceKey The concrete source key currently being evaluated.\n\t * @param mappedTypeParameterName The mapped type parameter identifier.\n\t * @returns The remapped key, null when excluded via never, or undefined when unresolved.\n\t */\n\tpublic static resolveMappedTypeRemappedKey(\n\t\tcontext: ITypeScriptToSchemaContext,\n\t\tnameTypeNode: ts.TypeNode,\n\t\tsourceKey: string,\n\t\tmappedTypeParameterName: string\n\t): string | null | undefined {\n\t\tif (ts.isParenthesizedTypeNode(nameTypeNode)) {\n\t\t\treturn MappedTypeSchemaResolver.resolveMappedTypeRemappedKey(\n\t\t\t\tcontext,\n\t\t\t\tnameTypeNode.type,\n\t\t\t\tsourceKey,\n\t\t\t\tmappedTypeParameterName\n\t\t\t);\n\t\t}\n\n\t\tif (nameTypeNode.kind === ts.SyntaxKind.NeverKeyword) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (JsonSchemaBuilder.isMappedTypeParameterReference(nameTypeNode, mappedTypeParameterName)) {\n\t\t\treturn sourceKey;\n\t\t}\n\n\t\tif (ts.isLiteralTypeNode(nameTypeNode)) {\n\t\t\tif (ts.isStringLiteral(nameTypeNode.literal) || ts.isNumericLiteral(nameTypeNode.literal)) {\n\t\t\t\treturn nameTypeNode.literal.text;\n\t\t\t}\n\t\t\tif (nameTypeNode.literal.kind === ts.SyntaxKind.TrueKeyword) {\n\t\t\t\treturn \"true\";\n\t\t\t}\n\t\t\tif (nameTypeNode.literal.kind === ts.SyntaxKind.FalseKeyword) {\n\t\t\t\treturn \"false\";\n\t\t\t}\n\t\t}\n\n\t\tif (ts.isIntersectionTypeNode(nameTypeNode)) {\n\t\t\tconst hasMappedKeyReference = nameTypeNode.types.some(type =>\n\t\t\t\tJsonSchemaBuilder.isMappedTypeParameterReference(type, mappedTypeParameterName)\n\t\t\t);\n\t\t\tconst hasStringKeyword = nameTypeNode.types.some(\n\t\t\t\ttype => type.kind === ts.SyntaxKind.StringKeyword\n\t\t\t);\n\t\t\tif (hasMappedKeyReference && hasStringKeyword) {\n\t\t\t\treturn sourceKey;\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (ts.isTemplateLiteralTypeNode(nameTypeNode)) {\n\t\t\tlet remappedKey = nameTypeNode.head.text;\n\t\t\tfor (const span of nameTypeNode.templateSpans) {\n\t\t\t\tconst spanValue = MappedTypeSchemaResolver.resolveMappedTypeRemappedKey(\n\t\t\t\t\tcontext,\n\t\t\t\t\tspan.type,\n\t\t\t\t\tsourceKey,\n\t\t\t\t\tmappedTypeParameterName\n\t\t\t\t);\n\t\t\t\tif (!Is.stringValue(spanValue)) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\tremappedKey += `${spanValue}${span.literal.text}`;\n\t\t\t}\n\n\t\t\treturn remappedKey;\n\t\t}\n\n\t\tif (ts.isTypeReferenceNode(nameTypeNode) && ts.isIdentifier(nameTypeNode.typeName)) {\n\t\t\tconst intrinsicName = nameTypeNode.typeName.text;\n\t\t\tif (nameTypeNode.typeArguments?.length === 1) {\n\t\t\t\tconst intrinsicInput = MappedTypeSchemaResolver.resolveMappedTypeRemappedKey(\n\t\t\t\t\tcontext,\n\t\t\t\t\tnameTypeNode.typeArguments[0],\n\t\t\t\t\tsourceKey,\n\t\t\t\t\tmappedTypeParameterName\n\t\t\t\t);\n\t\t\t\tif (!Is.stringValue(intrinsicInput)) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\n\t\t\t\treturn MappedTypeSchemaResolver.applyIntrinsicMappedTypeKeyRemap(\n\t\t\t\t\tintrinsicName,\n\t\t\t\t\tintrinsicInput\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (ts.isConditionalTypeNode(nameTypeNode)) {\n\t\t\tif (\n\t\t\t\t!JsonSchemaBuilder.isMappedTypeParameterReference(\n\t\t\t\t\tnameTypeNode.checkType,\n\t\t\t\t\tmappedTypeParameterName\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tconst satisfies = MappedTypeSchemaResolver.evaluateMappedKeyExtendsCondition(\n\t\t\t\tcontext,\n\t\t\t\tsourceKey,\n\t\t\t\tnameTypeNode.extendsType\n\t\t\t);\n\t\t\tif (satisfies === undefined) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tconst branchType = satisfies ? nameTypeNode.trueType : nameTypeNode.falseType;\n\t\t\treturn MappedTypeSchemaResolver.resolveMappedTypeRemappedKey(\n\t\t\t\tcontext,\n\t\t\t\tbranchType,\n\t\t\t\tsourceKey,\n\t\t\t\tmappedTypeParameterName\n\t\t\t);\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Evaluate whether a concrete mapped key satisfies an `extends` condition.\n\t * @param context The generation context.\n\t * @param sourceKey The concrete source key being evaluated.\n\t * @param extendsTypeNode The extends condition type node.\n\t * @returns True when the key satisfies the condition, false when it does not, otherwise undefined.\n\t */\n\tpublic static evaluateMappedKeyExtendsCondition(\n\t\tcontext: ITypeScriptToSchemaContext,\n\t\tsourceKey: string,\n\t\textendsTypeNode: ts.TypeNode\n\t): boolean | undefined {\n\t\tif (ts.isParenthesizedTypeNode(extendsTypeNode)) {\n\t\t\treturn MappedTypeSchemaResolver.evaluateMappedKeyExtendsCondition(\n\t\t\t\tcontext,\n\t\t\t\tsourceKey,\n\t\t\t\textendsTypeNode.type\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\textendsTypeNode.kind === ts.SyntaxKind.StringKeyword ||\n\t\t\textendsTypeNode.kind === ts.SyntaxKind.AnyKeyword ||\n\t\t\textendsTypeNode.kind === ts.SyntaxKind.UnknownKeyword\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (\n\t\t\textendsTypeNode.kind === ts.SyntaxKind.NeverKeyword ||\n\t\t\textendsTypeNode.kind === ts.SyntaxKind.NumberKeyword ||\n\t\t\textendsTypeNode.kind === ts.SyntaxKind.BooleanKeyword ||\n\t\t\textendsTypeNode.kind === ts.SyntaxKind.ObjectKeyword\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (ts.isLiteralTypeNode(extendsTypeNode)) {\n\t\t\tif (\n\t\t\t\tts.isStringLiteral(extendsTypeNode.literal) ||\n\t\t\t\tts.isNumericLiteral(extendsTypeNode.literal)\n\t\t\t) {\n\t\t\t\treturn sourceKey === extendsTypeNode.literal.text;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tif (ts.isUnionTypeNode(extendsTypeNode)) {\n\t\t\tlet hasUndetermined = false;\n\t\t\tfor (const memberType of extendsTypeNode.types) {\n\t\t\t\tconst result = MappedTypeSchemaResolver.evaluateMappedKeyExtendsCondition(\n\t\t\t\t\tcontext,\n\t\t\t\t\tsourceKey,\n\t\t\t\t\tmemberType\n\t\t\t\t);\n\t\t\t\tif (result === true) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tif (result === undefined) {\n\t\t\t\t\thasUndetermined = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn hasUndetermined ? undefined : false;\n\t\t}\n\n\t\tif (\n\t\t\tts.isTypeOperatorNode(extendsTypeNode) &&\n\t\t\textendsTypeNode.operator === ts.SyntaxKind.KeyOfKeyword\n\t\t) {\n\t\t\tconst keys = JsonSchemaBuilder.extractKeyofTypeKeys(context, extendsTypeNode.type);\n\t\t\tif (keys.length > 0) {\n\t\t\t\treturn keys.includes(sourceKey);\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (ts.isTypeReferenceNode(extendsTypeNode)) {\n\t\t\tconst resolved = JsonSchemaBuilder.resolveReferencedTypeNodeFromLocalDeclaration(\n\t\t\t\tcontext,\n\t\t\t\textendsTypeNode\n\t\t\t);\n\t\t\tif (resolved) {\n\t\t\t\treturn MappedTypeSchemaResolver.evaluateMappedKeyExtendsCondition(\n\t\t\t\t\tcontext,\n\t\t\t\t\tsourceKey,\n\t\t\t\t\tresolved\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Build a conservative fallback schema for mapped types whose key remapping cannot be resolved.\n\t * @param context The generation context.\n\t * @param typeNode The mapped type node.\n\t * @param mappedKeys The resolved source keys from the mapped type constraint.\n\t * @param mappedTypeParameterName The mapped type parameter identifier.\n\t * @param sourceObjectSchema The optional source object schema for property lookups.\n\t * @returns The fallback mapped type schema.\n\t */\n\tpublic static buildMappedTypeFallbackSchema(\n\t\tcontext: ITypeScriptToSchemaContext,\n\t\ttypeNode: ts.MappedTypeNode,\n\t\tmappedKeys: string[],\n\t\tmappedTypeParameterName: string,\n\t\tsourceObjectSchema?: IJsonSchema\n\t): IJsonSchema {\n\t\tconst additionalProperties =\n\t\t\tMappedTypeSchemaResolver.buildMappedTypeFallbackAdditionalProperties(\n\t\t\t\tcontext,\n\t\t\t\ttypeNode,\n\t\t\t\tmappedKeys,\n\t\t\t\tmappedTypeParameterName,\n\t\t\t\tsourceObjectSchema\n\t\t\t);\n\n\t\treturn {\n\t\t\ttype: \"object\",\n\t\t\tadditionalProperties: additionalProperties ?? {}\n\t\t};\n\t}\n\n\t/**\n\t * Build fallback additionalProperties for unresolved mapped key remapping.\n\t * @param context The generation context.\n\t * @param typeNode The mapped type node.\n\t * @param mappedKeys The resolved source keys from the mapped type constraint.\n\t * @param mappedTypeParameterName The mapped type parameter identifier.\n\t * @param sourceObjectSchema The optional source object schema for property lookups.\n\t * @returns The fallback additionalProperties schema.\n\t */\n\tpublic static buildMappedTypeFallbackAdditionalProperties(\n\t\tcontext: ITypeScriptToSchemaContext,\n\t\ttypeNode: ts.MappedTypeNode,\n\t\tmappedKeys: string[],\n\t\tmappedTypeParameterName: string,\n\t\tsourceObjectSchema?: IJsonSchema\n\t): IJsonSchema | undefined {\n\t\tconst resolvedPropertySchemas = mappedKeys\n\t\t\t.map(mappedKey =>\n\t\t\t\tJsonSchemaBuilder.mapMappedTypePropertySchema(\n\t\t\t\t\tcontext,\n\t\t\t\t\ttypeNode,\n\t\t\t\t\tmappedKey,\n\t\t\t\t\tmappedTypeParameterName,\n\t\t\t\t\tsourceObjectSchema\n\t\t\t\t)\n\t\t\t)\n\t\t\t.filter((mappedType): mappedType is IJsonSchema => mappedType !== undefined);\n\n\t\tif (resolvedPropertySchemas.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst uniqueSchemas = resolvedPropertySchemas.filter((schema, index, allSchemas) => {\n\t\t\tconst schemaKey = JsonHelper.canonicalize(schema);\n\t\t\treturn allSchemas.findIndex(s => JsonHelper.canonicalize(s) === schemaKey) === index;\n\t\t});\n\n\t\tif (uniqueSchemas.length === 1) {\n\t\t\treturn uniqueSchemas[0];\n\t\t}\n\n\t\treturn {\n\t\t\tanyOf: uniqueSchemas\n\t\t};\n\t}\n\n\t/**\n\t * Merge mapped property schemas when multiple source keys remap to the same output key.\n\t * @param existingSchema The existing schema already assigned to the mapped key.\n\t * @param nextSchema The next schema to merge into the mapped key.\n\t * @returns The merged schema.\n\t */\n\tpublic static mergeMappedTypePropertySchemas(\n\t\texistingSchema: IJsonSchema,\n\t\tnextSchema: IJsonSchema\n\t): IJsonSchema {\n\t\tconst schemaVariants = [\n\t\t\t...(existingSchema.anyOf ?? [existingSchema]),\n\t\t\t...(nextSchema.anyOf ?? [nextSchema])\n\t\t];\n\n\t\tconst uniqueSchemas = schemaVariants.filter((schema, index, allSchemas) => {\n\t\t\tconst schemaKey = JsonHelper.canonicalize(schema);\n\t\t\treturn allSchemas.findIndex(s => JsonHelper.canonicalize(s) === schemaKey) === index;\n\t\t});\n\n\t\tif (uniqueSchemas.length === 1) {\n\t\t\treturn uniqueSchemas[0];\n\t\t}\n\n\t\treturn {\n\t\t\tanyOf: uniqueSchemas\n\t\t};\n\t}\n\n\t/**\n\t * Resolve required remapped keys from the source object's required key set.\n\t * @param mappedEntries The source-to-output mapped key entries.\n\t * @param sourceObjectSchema The source object schema containing required keys.\n\t * @returns The required output keys.\n\t */\n\tpublic static resolveMappedTypeSourceRequiredPropertyKeys(\n\t\tmappedEntries: { sourceKey: string; mappedKey: string }[],\n\t\tsourceObjectSchema: IJsonSchema\n\t): string[] | undefined {\n\t\tif (!Is.array<string>(sourceObjectSchema.required)) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst sourceRequiredKeys = new Set(sourceObjectSchema.required);\n\t\tconst remappedRequiredKeys = mappedEntries\n\t\t\t.filter(mappedEntry => sourceRequiredKeys.has(mappedEntry.sourceKey))\n\t\t\t.map(mappedEntry => mappedEntry.mappedKey);\n\n\t\treturn [...new Set(remappedRequiredKeys)];\n\t}\n\n\t/**\n\t * Apply TypeScript intrinsic string remapping helpers to a key.\n\t * @param intrinsicName The intrinsic helper name.\n\t * @param value The input key value.\n\t * @returns The remapped key value.\n\t */\n\tprivate static applyIntrinsicMappedTypeKeyRemap(\n\t\tintrinsicName: string,\n\t\tvalue: string\n\t): string | undefined {\n\t\tswitch (intrinsicName) {\n\t\t\tcase \"Uppercase\":\n\t\t\t\treturn value.toUpperCase();\n\t\t\tcase \"Lowercase\":\n\t\t\t\treturn value.toLowerCase();\n\t\t\tcase \"Capitalize\":\n\t\t\t\treturn value.length > 0 ? `${value[0].toUpperCase()}${value.slice(1)}` : value;\n\t\t\tcase \"Uncapitalize\":\n\t\t\t\treturn value.length > 0 ? `${value[0].toLowerCase()}${value.slice(1)}` : value;\n\t\t\tdefault:\n\t\t\t\treturn undefined;\n\t\t}\n\t}\n}\n"]}
|
|
@@ -127,7 +127,7 @@ export class ObjectTransformer {
|
|
|
127
127
|
static normalizeSchemaDescriptions(schema) {
|
|
128
128
|
const normalizedSchema = ObjectHelper.clone(schema);
|
|
129
129
|
const normalizeObject = (value) => {
|
|
130
|
-
if (
|
|
130
|
+
if (Is.array(value)) {
|
|
131
131
|
for (const item of value) {
|
|
132
132
|
normalizeObject(item);
|
|
133
133
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"objectTransformer.js","sourceRoot":"","sources":["../../../src/utils/objectTransformer.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { Is, ObjectHelper } from \"@twin.org/core\";\nimport type { IJsonSchema } from \"@twin.org/tools-models\";\n\n/**\n * Applies common object-schema transformations used by the builder.\n */\nexport class ObjectTransformer {\n\t/**\n\t * Resolve a property schema from an object schema by property key.\n\t * @param baseSchema The source object schema.\n\t * @param propertyKey The property key to resolve.\n\t * @returns The resolved property schema.\n\t */\n\tpublic static resolvePropertySchemaFromObjectSchema(\n\t\tbaseSchema: IJsonSchema,\n\t\tpropertyKey: string\n\t): IJsonSchema | undefined {\n\t\tif (!baseSchema.properties || !Is.object(baseSchema.properties)) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst propertySchema = baseSchema.properties[propertyKey];\n\t\treturn propertySchema ? ObjectHelper.clone(propertySchema) : undefined;\n\t}\n\n\t/**\n\t * Remove keys from an object schema.\n\t * @param baseSchema The source object schema.\n\t * @param omittedKeys The keys to remove.\n\t * @returns The transformed object schema.\n\t */\n\tpublic static omitKeysFromObjectSchema(\n\t\tbaseSchema: IJsonSchema,\n\t\tomittedKeys: string[]\n\t): IJsonSchema {\n\t\tconst omittedKeySet = new Set(omittedKeys);\n\t\tconst mappedSchema = ObjectTransformer.toInlineUtilityObjectSchema(baseSchema);\n\n\t\tif (Is.object(mappedSchema.properties)) {\n\t\t\tfor (const key of Object.keys(mappedSchema.properties)) {\n\t\t\t\tif (omittedKeySet.has(key)) {\n\t\t\t\t\tdelete mappedSchema.properties[key];\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (Object.keys(mappedSchema.properties).length === 0) {\n\t\t\t\tdelete mappedSchema.properties;\n\t\t\t}\n\t\t}\n\n\t\tif (Is.array(mappedSchema.required)) {\n\t\t\tmappedSchema.required = mappedSchema.required.filter(key => !omittedKeySet.has(key));\n\t\t\tif (mappedSchema.required.length === 0) {\n\t\t\t\tdelete mappedSchema.required;\n\t\t\t}\n\t\t}\n\n\t\treturn mappedSchema;\n\t}\n\n\t/**\n\t * Keep only keys from an object schema.\n\t * @param baseSchema The source object schema.\n\t * @param pickedKeys The keys to keep.\n\t * @returns The transformed object schema.\n\t */\n\tpublic static pickKeysFromObjectSchema(\n\t\tbaseSchema: IJsonSchema,\n\t\tpickedKeys: string[]\n\t): IJsonSchema {\n\t\tconst pickedKeySet = new Set(pickedKeys);\n\t\tconst mappedSchema = ObjectTransformer.toInlineUtilityObjectSchema(baseSchema);\n\n\t\tif (Is.object(mappedSchema.properties)) {\n\t\t\tfor (const key of Object.keys(mappedSchema.properties)) {\n\t\t\t\tif (!pickedKeySet.has(key)) {\n\t\t\t\t\tdelete mappedSchema.properties[key];\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (Object.keys(mappedSchema.properties).length === 0) {\n\t\t\t\tdelete mappedSchema.properties;\n\t\t\t}\n\t\t}\n\n\t\tif (Is.array(mappedSchema.required)) {\n\t\t\tmappedSchema.required = mappedSchema.required.filter(key => pickedKeySet.has(key));\n\t\t\tif (mappedSchema.required.length === 0) {\n\t\t\t\tdelete mappedSchema.required;\n\t\t\t}\n\t\t}\n\n\t\treturn mappedSchema;\n\t}\n\n\t/**\n\t * Normalize utility-derived object schemas for inline property usage.\n\t * When the schema contains an allOf, flatten it by merging properties from all branches.\n\t * @param schema The source object schema.\n\t * @returns The normalized inline schema.\n\t * @internal\n\t */\n\tpublic static toInlineUtilityObjectSchema(schema: IJsonSchema): IJsonSchema {\n\t\tconst mappedSchema = ObjectHelper.clone(schema);\n\t\tdelete mappedSchema.$schema;\n\t\tdelete mappedSchema.$id;\n\t\tdelete mappedSchema.title;\n\n\t\t// Flatten allOf by merging properties and required arrays from all branches\n\t\t// This handles inheritance cases where a type extends another type\n\t\tif (Is.array(mappedSchema.allOf) && mappedSchema.allOf.length > 0) {\n\t\t\tconst mergedProperties: { [key: string]: unknown } = {};\n\t\t\tconst mergedRequired = new Set<string>();\n\n\t\t\t// Collect properties and required fields from all allOf branches\n\t\t\tfor (const branch of mappedSchema.allOf) {\n\t\t\t\tif (Is.object(branch)) {\n\t\t\t\t\tconst branchRecord = branch as { [key: string]: unknown };\n\t\t\t\t\t// Merge properties\n\t\t\t\t\tif (Is.object(branchRecord.properties)) {\n\t\t\t\t\t\tObject.assign(mergedProperties, branchRecord.properties);\n\t\t\t\t\t}\n\t\t\t\t\t// Collect required fields\n\t\t\t\t\tif (Is.array(branchRecord.required)) {\n\t\t\t\t\t\tfor (const field of branchRecord.required) {\n\t\t\t\t\t\t\tif (Is.stringValue(field)) {\n\t\t\t\t\t\t\t\tmergedRequired.add(field);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove allOf and set merged properties at the top level\n\t\t\tdelete mappedSchema.allOf;\n\n\t\t\tif (Object.keys(mergedProperties).length > 0) {\n\t\t\t\tmappedSchema.properties = Object.assign(mappedSchema.properties ?? {}, mergedProperties);\n\t\t\t}\n\n\t\t\tif (mergedRequired.size > 0) {\n\t\t\t\tconst existingRequired = Is.array(mappedSchema.required) ? mappedSchema.required : [];\n\t\t\t\tmappedSchema.required = [...new Set([...existingRequired, ...mergedRequired])];\n\t\t\t}\n\t\t}\n\n\t\treturn mappedSchema;\n\t}\n\n\t/**\n\t * Normalize schema description whitespace while preserving intentional line breaks.\n\t * @param schema The schema to normalize.\n\t * @returns The normalized schema.\n\t */\n\tpublic static normalizeSchemaDescriptions(schema: IJsonSchema): IJsonSchema {\n\t\tconst normalizedSchema = ObjectHelper.clone(schema);\n\t\tconst normalizeObject = (value: unknown): void => {\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\tfor (const item of value) {\n\t\t\t\t\tnormalizeObject(item);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (Is.object(value)) {\n\t\t\t\tconst valueRecord = value as { [key: string]: unknown };\n\t\t\t\tif (Is.stringValue(valueRecord.description)) {\n\t\t\t\t\tvalueRecord.description = ObjectTransformer.normalizeSchemaDescriptionText(\n\t\t\t\t\t\tvalueRecord.description\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tfor (const nestedValue of Object.values(valueRecord)) {\n\t\t\t\t\tnormalizeObject(nestedValue);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tnormalizeObject(normalizedSchema);\n\t\treturn normalizedSchema;\n\t}\n\n\t/**\n\t * Normalize a description string while preserving explicit line breaks from source comments.\n\t * @param description The description to normalize.\n\t * @returns The normalized description.\n\t * @internal\n\t */\n\tprivate static normalizeSchemaDescriptionText(description: string): string {\n\t\treturn description\n\t\t\t.split(/\\r?\\n/)\n\t\t\t.map(line => line.replace(/\\s{2,}/g, \" \").trim())\n\t\t\t.join(\"\\n\");\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"objectTransformer.js","sourceRoot":"","sources":["../../../src/utils/objectTransformer.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { Is, ObjectHelper } from \"@twin.org/core\";\nimport type { IJsonSchema } from \"@twin.org/tools-models\";\n\n/**\n * Applies common object-schema transformations used by the builder.\n */\nexport class ObjectTransformer {\n\t/**\n\t * Resolve a property schema from an object schema by property key.\n\t * @param baseSchema The source object schema.\n\t * @param propertyKey The property key to resolve.\n\t * @returns The resolved property schema.\n\t */\n\tpublic static resolvePropertySchemaFromObjectSchema(\n\t\tbaseSchema: IJsonSchema,\n\t\tpropertyKey: string\n\t): IJsonSchema | undefined {\n\t\tif (!baseSchema.properties || !Is.object(baseSchema.properties)) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst propertySchema = baseSchema.properties[propertyKey];\n\t\treturn propertySchema ? ObjectHelper.clone(propertySchema) : undefined;\n\t}\n\n\t/**\n\t * Remove keys from an object schema.\n\t * @param baseSchema The source object schema.\n\t * @param omittedKeys The keys to remove.\n\t * @returns The transformed object schema.\n\t */\n\tpublic static omitKeysFromObjectSchema(\n\t\tbaseSchema: IJsonSchema,\n\t\tomittedKeys: string[]\n\t): IJsonSchema {\n\t\tconst omittedKeySet = new Set(omittedKeys);\n\t\tconst mappedSchema = ObjectTransformer.toInlineUtilityObjectSchema(baseSchema);\n\n\t\tif (Is.object(mappedSchema.properties)) {\n\t\t\tfor (const key of Object.keys(mappedSchema.properties)) {\n\t\t\t\tif (omittedKeySet.has(key)) {\n\t\t\t\t\tdelete mappedSchema.properties[key];\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (Object.keys(mappedSchema.properties).length === 0) {\n\t\t\t\tdelete mappedSchema.properties;\n\t\t\t}\n\t\t}\n\n\t\tif (Is.array(mappedSchema.required)) {\n\t\t\tmappedSchema.required = mappedSchema.required.filter(key => !omittedKeySet.has(key));\n\t\t\tif (mappedSchema.required.length === 0) {\n\t\t\t\tdelete mappedSchema.required;\n\t\t\t}\n\t\t}\n\n\t\treturn mappedSchema;\n\t}\n\n\t/**\n\t * Keep only keys from an object schema.\n\t * @param baseSchema The source object schema.\n\t * @param pickedKeys The keys to keep.\n\t * @returns The transformed object schema.\n\t */\n\tpublic static pickKeysFromObjectSchema(\n\t\tbaseSchema: IJsonSchema,\n\t\tpickedKeys: string[]\n\t): IJsonSchema {\n\t\tconst pickedKeySet = new Set(pickedKeys);\n\t\tconst mappedSchema = ObjectTransformer.toInlineUtilityObjectSchema(baseSchema);\n\n\t\tif (Is.object(mappedSchema.properties)) {\n\t\t\tfor (const key of Object.keys(mappedSchema.properties)) {\n\t\t\t\tif (!pickedKeySet.has(key)) {\n\t\t\t\t\tdelete mappedSchema.properties[key];\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (Object.keys(mappedSchema.properties).length === 0) {\n\t\t\t\tdelete mappedSchema.properties;\n\t\t\t}\n\t\t}\n\n\t\tif (Is.array(mappedSchema.required)) {\n\t\t\tmappedSchema.required = mappedSchema.required.filter(key => pickedKeySet.has(key));\n\t\t\tif (mappedSchema.required.length === 0) {\n\t\t\t\tdelete mappedSchema.required;\n\t\t\t}\n\t\t}\n\n\t\treturn mappedSchema;\n\t}\n\n\t/**\n\t * Normalize utility-derived object schemas for inline property usage.\n\t * When the schema contains an allOf, flatten it by merging properties from all branches.\n\t * @param schema The source object schema.\n\t * @returns The normalized inline schema.\n\t * @internal\n\t */\n\tpublic static toInlineUtilityObjectSchema(schema: IJsonSchema): IJsonSchema {\n\t\tconst mappedSchema = ObjectHelper.clone(schema);\n\t\tdelete mappedSchema.$schema;\n\t\tdelete mappedSchema.$id;\n\t\tdelete mappedSchema.title;\n\n\t\t// Flatten allOf by merging properties and required arrays from all branches\n\t\t// This handles inheritance cases where a type extends another type\n\t\tif (Is.array(mappedSchema.allOf) && mappedSchema.allOf.length > 0) {\n\t\t\tconst mergedProperties: { [key: string]: unknown } = {};\n\t\t\tconst mergedRequired = new Set<string>();\n\n\t\t\t// Collect properties and required fields from all allOf branches\n\t\t\tfor (const branch of mappedSchema.allOf) {\n\t\t\t\tif (Is.object(branch)) {\n\t\t\t\t\tconst branchRecord = branch as { [key: string]: unknown };\n\t\t\t\t\t// Merge properties\n\t\t\t\t\tif (Is.object(branchRecord.properties)) {\n\t\t\t\t\t\tObject.assign(mergedProperties, branchRecord.properties);\n\t\t\t\t\t}\n\t\t\t\t\t// Collect required fields\n\t\t\t\t\tif (Is.array(branchRecord.required)) {\n\t\t\t\t\t\tfor (const field of branchRecord.required) {\n\t\t\t\t\t\t\tif (Is.stringValue(field)) {\n\t\t\t\t\t\t\t\tmergedRequired.add(field);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove allOf and set merged properties at the top level\n\t\t\tdelete mappedSchema.allOf;\n\n\t\t\tif (Object.keys(mergedProperties).length > 0) {\n\t\t\t\tmappedSchema.properties = Object.assign(mappedSchema.properties ?? {}, mergedProperties);\n\t\t\t}\n\n\t\t\tif (mergedRequired.size > 0) {\n\t\t\t\tconst existingRequired = Is.array(mappedSchema.required) ? mappedSchema.required : [];\n\t\t\t\tmappedSchema.required = [...new Set([...existingRequired, ...mergedRequired])];\n\t\t\t}\n\t\t}\n\n\t\treturn mappedSchema;\n\t}\n\n\t/**\n\t * Normalize schema description whitespace while preserving intentional line breaks.\n\t * @param schema The schema to normalize.\n\t * @returns The normalized schema.\n\t */\n\tpublic static normalizeSchemaDescriptions(schema: IJsonSchema): IJsonSchema {\n\t\tconst normalizedSchema = ObjectHelper.clone(schema);\n\t\tconst normalizeObject = (value: unknown): void => {\n\t\t\tif (Is.array(value)) {\n\t\t\t\tfor (const item of value) {\n\t\t\t\t\tnormalizeObject(item);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (Is.object(value)) {\n\t\t\t\tconst valueRecord = value as { [key: string]: unknown };\n\t\t\t\tif (Is.stringValue(valueRecord.description)) {\n\t\t\t\t\tvalueRecord.description = ObjectTransformer.normalizeSchemaDescriptionText(\n\t\t\t\t\t\tvalueRecord.description\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tfor (const nestedValue of Object.values(valueRecord)) {\n\t\t\t\t\tnormalizeObject(nestedValue);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tnormalizeObject(normalizedSchema);\n\t\treturn normalizedSchema;\n\t}\n\n\t/**\n\t * Normalize a description string while preserving explicit line breaks from source comments.\n\t * @param description The description to normalize.\n\t * @returns The normalized description.\n\t * @internal\n\t */\n\tprivate static normalizeSchemaDescriptionText(description: string): string {\n\t\treturn description\n\t\t\t.split(/\\r?\\n/)\n\t\t\t.map(line => line.replace(/\\s{2,}/g, \" \").trim())\n\t\t\t.join(\"\\n\");\n\t}\n}\n"]}
|
|
@@ -25,17 +25,29 @@ export class Resolver {
|
|
|
25
25
|
* Resolve a type declaration AST from a package and type name.
|
|
26
26
|
* @param packageName The package to inspect.
|
|
27
27
|
* @param typeName The type to resolve.
|
|
28
|
+
* @param containingFilePath An optional source file path to use as the starting point for
|
|
29
|
+
* package resolution. When provided, TypeScript module resolution walks up from that file's
|
|
30
|
+
* directory, which allows transitive dependencies installed alongside the source file (e.g.
|
|
31
|
+
* in a sub-directory node_modules) to be found even when they are not reachable from the
|
|
32
|
+
* current working directory. The path is normalised to absolute before use;
|
|
33
|
+
* falls back to process.cwd() when omitted.
|
|
28
34
|
* @returns The resolved declaration AST.
|
|
29
35
|
*/
|
|
30
|
-
static resolveTypeDeclarationAst(packageName, typeName) {
|
|
31
|
-
|
|
36
|
+
static resolveTypeDeclarationAst(packageName, typeName, containingFilePath) {
|
|
37
|
+
// path.resolve normalises both absolute and relative paths to an absolute form so that
|
|
38
|
+
// TypeScript module resolution can correctly walk up the directory tree to node_modules.
|
|
39
|
+
const containingFile = containingFilePath
|
|
40
|
+
? FileUtils.normalizeFilePath(FileUtils.resolvePath(containingFilePath))
|
|
41
|
+
: `${FileUtils.normalizeFilePath(FileUtils.getCurrentWorkingDirectory())}/__typeScriptToSchema__.ts`;
|
|
42
|
+
const resolveDir = FileUtils.getDirectoryPath(containingFile);
|
|
43
|
+
const cacheKey = `${resolveDir}::${packageName}::${typeName}`;
|
|
44
|
+
const moduleCacheKey = `${resolveDir}::${packageName}`;
|
|
32
45
|
const cachedDeclaration = Resolver._typeDeclarationCache[cacheKey];
|
|
33
46
|
if (cachedDeclaration !== undefined) {
|
|
34
47
|
return cachedDeclaration ?? undefined;
|
|
35
48
|
}
|
|
36
49
|
const compilerOptions = Resolver.getModuleResolutionCompilerOptions();
|
|
37
|
-
const
|
|
38
|
-
const resolvedModuleFileName = Resolver.resolvePackageEntryFile(packageName, containingFile, compilerOptions);
|
|
50
|
+
const resolvedModuleFileName = Resolver.resolvePackageEntryFile(packageName, containingFile, compilerOptions, moduleCacheKey);
|
|
39
51
|
if (!resolvedModuleFileName) {
|
|
40
52
|
Resolver._typeDeclarationCache[cacheKey] = null;
|
|
41
53
|
return undefined;
|
|
@@ -49,21 +61,22 @@ export class Resolver {
|
|
|
49
61
|
* @param packageName The package to resolve.
|
|
50
62
|
* @param containingFile The containing file for module resolution.
|
|
51
63
|
* @param compilerOptions Compiler options for module resolution.
|
|
64
|
+
* @param cacheKey The cache key to use for the resolved module file cache.
|
|
52
65
|
* @returns The resolved entry file path.
|
|
53
66
|
* @internal
|
|
54
67
|
*/
|
|
55
|
-
static resolvePackageEntryFile(packageName, containingFile, compilerOptions) {
|
|
56
|
-
const cachedResolvedModuleFile = Resolver._resolvedModuleFileCache[
|
|
68
|
+
static resolvePackageEntryFile(packageName, containingFile, compilerOptions, cacheKey) {
|
|
69
|
+
const cachedResolvedModuleFile = Resolver._resolvedModuleFileCache[cacheKey];
|
|
57
70
|
if (cachedResolvedModuleFile !== undefined) {
|
|
58
71
|
return cachedResolvedModuleFile ?? undefined;
|
|
59
72
|
}
|
|
60
73
|
const resolvedModule = ts.resolveModuleName(packageName, containingFile, compilerOptions, ts.sys).resolvedModule;
|
|
61
74
|
const resolvedModuleFileName = resolvedModule?.resolvedFileName;
|
|
62
75
|
if (!resolvedModuleFileName) {
|
|
63
|
-
Resolver._resolvedModuleFileCache[
|
|
76
|
+
Resolver._resolvedModuleFileCache[cacheKey] = null;
|
|
64
77
|
return undefined;
|
|
65
78
|
}
|
|
66
|
-
Resolver._resolvedModuleFileCache[
|
|
79
|
+
Resolver._resolvedModuleFileCache[cacheKey] = resolvedModuleFileName;
|
|
67
80
|
return resolvedModuleFileName;
|
|
68
81
|
}
|
|
69
82
|
/**
|
|
@@ -80,7 +93,7 @@ export class Resolver {
|
|
|
80
93
|
};
|
|
81
94
|
}
|
|
82
95
|
/**
|
|
83
|
-
* Find a type declaration by walking a module
|
|
96
|
+
* Find a type declaration by walking a module import/export graph.
|
|
84
97
|
* @param sourceFilePath The source file path to inspect.
|
|
85
98
|
* @param typeName The type name to find.
|
|
86
99
|
* @param visitedFiles The visited file set.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../../src/utils/resolver.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport * as ts from \"typescript\";\nimport { FileUtils } from \"./fileUtils.js\";\n\n/**\n * Resolve TypeScript type declarations from package names.\n */\nexport class Resolver {\n\t/**\n\t * Cache for resolved package entry files.\n\t * @internal\n\t */\n\tprivate static readonly _resolvedModuleFileCache: { [id: string]: string | null | undefined } =\n\t\t{};\n\n\t/**\n\t * Cache for parsed source files.\n\t * @internal\n\t */\n\tprivate static readonly _sourceFileCache: { [id: string]: ts.SourceFile | null | undefined } = {};\n\n\t/**\n\t * Cache for resolved type declarations.\n\t * @internal\n\t */\n\tprivate static readonly _typeDeclarationCache: {\n\t\t[id: string]:\n\t\t\t| {\n\t\t\t\t\tsourceFile: ts.SourceFile;\n\t\t\t\t\tdeclaration: ts.InterfaceDeclaration | ts.TypeAliasDeclaration;\n\t\t\t }\n\t\t\t| null\n\t\t\t| undefined;\n\t} = {};\n\n\t/**\n\t * Resolve a type declaration AST from a package and type name.\n\t * @param packageName The package to inspect.\n\t * @param typeName The type to resolve.\n\t * @returns The resolved declaration AST.\n\t */\n\tpublic static resolveTypeDeclarationAst(\n\t\tpackageName: string,\n\t\ttypeName: string\n\t):\n\t\t| {\n\t\t\t\tsourceFile: ts.SourceFile;\n\t\t\t\tdeclaration: ts.InterfaceDeclaration | ts.TypeAliasDeclaration;\n\t\t }\n\t\t| undefined {\n\t\tconst cacheKey = `${packageName}::${typeName}`;\n\t\tconst cachedDeclaration = Resolver._typeDeclarationCache[cacheKey];\n\t\tif (cachedDeclaration !== undefined) {\n\t\t\treturn cachedDeclaration ?? undefined;\n\t\t}\n\n\t\tconst compilerOptions = Resolver.getModuleResolutionCompilerOptions();\n\t\tconst containingFile = `${FileUtils.normalizeFilePath(FileUtils.getCurrentWorkingDirectory())}/__typeScriptToSchema__.ts`;\n\t\tconst resolvedModuleFileName = Resolver.resolvePackageEntryFile(\n\t\t\tpackageName,\n\t\t\tcontainingFile,\n\t\t\tcompilerOptions\n\t\t);\n\n\t\tif (!resolvedModuleFileName) {\n\t\t\tResolver._typeDeclarationCache[cacheKey] = null;\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst declarationResult = Resolver.findTypeDeclarationInModuleGraph(\n\t\t\tresolvedModuleFileName,\n\t\t\ttypeName,\n\t\t\tnew Set<string>(),\n\t\t\tcompilerOptions\n\t\t);\n\n\t\tResolver._typeDeclarationCache[cacheKey] = declarationResult ?? null;\n\t\treturn declarationResult;\n\t}\n\n\t/**\n\t * Resolve and cache the package entry file for a module name.\n\t * @param packageName The package to resolve.\n\t * @param containingFile The containing file for module resolution.\n\t * @param compilerOptions Compiler options for module resolution.\n\t * @returns The resolved entry file path.\n\t * @internal\n\t */\n\tprivate static resolvePackageEntryFile(\n\t\tpackageName: string,\n\t\tcontainingFile: string,\n\t\tcompilerOptions: ts.CompilerOptions\n\t): string | undefined {\n\t\tconst cachedResolvedModuleFile = Resolver._resolvedModuleFileCache[packageName];\n\t\tif (cachedResolvedModuleFile !== undefined) {\n\t\t\treturn cachedResolvedModuleFile ?? undefined;\n\t\t}\n\n\t\tconst resolvedModule = ts.resolveModuleName(\n\t\t\tpackageName,\n\t\t\tcontainingFile,\n\t\t\tcompilerOptions,\n\t\t\tts.sys\n\t\t).resolvedModule;\n\t\tconst resolvedModuleFileName = resolvedModule?.resolvedFileName;\n\t\tif (!resolvedModuleFileName) {\n\t\t\tResolver._resolvedModuleFileCache[packageName] = null;\n\t\t\treturn undefined;\n\t\t}\n\n\t\tResolver._resolvedModuleFileCache[packageName] = resolvedModuleFileName;\n\t\treturn resolvedModuleFileName;\n\t}\n\n\t/**\n\t * Resolve compiler options for module lookup.\n\t * @returns The compiler options.\n\t * @internal\n\t */\n\tprivate static getModuleResolutionCompilerOptions(): ts.CompilerOptions {\n\t\treturn {\n\t\t\tmodule: ts.ModuleKind.NodeNext,\n\t\t\tmoduleResolution: ts.ModuleResolutionKind.NodeNext,\n\t\t\ttarget: ts.ScriptTarget.ESNext,\n\t\t\tskipLibCheck: true\n\t\t};\n\t}\n\n\t/**\n\t * Find a type declaration by walking a module's import/export graph.\n\t * @param sourceFilePath The source file path to inspect.\n\t * @param typeName The type name to find.\n\t * @param visitedFiles The visited file set.\n\t * @param compilerOptions Compiler options for module resolution.\n\t * @returns The matched declaration with its source file.\n\t * @internal\n\t */\n\tprivate static findTypeDeclarationInModuleGraph(\n\t\tsourceFilePath: string,\n\t\ttypeName: string,\n\t\tvisitedFiles: Set<string>,\n\t\tcompilerOptions: ts.CompilerOptions\n\t):\n\t\t| {\n\t\t\t\tsourceFile: ts.SourceFile;\n\t\t\t\tdeclaration: ts.InterfaceDeclaration | ts.TypeAliasDeclaration;\n\t\t }\n\t\t| undefined {\n\t\tconst absoluteSourcePath = FileUtils.normalizeFilePath(sourceFilePath);\n\t\tif (visitedFiles.has(absoluteSourcePath)) {\n\t\t\treturn undefined;\n\t\t}\n\t\tvisitedFiles.add(absoluteSourcePath);\n\n\t\tconst sourceFile = Resolver.getOrCreateSourceFile(sourceFilePath);\n\t\tif (!sourceFile) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tfor (const statement of sourceFile.statements) {\n\t\t\t// interface IFoo { ... } or type Foo = ... (the declaration we are searching for)\n\t\t\tif (\n\t\t\t\t(ts.isInterfaceDeclaration(statement) || ts.isTypeAliasDeclaration(statement)) &&\n\t\t\t\tstatement.name.text === typeName\n\t\t\t) {\n\t\t\t\treturn {\n\t\t\t\t\tsourceFile,\n\t\t\t\t\tdeclaration: statement\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tconst moduleSpecifiers = sourceFile.statements\n\t\t\t// import { ... } from \"...\" or export { ... } from \"...\" (re-export and import chains)\n\t\t\t.filter(statement => ts.isExportDeclaration(statement) || ts.isImportDeclaration(statement))\n\t\t\t.flatMap(statement => {\n\t\t\t\tconst moduleSpecifier = statement.moduleSpecifier;\n\t\t\t\t// \"./module.js\" (string literal module specifier)\n\t\t\t\treturn moduleSpecifier && ts.isStringLiteral(moduleSpecifier) ? [moduleSpecifier.text] : [];\n\t\t\t});\n\n\t\tfor (const moduleSpecifier of moduleSpecifiers) {\n\t\t\tconst resolvedImportPath = Resolver.resolveModuleSpecifierFromFile(\n\t\t\t\tmoduleSpecifier,\n\t\t\t\tsourceFilePath,\n\t\t\t\tcompilerOptions\n\t\t\t);\n\t\t\tif (resolvedImportPath) {\n\t\t\t\tconst declarationResult = Resolver.findTypeDeclarationInModuleGraph(\n\t\t\t\t\tresolvedImportPath,\n\t\t\t\t\ttypeName,\n\t\t\t\t\tvisitedFiles,\n\t\t\t\t\tcompilerOptions\n\t\t\t\t);\n\t\t\t\tif (declarationResult) {\n\t\t\t\t\treturn declarationResult;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Read and cache a parsed source file.\n\t * @param sourceFilePath The source file path.\n\t * @returns The parsed source file.\n\t * @internal\n\t */\n\tprivate static getOrCreateSourceFile(sourceFilePath: string): ts.SourceFile | undefined {\n\t\tconst normalizedPath = FileUtils.normalizeFilePath(sourceFilePath);\n\t\tconst cachedSourceFile = Resolver._sourceFileCache[normalizedPath];\n\t\tif (cachedSourceFile !== undefined) {\n\t\t\treturn cachedSourceFile ?? undefined;\n\t\t}\n\n\t\tconst source = FileUtils.readFile(sourceFilePath);\n\t\tif (!source) {\n\t\t\tResolver._sourceFileCache[normalizedPath] = null;\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst sourceFile = ts.createSourceFile(sourceFilePath, source, ts.ScriptTarget.Latest, true);\n\t\tResolver._sourceFileCache[normalizedPath] = sourceFile;\n\t\treturn sourceFile;\n\t}\n\n\t/**\n\t * Resolve a module specifier from a containing file.\n\t * @param moduleSpecifier The module specifier text.\n\t * @param containingFilePath The file containing the import/export.\n\t * @param compilerOptions Compiler options for module resolution.\n\t * @returns The resolved file path.\n\t * @internal\n\t */\n\tprivate static resolveModuleSpecifierFromFile(\n\t\tmoduleSpecifier: string,\n\t\tcontainingFilePath: string,\n\t\tcompilerOptions: ts.CompilerOptions\n\t): string | undefined {\n\t\treturn ts.resolveModuleName(moduleSpecifier, containingFilePath, compilerOptions, ts.sys)\n\t\t\t.resolvedModule?.resolvedFileName;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../../src/utils/resolver.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport * as ts from \"typescript\";\nimport { FileUtils } from \"./fileUtils.js\";\n\n/**\n * Resolve TypeScript type declarations from package names.\n */\nexport class Resolver {\n\t/**\n\t * Cache for resolved package entry files.\n\t * @internal\n\t */\n\tprivate static readonly _resolvedModuleFileCache: { [id: string]: string | null | undefined } =\n\t\t{};\n\n\t/**\n\t * Cache for parsed source files.\n\t * @internal\n\t */\n\tprivate static readonly _sourceFileCache: { [id: string]: ts.SourceFile | null | undefined } = {};\n\n\t/**\n\t * Cache for resolved type declarations.\n\t * @internal\n\t */\n\tprivate static readonly _typeDeclarationCache: {\n\t\t[id: string]:\n\t\t\t| {\n\t\t\t\t\tsourceFile: ts.SourceFile;\n\t\t\t\t\tdeclaration: ts.InterfaceDeclaration | ts.TypeAliasDeclaration;\n\t\t\t }\n\t\t\t| null\n\t\t\t| undefined;\n\t} = {};\n\n\t/**\n\t * Resolve a type declaration AST from a package and type name.\n\t * @param packageName The package to inspect.\n\t * @param typeName The type to resolve.\n\t * @param containingFilePath An optional source file path to use as the starting point for\n\t * package resolution. When provided, TypeScript module resolution walks up from that file's\n\t * directory, which allows transitive dependencies installed alongside the source file (e.g.\n\t * in a sub-directory node_modules) to be found even when they are not reachable from the\n\t * current working directory. The path is normalised to absolute before use;\n\t * falls back to process.cwd() when omitted.\n\t * @returns The resolved declaration AST.\n\t */\n\tpublic static resolveTypeDeclarationAst(\n\t\tpackageName: string,\n\t\ttypeName: string,\n\t\tcontainingFilePath?: string\n\t):\n\t\t| {\n\t\t\t\tsourceFile: ts.SourceFile;\n\t\t\t\tdeclaration: ts.InterfaceDeclaration | ts.TypeAliasDeclaration;\n\t\t }\n\t\t| undefined {\n\t\t// path.resolve normalises both absolute and relative paths to an absolute form so that\n\t\t// TypeScript module resolution can correctly walk up the directory tree to node_modules.\n\t\tconst containingFile = containingFilePath\n\t\t\t? FileUtils.normalizeFilePath(FileUtils.resolvePath(containingFilePath))\n\t\t\t: `${FileUtils.normalizeFilePath(FileUtils.getCurrentWorkingDirectory())}/__typeScriptToSchema__.ts`;\n\t\tconst resolveDir = FileUtils.getDirectoryPath(containingFile);\n\t\tconst cacheKey = `${resolveDir}::${packageName}::${typeName}`;\n\t\tconst moduleCacheKey = `${resolveDir}::${packageName}`;\n\n\t\tconst cachedDeclaration = Resolver._typeDeclarationCache[cacheKey];\n\t\tif (cachedDeclaration !== undefined) {\n\t\t\treturn cachedDeclaration ?? undefined;\n\t\t}\n\n\t\tconst compilerOptions = Resolver.getModuleResolutionCompilerOptions();\n\t\tconst resolvedModuleFileName = Resolver.resolvePackageEntryFile(\n\t\t\tpackageName,\n\t\t\tcontainingFile,\n\t\t\tcompilerOptions,\n\t\t\tmoduleCacheKey\n\t\t);\n\n\t\tif (!resolvedModuleFileName) {\n\t\t\tResolver._typeDeclarationCache[cacheKey] = null;\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst declarationResult = Resolver.findTypeDeclarationInModuleGraph(\n\t\t\tresolvedModuleFileName,\n\t\t\ttypeName,\n\t\t\tnew Set<string>(),\n\t\t\tcompilerOptions\n\t\t);\n\n\t\tResolver._typeDeclarationCache[cacheKey] = declarationResult ?? null;\n\t\treturn declarationResult;\n\t}\n\n\t/**\n\t * Resolve and cache the package entry file for a module name.\n\t * @param packageName The package to resolve.\n\t * @param containingFile The containing file for module resolution.\n\t * @param compilerOptions Compiler options for module resolution.\n\t * @param cacheKey The cache key to use for the resolved module file cache.\n\t * @returns The resolved entry file path.\n\t * @internal\n\t */\n\tprivate static resolvePackageEntryFile(\n\t\tpackageName: string,\n\t\tcontainingFile: string,\n\t\tcompilerOptions: ts.CompilerOptions,\n\t\tcacheKey: string\n\t): string | undefined {\n\t\tconst cachedResolvedModuleFile = Resolver._resolvedModuleFileCache[cacheKey];\n\t\tif (cachedResolvedModuleFile !== undefined) {\n\t\t\treturn cachedResolvedModuleFile ?? undefined;\n\t\t}\n\n\t\tconst resolvedModule = ts.resolveModuleName(\n\t\t\tpackageName,\n\t\t\tcontainingFile,\n\t\t\tcompilerOptions,\n\t\t\tts.sys\n\t\t).resolvedModule;\n\t\tconst resolvedModuleFileName = resolvedModule?.resolvedFileName;\n\t\tif (!resolvedModuleFileName) {\n\t\t\tResolver._resolvedModuleFileCache[cacheKey] = null;\n\t\t\treturn undefined;\n\t\t}\n\n\t\tResolver._resolvedModuleFileCache[cacheKey] = resolvedModuleFileName;\n\t\treturn resolvedModuleFileName;\n\t}\n\n\t/**\n\t * Resolve compiler options for module lookup.\n\t * @returns The compiler options.\n\t * @internal\n\t */\n\tprivate static getModuleResolutionCompilerOptions(): ts.CompilerOptions {\n\t\treturn {\n\t\t\tmodule: ts.ModuleKind.NodeNext,\n\t\t\tmoduleResolution: ts.ModuleResolutionKind.NodeNext,\n\t\t\ttarget: ts.ScriptTarget.ESNext,\n\t\t\tskipLibCheck: true\n\t\t};\n\t}\n\n\t/**\n\t * Find a type declaration by walking a module import/export graph.\n\t * @param sourceFilePath The source file path to inspect.\n\t * @param typeName The type name to find.\n\t * @param visitedFiles The visited file set.\n\t * @param compilerOptions Compiler options for module resolution.\n\t * @returns The matched declaration with its source file.\n\t * @internal\n\t */\n\tprivate static findTypeDeclarationInModuleGraph(\n\t\tsourceFilePath: string,\n\t\ttypeName: string,\n\t\tvisitedFiles: Set<string>,\n\t\tcompilerOptions: ts.CompilerOptions\n\t):\n\t\t| {\n\t\t\t\tsourceFile: ts.SourceFile;\n\t\t\t\tdeclaration: ts.InterfaceDeclaration | ts.TypeAliasDeclaration;\n\t\t }\n\t\t| undefined {\n\t\tconst absoluteSourcePath = FileUtils.normalizeFilePath(sourceFilePath);\n\t\tif (visitedFiles.has(absoluteSourcePath)) {\n\t\t\treturn undefined;\n\t\t}\n\t\tvisitedFiles.add(absoluteSourcePath);\n\n\t\tconst sourceFile = Resolver.getOrCreateSourceFile(sourceFilePath);\n\t\tif (!sourceFile) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tfor (const statement of sourceFile.statements) {\n\t\t\t// interface IFoo { ... } or type Foo = ... (the declaration we are searching for)\n\t\t\tif (\n\t\t\t\t(ts.isInterfaceDeclaration(statement) || ts.isTypeAliasDeclaration(statement)) &&\n\t\t\t\tstatement.name.text === typeName\n\t\t\t) {\n\t\t\t\treturn {\n\t\t\t\t\tsourceFile,\n\t\t\t\t\tdeclaration: statement\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tconst moduleSpecifiers = sourceFile.statements\n\t\t\t// import { ... } from \"...\" or export { ... } from \"...\" (re-export and import chains)\n\t\t\t.filter(statement => ts.isExportDeclaration(statement) || ts.isImportDeclaration(statement))\n\t\t\t.flatMap(statement => {\n\t\t\t\tconst moduleSpecifier = statement.moduleSpecifier;\n\t\t\t\t// \"./module.js\" (string literal module specifier)\n\t\t\t\treturn moduleSpecifier && ts.isStringLiteral(moduleSpecifier) ? [moduleSpecifier.text] : [];\n\t\t\t});\n\n\t\tfor (const moduleSpecifier of moduleSpecifiers) {\n\t\t\tconst resolvedImportPath = Resolver.resolveModuleSpecifierFromFile(\n\t\t\t\tmoduleSpecifier,\n\t\t\t\tsourceFilePath,\n\t\t\t\tcompilerOptions\n\t\t\t);\n\t\t\tif (resolvedImportPath) {\n\t\t\t\tconst declarationResult = Resolver.findTypeDeclarationInModuleGraph(\n\t\t\t\t\tresolvedImportPath,\n\t\t\t\t\ttypeName,\n\t\t\t\t\tvisitedFiles,\n\t\t\t\t\tcompilerOptions\n\t\t\t\t);\n\t\t\t\tif (declarationResult) {\n\t\t\t\t\treturn declarationResult;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Read and cache a parsed source file.\n\t * @param sourceFilePath The source file path.\n\t * @returns The parsed source file.\n\t * @internal\n\t */\n\tprivate static getOrCreateSourceFile(sourceFilePath: string): ts.SourceFile | undefined {\n\t\tconst normalizedPath = FileUtils.normalizeFilePath(sourceFilePath);\n\t\tconst cachedSourceFile = Resolver._sourceFileCache[normalizedPath];\n\t\tif (cachedSourceFile !== undefined) {\n\t\t\treturn cachedSourceFile ?? undefined;\n\t\t}\n\n\t\tconst source = FileUtils.readFile(sourceFilePath);\n\t\tif (!source) {\n\t\t\tResolver._sourceFileCache[normalizedPath] = null;\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst sourceFile = ts.createSourceFile(sourceFilePath, source, ts.ScriptTarget.Latest, true);\n\t\tResolver._sourceFileCache[normalizedPath] = sourceFile;\n\t\treturn sourceFile;\n\t}\n\n\t/**\n\t * Resolve a module specifier from a containing file.\n\t * @param moduleSpecifier The module specifier text.\n\t * @param containingFilePath The file containing the import/export.\n\t * @param compilerOptions Compiler options for module resolution.\n\t * @returns The resolved file path.\n\t * @internal\n\t */\n\tprivate static resolveModuleSpecifierFromFile(\n\t\tmoduleSpecifier: string,\n\t\tcontainingFilePath: string,\n\t\tcompilerOptions: ts.CompilerOptions\n\t): string | undefined {\n\t\treturn ts.resolveModuleName(moduleSpecifier, containingFilePath, compilerOptions, ts.sys)\n\t\t\t.resolvedModule?.resolvedFileName;\n\t}\n}\n"]}
|