@twin.org/tools-core 0.0.3-next.2 → 0.0.3-next.21
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/README.md +2 -2
- package/dist/es/index.js +20 -11
- package/dist/es/index.js.map +1 -1
- package/dist/es/models/ITypeScriptToSchemaContext.js +2 -0
- package/dist/es/models/ITypeScriptToSchemaContext.js.map +1 -0
- package/dist/es/models/ITypeScriptToSchemaDiagnostics.js +4 -0
- package/dist/es/models/ITypeScriptToSchemaDiagnostics.js.map +1 -0
- package/dist/es/models/ITypeScriptToSchemaOptions.js +4 -0
- package/dist/es/models/ITypeScriptToSchemaOptions.js.map +1 -0
- package/dist/es/utils/constants.js +43 -0
- package/dist/es/utils/constants.js.map +1 -0
- package/dist/es/utils/diagnosticReporter.js +32 -0
- package/dist/es/utils/diagnosticReporter.js.map +1 -0
- package/dist/es/utils/disallowedTypeGuard.js +151 -0
- package/dist/es/utils/disallowedTypeGuard.js.map +1 -0
- package/dist/es/utils/enum.js +152 -0
- package/dist/es/utils/enum.js.map +1 -0
- package/dist/es/utils/fileUtils.js +130 -0
- package/dist/es/utils/fileUtils.js.map +1 -0
- package/dist/es/utils/importTypeQuerySchemaResolver.js +328 -0
- package/dist/es/utils/importTypeQuerySchemaResolver.js.map +1 -0
- package/dist/es/utils/indexSignaturePatternResolver.js +94 -0
- package/dist/es/utils/indexSignaturePatternResolver.js.map +1 -0
- package/dist/es/utils/intersectionSchemaMerger.js +85 -0
- package/dist/es/utils/intersectionSchemaMerger.js.map +1 -0
- package/dist/es/utils/jsDoc.js +120 -0
- package/dist/es/utils/jsDoc.js.map +1 -0
- package/dist/es/utils/jsonSchemaBuilder.js +3373 -0
- package/dist/es/utils/jsonSchemaBuilder.js.map +1 -0
- package/dist/es/utils/mappedTypeSchemaResolver.js +231 -0
- package/dist/es/utils/mappedTypeSchemaResolver.js.map +1 -0
- package/dist/es/utils/objectTransformer.js +162 -0
- package/dist/es/utils/objectTransformer.js.map +1 -0
- package/dist/es/utils/regEx.js +128 -0
- package/dist/es/utils/regEx.js.map +1 -0
- package/dist/es/utils/resolver.js +164 -0
- package/dist/es/utils/resolver.js.map +1 -0
- package/dist/es/utils/templateLiteralPatternBuilder.js +94 -0
- package/dist/es/utils/templateLiteralPatternBuilder.js.map +1 -0
- package/dist/es/utils/typeScriptToSchema.js +112 -0
- package/dist/es/utils/typeScriptToSchema.js.map +1 -0
- package/dist/es/utils/utilityTypeSchemaMapper.js +412 -0
- package/dist/es/utils/utilityTypeSchemaMapper.js.map +1 -0
- package/dist/types/index.d.ts +20 -11
- package/dist/types/models/ITypeScriptToSchemaContext.d.ts +64 -0
- package/dist/types/models/ITypeScriptToSchemaDiagnostics.d.ts +31 -0
- package/dist/types/models/ITypeScriptToSchemaOptions.d.ts +22 -0
- package/dist/types/utils/constants.d.ts +13 -0
- package/dist/types/utils/diagnosticReporter.d.ts +17 -0
- package/dist/types/utils/disallowedTypeGuard.d.ts +16 -0
- package/dist/types/utils/enum.d.ts +42 -0
- package/dist/types/utils/fileUtils.d.ts +66 -0
- package/dist/types/utils/importTypeQuerySchemaResolver.d.ts +52 -0
- package/dist/types/utils/indexSignaturePatternResolver.d.ts +21 -0
- package/dist/types/utils/intersectionSchemaMerger.d.ts +16 -0
- package/dist/types/utils/jsDoc.d.ts +46 -0
- package/dist/types/utils/jsonSchemaBuilder.d.ts +747 -0
- package/dist/types/utils/mappedTypeSchemaResolver.d.ts +46 -0
- package/dist/types/utils/objectTransformer.d.ts +33 -0
- package/dist/types/utils/regEx.d.ts +24 -0
- package/dist/types/utils/resolver.d.ts +16 -0
- package/dist/types/utils/templateLiteralPatternBuilder.d.ts +12 -0
- package/dist/types/utils/typeScriptToSchema.d.ts +31 -0
- package/dist/types/utils/utilityTypeSchemaMapper.d.ts +92 -0
- package/docs/changelog.md +176 -1
- package/docs/examples.md +87 -1
- package/docs/reference/classes/Constants.md +29 -0
- package/docs/reference/classes/DiagnosticReporter.md +49 -0
- package/docs/reference/classes/DisallowedTypeGuard.md +35 -0
- package/docs/reference/classes/Enum.md +93 -0
- package/docs/reference/classes/FileUtils.md +237 -0
- package/docs/reference/classes/ImportTypeQuerySchemaResolver.md +87 -0
- package/docs/reference/classes/IndexSignaturePatternResolver.md +69 -0
- package/docs/reference/classes/IntersectionSchemaMerger.md +48 -0
- package/docs/reference/classes/JsDoc.md +141 -0
- package/docs/reference/classes/JsonSchemaBuilder.md +2870 -0
- package/docs/reference/classes/MappedTypeSchemaResolver.md +211 -0
- package/docs/reference/classes/ObjectTransformer.md +119 -0
- package/docs/reference/classes/RegEx.md +99 -0
- package/docs/reference/classes/Resolver.md +41 -0
- package/docs/reference/classes/TemplateLiteralPatternBuilder.md +35 -0
- package/docs/reference/classes/TypeScriptToSchema.md +91 -0
- package/docs/reference/classes/UtilityTypeSchemaMapper.md +341 -0
- package/docs/reference/index.md +20 -14
- package/docs/reference/interfaces/ITypeScriptToSchemaContext.md +113 -0
- package/docs/reference/interfaces/ITypeScriptToSchemaDiagnostics.md +55 -0
- package/docs/reference/interfaces/ITypeScriptToSchemaOptions.md +44 -0
- package/locales/en.json +32 -1
- package/package.json +4 -3
- package/dist/es/models/IJsonSchema.js +0 -2
- package/dist/es/models/IJsonSchema.js.map +0 -1
- package/dist/es/models/IOpenApi.js +0 -2
- package/dist/es/models/IOpenApi.js.map +0 -1
- package/dist/es/models/IOpenApiExample.js +0 -4
- package/dist/es/models/IOpenApiExample.js.map +0 -1
- package/dist/es/models/IOpenApiHeader.js +0 -4
- package/dist/es/models/IOpenApiHeader.js.map +0 -1
- package/dist/es/models/IOpenApiPathMethod.js +0 -2
- package/dist/es/models/IOpenApiPathMethod.js.map +0 -1
- package/dist/es/models/IOpenApiResponse.js +0 -2
- package/dist/es/models/IOpenApiResponse.js.map +0 -1
- package/dist/es/models/IOpenApiSecurityScheme.js +0 -4
- package/dist/es/models/IOpenApiSecurityScheme.js.map +0 -1
- package/dist/es/models/IPackageJson.js +0 -4
- package/dist/es/models/IPackageJson.js.map +0 -1
- package/dist/es/models/jsonTypeName.js +0 -2
- package/dist/es/models/jsonTypeName.js.map +0 -1
- package/dist/es/utils/jsonSchemaHelper.js +0 -258
- package/dist/es/utils/jsonSchemaHelper.js.map +0 -1
- package/dist/es/utils/openApiHelper.js +0 -12
- package/dist/es/utils/openApiHelper.js.map +0 -1
- package/dist/types/models/IJsonSchema.d.ts +0 -5
- package/dist/types/models/IOpenApi.d.ts +0 -54
- package/dist/types/models/IOpenApiExample.d.ts +0 -13
- package/dist/types/models/IOpenApiHeader.d.ts +0 -19
- package/dist/types/models/IOpenApiPathMethod.d.ts +0 -65
- package/dist/types/models/IOpenApiResponse.d.ts +0 -32
- package/dist/types/models/IOpenApiSecurityScheme.d.ts +0 -25
- package/dist/types/models/IPackageJson.d.ts +0 -15
- package/dist/types/models/jsonTypeName.d.ts +0 -5
- package/dist/types/utils/jsonSchemaHelper.d.ts +0 -78
- package/dist/types/utils/openApiHelper.d.ts +0 -9
- package/docs/reference/classes/JsonSchemaHelper.md +0 -233
- package/docs/reference/classes/OpenApiHelper.md +0 -21
- package/docs/reference/interfaces/IOpenApi.md +0 -103
- package/docs/reference/interfaces/IOpenApiExample.md +0 -19
- package/docs/reference/interfaces/IOpenApiHeader.md +0 -31
- package/docs/reference/interfaces/IOpenApiPathMethod.md +0 -119
- package/docs/reference/interfaces/IOpenApiResponse.md +0 -35
- package/docs/reference/interfaces/IOpenApiSecurityScheme.md +0 -43
- package/docs/reference/interfaces/IPackageJson.md +0 -23
- package/docs/reference/type-aliases/IJsonSchema.md +0 -5
- package/docs/reference/type-aliases/JsonTypeName.md +0 -5
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// Copyright 2026 IOTA Stiftung.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
3
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { globSync } from "glob";
|
|
6
|
+
/**
|
|
7
|
+
* Utility helpers for TypeScript file and directory paths.
|
|
8
|
+
*/
|
|
9
|
+
export class FileUtils {
|
|
10
|
+
/**
|
|
11
|
+
* Does the file exist.
|
|
12
|
+
* @param filePath The file path.
|
|
13
|
+
* @returns True if the file exists.
|
|
14
|
+
*/
|
|
15
|
+
static fileExists(filePath) {
|
|
16
|
+
return existsSync(filePath);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Read the file.
|
|
20
|
+
* @param filePath The file path.
|
|
21
|
+
* @returns The file contents.
|
|
22
|
+
*/
|
|
23
|
+
static readFile(filePath) {
|
|
24
|
+
return readFileSync(filePath, "utf-8");
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Resolve a path.
|
|
28
|
+
* @param filePath The file path.
|
|
29
|
+
* @returns The resolved path.
|
|
30
|
+
*/
|
|
31
|
+
static resolvePath(filePath) {
|
|
32
|
+
return path.resolve(filePath);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Get the current working directory.
|
|
36
|
+
* @returns The current working directory.
|
|
37
|
+
*/
|
|
38
|
+
static getCurrentWorkingDirectory() {
|
|
39
|
+
return process.cwd();
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Normalize path separators for consistent comparisons.
|
|
43
|
+
* @param filePath The file path.
|
|
44
|
+
* @returns The normalized file path.
|
|
45
|
+
*/
|
|
46
|
+
static normalizeFilePath(filePath) {
|
|
47
|
+
return filePath.replaceAll("\\", "/");
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Get the directory portion of a file path.
|
|
51
|
+
* @param filePath The file path.
|
|
52
|
+
* @returns The directory path.
|
|
53
|
+
*/
|
|
54
|
+
static getDirectoryPath(filePath) {
|
|
55
|
+
const normalizedPath = FileUtils.normalizeFilePath(filePath);
|
|
56
|
+
const lastSeparatorIndex = normalizedPath.lastIndexOf("/");
|
|
57
|
+
return lastSeparatorIndex > -1 ? normalizedPath.slice(0, lastSeparatorIndex) : normalizedPath;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Resolve a relative path against a base directory.
|
|
61
|
+
* @param baseDirectory The base directory.
|
|
62
|
+
* @param relativePath The relative path.
|
|
63
|
+
* @returns The resolved path.
|
|
64
|
+
*/
|
|
65
|
+
static resolveRelativePath(baseDirectory, relativePath) {
|
|
66
|
+
const normalizedRelative = FileUtils.normalizeFilePath(relativePath);
|
|
67
|
+
// Return absolute paths unchanged (Windows drive letter or POSIX root)
|
|
68
|
+
if (path.isAbsolute(normalizedRelative)) {
|
|
69
|
+
return normalizedRelative;
|
|
70
|
+
}
|
|
71
|
+
const normalizedBase = FileUtils.normalizeFilePath(baseDirectory);
|
|
72
|
+
if (path.isAbsolute(normalizedBase)) {
|
|
73
|
+
return FileUtils.normalizeFilePath(path.resolve(baseDirectory, relativePath));
|
|
74
|
+
}
|
|
75
|
+
// Base was relative — resolve to absolute then express relative to CWD to preserve relative form
|
|
76
|
+
return FileUtils.normalizeFilePath(path.relative(process.cwd(), path.resolve(baseDirectory, relativePath)));
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Resolve a local import specifier to a TypeScript source file path.
|
|
80
|
+
* @param sourceFilePath The importing source file path.
|
|
81
|
+
* @param importPath The import specifier.
|
|
82
|
+
* @returns The resolved source file path.
|
|
83
|
+
*/
|
|
84
|
+
static resolveImportSourceFilePath(sourceFilePath, importPath) {
|
|
85
|
+
const sourceDirectory = FileUtils.getDirectoryPath(sourceFilePath);
|
|
86
|
+
const resolvedBase = FileUtils.resolveRelativePath(sourceDirectory, importPath);
|
|
87
|
+
const baseWithoutExtension = resolvedBase.replace(/\.(c|m)?js$/u, "");
|
|
88
|
+
const candidates = [
|
|
89
|
+
resolvedBase,
|
|
90
|
+
`${resolvedBase}.ts`,
|
|
91
|
+
`${resolvedBase}.d.ts`,
|
|
92
|
+
`${resolvedBase}/index.ts`,
|
|
93
|
+
`${resolvedBase}/index.d.ts`,
|
|
94
|
+
`${baseWithoutExtension}.d.ts`,
|
|
95
|
+
`${baseWithoutExtension}/index.d.ts`
|
|
96
|
+
];
|
|
97
|
+
for (const candidate of candidates) {
|
|
98
|
+
if (FileUtils.fileExists(candidate)) {
|
|
99
|
+
return candidate;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Determine if the provided path includes glob pattern tokens.
|
|
106
|
+
* @param sourceFileOrGlob The direct source file path or glob pattern.
|
|
107
|
+
* @returns True if the value is a glob pattern.
|
|
108
|
+
*/
|
|
109
|
+
static isGlobPattern(sourceFileOrGlob) {
|
|
110
|
+
return /[*?[\]{}]/u.test(sourceFileOrGlob);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Resolve source files from a direct path or a glob pattern.
|
|
114
|
+
* @param sourceFileOrGlob The direct source file path or glob pattern.
|
|
115
|
+
* @returns The resolved source file paths.
|
|
116
|
+
*/
|
|
117
|
+
static resolveSourceFiles(sourceFileOrGlob) {
|
|
118
|
+
if (!FileUtils.isGlobPattern(sourceFileOrGlob)) {
|
|
119
|
+
return FileUtils.fileExists(sourceFileOrGlob) ? [sourceFileOrGlob] : [];
|
|
120
|
+
}
|
|
121
|
+
const sourceFiles = globSync(sourceFileOrGlob, {
|
|
122
|
+
windowsPathsNoEscape: true,
|
|
123
|
+
withFileTypes: false
|
|
124
|
+
});
|
|
125
|
+
return sourceFiles
|
|
126
|
+
.filter(sourceFile => /\.(ts|tsx|mts|cts)$/u.test(sourceFile) && FileUtils.fileExists(sourceFile))
|
|
127
|
+
.sort((sourceFileA, sourceFileB) => sourceFileA.localeCompare(sourceFileB));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=fileUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileUtils.js","sourceRoot":"","sources":["../../../src/utils/fileUtils.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { existsSync, readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { globSync } from \"glob\";\n\n/**\n * Utility helpers for TypeScript file and directory paths.\n */\nexport class FileUtils {\n\t/**\n\t * Does the file exist.\n\t * @param filePath The file path.\n\t * @returns True if the file exists.\n\t */\n\tpublic static fileExists(filePath: string): boolean {\n\t\treturn existsSync(filePath);\n\t}\n\n\t/**\n\t * Read the file.\n\t * @param filePath The file path.\n\t * @returns The file contents.\n\t */\n\tpublic static readFile(filePath: string): string {\n\t\treturn readFileSync(filePath, \"utf-8\");\n\t}\n\n\t/**\n\t * Resolve a path.\n\t * @param filePath The file path.\n\t * @returns The resolved path.\n\t */\n\tpublic static resolvePath(filePath: string): string {\n\t\treturn path.resolve(filePath);\n\t}\n\n\t/**\n\t * Get the current working directory.\n\t * @returns The current working directory.\n\t */\n\tpublic static getCurrentWorkingDirectory(): string {\n\t\treturn process.cwd();\n\t}\n\n\t/**\n\t * Normalize path separators for consistent comparisons.\n\t * @param filePath The file path.\n\t * @returns The normalized file path.\n\t */\n\tpublic static normalizeFilePath(filePath: string): string {\n\t\treturn filePath.replaceAll(\"\\\\\", \"/\");\n\t}\n\n\t/**\n\t * Get the directory portion of a file path.\n\t * @param filePath The file path.\n\t * @returns The directory path.\n\t */\n\tpublic static getDirectoryPath(filePath: string): string {\n\t\tconst normalizedPath = FileUtils.normalizeFilePath(filePath);\n\t\tconst lastSeparatorIndex = normalizedPath.lastIndexOf(\"/\");\n\t\treturn lastSeparatorIndex > -1 ? normalizedPath.slice(0, lastSeparatorIndex) : normalizedPath;\n\t}\n\n\t/**\n\t * Resolve a relative path against a base directory.\n\t * @param baseDirectory The base directory.\n\t * @param relativePath The relative path.\n\t * @returns The resolved path.\n\t */\n\tpublic static resolveRelativePath(baseDirectory: string, relativePath: string): string {\n\t\tconst normalizedRelative = FileUtils.normalizeFilePath(relativePath);\n\n\t\t// Return absolute paths unchanged (Windows drive letter or POSIX root)\n\t\tif (path.isAbsolute(normalizedRelative)) {\n\t\t\treturn normalizedRelative;\n\t\t}\n\n\t\tconst normalizedBase = FileUtils.normalizeFilePath(baseDirectory);\n\n\t\tif (path.isAbsolute(normalizedBase)) {\n\t\t\treturn FileUtils.normalizeFilePath(path.resolve(baseDirectory, relativePath));\n\t\t}\n\n\t\t// Base was relative — resolve to absolute then express relative to CWD to preserve relative form\n\t\treturn FileUtils.normalizeFilePath(\n\t\t\tpath.relative(process.cwd(), path.resolve(baseDirectory, relativePath))\n\t\t);\n\t}\n\n\t/**\n\t * Resolve a local import specifier to a TypeScript source file path.\n\t * @param sourceFilePath The importing source file path.\n\t * @param importPath The import specifier.\n\t * @returns The resolved source file path.\n\t */\n\tpublic static resolveImportSourceFilePath(\n\t\tsourceFilePath: string,\n\t\timportPath: string\n\t): string | undefined {\n\t\tconst sourceDirectory = FileUtils.getDirectoryPath(sourceFilePath);\n\t\tconst resolvedBase = FileUtils.resolveRelativePath(sourceDirectory, importPath);\n\t\tconst baseWithoutExtension = resolvedBase.replace(/\\.(c|m)?js$/u, \"\");\n\t\tconst candidates = [\n\t\t\tresolvedBase,\n\t\t\t`${resolvedBase}.ts`,\n\t\t\t`${resolvedBase}.d.ts`,\n\t\t\t`${resolvedBase}/index.ts`,\n\t\t\t`${resolvedBase}/index.d.ts`,\n\t\t\t`${baseWithoutExtension}.d.ts`,\n\t\t\t`${baseWithoutExtension}/index.d.ts`\n\t\t];\n\n\t\tfor (const candidate of candidates) {\n\t\t\tif (FileUtils.fileExists(candidate)) {\n\t\t\t\treturn candidate;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Determine if the provided path includes glob pattern tokens.\n\t * @param sourceFileOrGlob The direct source file path or glob pattern.\n\t * @returns True if the value is a glob pattern.\n\t */\n\tpublic static isGlobPattern(sourceFileOrGlob: string): boolean {\n\t\treturn /[*?[\\]{}]/u.test(sourceFileOrGlob);\n\t}\n\n\t/**\n\t * Resolve source files from a direct path or a glob pattern.\n\t * @param sourceFileOrGlob The direct source file path or glob pattern.\n\t * @returns The resolved source file paths.\n\t */\n\tpublic static resolveSourceFiles(sourceFileOrGlob: string): string[] {\n\t\tif (!FileUtils.isGlobPattern(sourceFileOrGlob)) {\n\t\t\treturn FileUtils.fileExists(sourceFileOrGlob) ? [sourceFileOrGlob] : [];\n\t\t}\n\n\t\tconst sourceFiles = globSync(sourceFileOrGlob, {\n\t\t\twindowsPathsNoEscape: true,\n\t\t\twithFileTypes: false\n\t\t});\n\n\t\treturn sourceFiles\n\t\t\t.filter(\n\t\t\t\tsourceFile => /\\.(ts|tsx|mts|cts)$/u.test(sourceFile) && FileUtils.fileExists(sourceFile)\n\t\t\t)\n\t\t\t.sort((sourceFileA, sourceFileB) => sourceFileA.localeCompare(sourceFileB));\n\t}\n}\n"]}
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
// Copyright 2026 IOTA Stiftung.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
3
|
+
/* eslint-disable jsdoc/require-param, jsdoc/require-returns */
|
|
4
|
+
import { Is, StringHelper } from "@twin.org/core";
|
|
5
|
+
import * as ts from "typescript";
|
|
6
|
+
import { DiagnosticReporter } from "./diagnosticReporter.js";
|
|
7
|
+
import { FileUtils } from "./fileUtils.js";
|
|
8
|
+
import { JsonSchemaBuilder } from "./jsonSchemaBuilder.js";
|
|
9
|
+
import { Resolver } from "./resolver.js";
|
|
10
|
+
/**
|
|
11
|
+
* Static helpers for import type and type query schema resolution.
|
|
12
|
+
*/
|
|
13
|
+
export class ImportTypeQuerySchemaResolver {
|
|
14
|
+
/**
|
|
15
|
+
* Map import type nodes (e.g. import("pkg").Type) to schema references.
|
|
16
|
+
*/
|
|
17
|
+
static mapImportTypeNodeToSchema(context, typeNode) {
|
|
18
|
+
if (typeNode.isTypeOf ||
|
|
19
|
+
!ts.isLiteralTypeNode(typeNode.argument) ||
|
|
20
|
+
!ts.isStringLiteral(typeNode.argument.literal)) {
|
|
21
|
+
DiagnosticReporter.report(context, typeNode, "jsonSchemaBuilder.diagnostic.unsupportedImportTypeForm", { argument: typeNode.getText() });
|
|
22
|
+
return {};
|
|
23
|
+
}
|
|
24
|
+
const moduleSpecifier = typeNode.argument.literal.text;
|
|
25
|
+
const typeName = ImportTypeQuerySchemaResolver.extractImportTypeName(typeNode.qualifier);
|
|
26
|
+
if (!typeName) {
|
|
27
|
+
DiagnosticReporter.report(context, typeNode, "jsonSchemaBuilder.diagnostic.unresolvedImportTypeQualifier", { argument: moduleSpecifier });
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
const title = StringHelper.stripPrefix(typeName);
|
|
31
|
+
const existingSchemaId = JsonSchemaBuilder.findExistingSchemaIdByTitle(context, title);
|
|
32
|
+
const resolvedSchemaId = existingSchemaId ??
|
|
33
|
+
ImportTypeQuerySchemaResolver.resolveImportTypeReferenceSchemaId(context, moduleSpecifier, typeName, title);
|
|
34
|
+
return {
|
|
35
|
+
$ref: resolvedSchemaId ?? `${context.namespace}${title}`
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Map a type query node (typeof expr) to schema by resolving the referenced variable.
|
|
40
|
+
*/
|
|
41
|
+
static mapTypeQueryNodeToSchema(context, typeNode) {
|
|
42
|
+
if (ts.isQualifiedName(typeNode.exprName) && ts.isIdentifier(typeNode.exprName.left)) {
|
|
43
|
+
const localValue = JsonSchemaBuilder.resolveLocalConstObjectProperty(context, typeNode.exprName.left.text, typeNode.exprName.right.text);
|
|
44
|
+
if (localValue !== undefined) {
|
|
45
|
+
return { const: localValue };
|
|
46
|
+
}
|
|
47
|
+
const importedValue = ImportTypeQuerySchemaResolver.resolveConstObjectProperty(context, typeNode.exprName.left.text, typeNode.exprName.right.text);
|
|
48
|
+
if (importedValue !== undefined) {
|
|
49
|
+
return { const: importedValue };
|
|
50
|
+
}
|
|
51
|
+
DiagnosticReporter.report(context, typeNode, "jsonSchemaBuilder.diagnostic.unresolvedTypeQueryTarget", { target: typeNode.getText() });
|
|
52
|
+
return {};
|
|
53
|
+
}
|
|
54
|
+
const exprName = ts.isIdentifier(typeNode.exprName) ? typeNode.exprName.text : undefined;
|
|
55
|
+
if (!exprName || !context.activeSourceFile) {
|
|
56
|
+
DiagnosticReporter.report(context, typeNode, "jsonSchemaBuilder.diagnostic.unresolvedTypeQueryTarget", { target: typeNode.getText() });
|
|
57
|
+
return {};
|
|
58
|
+
}
|
|
59
|
+
const localDeclaration = JsonSchemaBuilder.findVariableDeclaration(context.activeSourceFile, exprName);
|
|
60
|
+
if (localDeclaration) {
|
|
61
|
+
if (localDeclaration.type) {
|
|
62
|
+
return JsonSchemaBuilder.mapTypeNodeToSchema(context, localDeclaration.type) ?? {};
|
|
63
|
+
}
|
|
64
|
+
if (localDeclaration.initializer) {
|
|
65
|
+
return JsonSchemaBuilder.inferSchemaFromExpression(context, localDeclaration.initializer);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const importedTypeQuerySchema = JsonSchemaBuilder.resolveImportedTypeQuerySchema(context, exprName);
|
|
69
|
+
if (importedTypeQuerySchema) {
|
|
70
|
+
return importedTypeQuerySchema;
|
|
71
|
+
}
|
|
72
|
+
DiagnosticReporter.report(context, typeNode, "jsonSchemaBuilder.diagnostic.unresolvedTypeQueryTarget", { target: exprName });
|
|
73
|
+
return {};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Resolve import-type references to local or external schema ids.
|
|
77
|
+
*/
|
|
78
|
+
static resolveImportTypeReferenceSchemaId(context, moduleSpecifier, typeName, title) {
|
|
79
|
+
const mappedReference = JsonSchemaBuilder.resolveReferenceMappingTarget(context, moduleSpecifier, typeName);
|
|
80
|
+
if (moduleSpecifier.startsWith(".")) {
|
|
81
|
+
if (mappedReference?.schemaId) {
|
|
82
|
+
return mappedReference.schemaId;
|
|
83
|
+
}
|
|
84
|
+
const activeFilePath = context.activeSourceFile?.fileName;
|
|
85
|
+
if (!activeFilePath) {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
const resolvedImportPath = FileUtils.resolveImportSourceFilePath(activeFilePath, moduleSpecifier);
|
|
89
|
+
if (!resolvedImportPath) {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
const importedSource = FileUtils.readFile(resolvedImportPath);
|
|
93
|
+
if (!importedSource) {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
JsonSchemaBuilder.parseAllObjectSchemas(context, resolvedImportPath, importedSource, []);
|
|
97
|
+
return context.schemas[context.packageName]?.[title]?.$id;
|
|
98
|
+
}
|
|
99
|
+
const cachedSchemaId = context.schemas[moduleSpecifier]?.[title]?.$id;
|
|
100
|
+
if (cachedSchemaId) {
|
|
101
|
+
return cachedSchemaId;
|
|
102
|
+
}
|
|
103
|
+
const declarationResult = Resolver.resolveTypeDeclarationAst(moduleSpecifier, typeName);
|
|
104
|
+
if (!declarationResult) {
|
|
105
|
+
return mappedReference?.schemaId;
|
|
106
|
+
}
|
|
107
|
+
const externalContext = {
|
|
108
|
+
namespace: mappedReference?.namespace ?? context.namespace,
|
|
109
|
+
packageName: moduleSpecifier,
|
|
110
|
+
schemas: context.schemas,
|
|
111
|
+
activeSourceFile: context.activeSourceFile,
|
|
112
|
+
options: context.options
|
|
113
|
+
};
|
|
114
|
+
JsonSchemaBuilder.parseAllObjectSchemas(externalContext, declarationResult.sourceFile.fileName, declarationResult.sourceFile.getFullText(), []);
|
|
115
|
+
return context.schemas[moduleSpecifier]?.[title]?.$id ?? mappedReference?.schemaId;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Resolve a property value from a const object declaration in an imported source file.
|
|
119
|
+
*/
|
|
120
|
+
static resolveConstObjectProperty(context, objectName, propertyName) {
|
|
121
|
+
if (!context.activeSourceFile) {
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
124
|
+
const importReference = ImportTypeQuerySchemaResolver.findImportedValueReference(context.activeSourceFile, objectName);
|
|
125
|
+
if (!importReference) {
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
const resolvedPath = ImportTypeQuerySchemaResolver.resolveImportDeclarationSourceFile(context.activeSourceFile.fileName, importReference.moduleSpecifier);
|
|
129
|
+
if (!resolvedPath) {
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
const importedSource = FileUtils.readFile(resolvedPath);
|
|
133
|
+
if (!importedSource) {
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
const importedSourceFile = ts.createSourceFile(resolvedPath, importedSource, ts.ScriptTarget.Latest, true);
|
|
137
|
+
let objDecl = importedSourceFile.statements
|
|
138
|
+
.filter((stmt) => ts.isVariableStatement(stmt))
|
|
139
|
+
.flatMap(stmt => [...stmt.declarationList.declarations])
|
|
140
|
+
.find(decl => ts.isIdentifier(decl.name) && decl.name.text === importReference.importedName);
|
|
141
|
+
objDecl ??= ImportTypeQuerySchemaResolver.findVariableDeclarationInModuleGraph(resolvedPath, importReference.importedName, new Set());
|
|
142
|
+
if (!objDecl) {
|
|
143
|
+
return undefined;
|
|
144
|
+
}
|
|
145
|
+
const valueFromInitializer = ImportTypeQuerySchemaResolver.extractConstObjectPropertyFromDeclarationInitializer(objDecl, propertyName);
|
|
146
|
+
if (valueFromInitializer !== undefined) {
|
|
147
|
+
return valueFromInitializer;
|
|
148
|
+
}
|
|
149
|
+
if (objDecl.type) {
|
|
150
|
+
return ImportTypeQuerySchemaResolver.extractConstObjectPropertyFromDeclarationType(objDecl.type, propertyName);
|
|
151
|
+
}
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Find a variable declaration by traversing import and export chains.
|
|
156
|
+
*/
|
|
157
|
+
static findVariableDeclarationInModuleGraph(sourceFilePath, variableName, visitedFiles) {
|
|
158
|
+
const normalizedSourceFilePath = FileUtils.normalizeFilePath(sourceFilePath);
|
|
159
|
+
if (visitedFiles.has(normalizedSourceFilePath)) {
|
|
160
|
+
return undefined;
|
|
161
|
+
}
|
|
162
|
+
visitedFiles.add(normalizedSourceFilePath);
|
|
163
|
+
const source = FileUtils.readFile(sourceFilePath);
|
|
164
|
+
if (!source) {
|
|
165
|
+
return undefined;
|
|
166
|
+
}
|
|
167
|
+
const sourceFile = ts.createSourceFile(sourceFilePath, source, ts.ScriptTarget.Latest, true);
|
|
168
|
+
const declaration = sourceFile.statements
|
|
169
|
+
.filter((stmt) => ts.isVariableStatement(stmt))
|
|
170
|
+
.flatMap(stmt => [...stmt.declarationList.declarations])
|
|
171
|
+
.find(decl => ts.isIdentifier(decl.name) && decl.name.text === variableName);
|
|
172
|
+
if (declaration) {
|
|
173
|
+
return declaration;
|
|
174
|
+
}
|
|
175
|
+
const compilerOptions = {
|
|
176
|
+
module: ts.ModuleKind.NodeNext,
|
|
177
|
+
moduleResolution: ts.ModuleResolutionKind.NodeNext,
|
|
178
|
+
target: ts.ScriptTarget.ESNext,
|
|
179
|
+
skipLibCheck: true
|
|
180
|
+
};
|
|
181
|
+
const moduleSpecifiers = sourceFile.statements
|
|
182
|
+
.filter(statement => ts.isExportDeclaration(statement) || ts.isImportDeclaration(statement))
|
|
183
|
+
.flatMap(statement => {
|
|
184
|
+
const moduleSpecifier = statement.moduleSpecifier;
|
|
185
|
+
return moduleSpecifier && ts.isStringLiteral(moduleSpecifier) ? [moduleSpecifier.text] : [];
|
|
186
|
+
});
|
|
187
|
+
for (const moduleSpecifier of moduleSpecifiers) {
|
|
188
|
+
const resolvedModulePath = ts.resolveModuleName(moduleSpecifier, sourceFilePath, compilerOptions, ts.sys).resolvedModule?.resolvedFileName;
|
|
189
|
+
if (resolvedModulePath) {
|
|
190
|
+
const declarationInModule = ImportTypeQuerySchemaResolver.findVariableDeclarationInModuleGraph(resolvedModulePath, variableName, visitedFiles);
|
|
191
|
+
if (declarationInModule) {
|
|
192
|
+
return declarationInModule;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Find an imported symbol reference by local identifier name.
|
|
200
|
+
*/
|
|
201
|
+
static findImportedValueReference(sourceFile, localName) {
|
|
202
|
+
for (const statement of sourceFile.statements) {
|
|
203
|
+
if (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier)) {
|
|
204
|
+
const bindings = statement.importClause?.namedBindings;
|
|
205
|
+
if (bindings && ts.isNamedImports(bindings)) {
|
|
206
|
+
const importElement = bindings.elements.find(el => el.name.text === localName);
|
|
207
|
+
if (importElement) {
|
|
208
|
+
return {
|
|
209
|
+
moduleSpecifier: statement.moduleSpecifier.text,
|
|
210
|
+
importedName: importElement.propertyName?.text ?? importElement.name.text
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return undefined;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Resolve an import declaration module specifier to a source file.
|
|
220
|
+
*/
|
|
221
|
+
static resolveImportDeclarationSourceFile(containingSourceFilePath, moduleSpecifier) {
|
|
222
|
+
const resolvedContainingSourceFilePath = FileUtils.resolvePath(containingSourceFilePath);
|
|
223
|
+
if (moduleSpecifier.startsWith(".")) {
|
|
224
|
+
return (FileUtils.resolveImportSourceFilePath(resolvedContainingSourceFilePath, moduleSpecifier) ??
|
|
225
|
+
(moduleSpecifier.endsWith(".js")
|
|
226
|
+
? FileUtils.resolveImportSourceFilePath(resolvedContainingSourceFilePath, `${moduleSpecifier.slice(0, -3)}.ts`)
|
|
227
|
+
: undefined));
|
|
228
|
+
}
|
|
229
|
+
const compilerOptions = {
|
|
230
|
+
module: ts.ModuleKind.NodeNext,
|
|
231
|
+
moduleResolution: ts.ModuleResolutionKind.NodeNext,
|
|
232
|
+
target: ts.ScriptTarget.ESNext,
|
|
233
|
+
skipLibCheck: true
|
|
234
|
+
};
|
|
235
|
+
return ts.resolveModuleName(moduleSpecifier, resolvedContainingSourceFilePath, compilerOptions, ts.sys).resolvedModule?.resolvedFileName;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Extract a const-object property value from a declaration initializer.
|
|
239
|
+
*/
|
|
240
|
+
static extractConstObjectPropertyFromDeclarationInitializer(objectDeclaration, propertyName) {
|
|
241
|
+
if (!objectDeclaration.initializer) {
|
|
242
|
+
return undefined;
|
|
243
|
+
}
|
|
244
|
+
let objLiteral;
|
|
245
|
+
if (ts.isObjectLiteralExpression(objectDeclaration.initializer)) {
|
|
246
|
+
objLiteral = objectDeclaration.initializer;
|
|
247
|
+
}
|
|
248
|
+
else if (ts.isAsExpression(objectDeclaration.initializer) &&
|
|
249
|
+
ts.isObjectLiteralExpression(objectDeclaration.initializer.expression)) {
|
|
250
|
+
objLiteral = objectDeclaration.initializer.expression;
|
|
251
|
+
}
|
|
252
|
+
if (!objLiteral) {
|
|
253
|
+
return undefined;
|
|
254
|
+
}
|
|
255
|
+
const prop = objLiteral.properties
|
|
256
|
+
.filter((p) => ts.isPropertyAssignment(p))
|
|
257
|
+
.find(p => ts.isIdentifier(p.name) && p.name.text === propertyName);
|
|
258
|
+
if (!prop) {
|
|
259
|
+
return undefined;
|
|
260
|
+
}
|
|
261
|
+
if (ts.isStringLiteral(prop.initializer)) {
|
|
262
|
+
return prop.initializer.text;
|
|
263
|
+
}
|
|
264
|
+
if (ts.isNumericLiteral(prop.initializer)) {
|
|
265
|
+
return Number(prop.initializer.text);
|
|
266
|
+
}
|
|
267
|
+
return undefined;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Extract a const-object property value from a declaration type annotation.
|
|
271
|
+
*/
|
|
272
|
+
static extractConstObjectPropertyFromDeclarationType(declarationTypeNode, propertyName) {
|
|
273
|
+
if (ts.isParenthesizedTypeNode(declarationTypeNode)) {
|
|
274
|
+
return ImportTypeQuerySchemaResolver.extractConstObjectPropertyFromDeclarationType(declarationTypeNode.type, propertyName);
|
|
275
|
+
}
|
|
276
|
+
if (ts.isTypeOperatorNode(declarationTypeNode) &&
|
|
277
|
+
declarationTypeNode.operator === ts.SyntaxKind.ReadonlyKeyword) {
|
|
278
|
+
return ImportTypeQuerySchemaResolver.extractConstObjectPropertyFromDeclarationType(declarationTypeNode.type, propertyName);
|
|
279
|
+
}
|
|
280
|
+
if (ts.isTypeReferenceNode(declarationTypeNode) &&
|
|
281
|
+
ts.isIdentifier(declarationTypeNode.typeName) &&
|
|
282
|
+
declarationTypeNode.typeName.text === "Readonly" &&
|
|
283
|
+
Is.arrayValue(declarationTypeNode.typeArguments)) {
|
|
284
|
+
return ImportTypeQuerySchemaResolver.extractConstObjectPropertyFromDeclarationType(declarationTypeNode.typeArguments[0], propertyName);
|
|
285
|
+
}
|
|
286
|
+
if (ts.isTypeLiteralNode(declarationTypeNode)) {
|
|
287
|
+
const propertySignature = declarationTypeNode.members.find((member) => {
|
|
288
|
+
if (!ts.isPropertySignature(member) || !member.name) {
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
return ((ts.isIdentifier(member.name) && member.name.text === propertyName) ||
|
|
292
|
+
(ts.isStringLiteral(member.name) && member.name.text === propertyName) ||
|
|
293
|
+
(ts.isNumericLiteral(member.name) && member.name.text === propertyName));
|
|
294
|
+
});
|
|
295
|
+
if (propertySignature?.type) {
|
|
296
|
+
return ImportTypeQuerySchemaResolver.extractLiteralValueFromTypeNode(propertySignature.type);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return undefined;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Extract a literal value from a type node when possible.
|
|
303
|
+
*/
|
|
304
|
+
static extractLiteralValueFromTypeNode(typeNode) {
|
|
305
|
+
if (ts.isLiteralTypeNode(typeNode)) {
|
|
306
|
+
if (ts.isStringLiteral(typeNode.literal)) {
|
|
307
|
+
return typeNode.literal.text;
|
|
308
|
+
}
|
|
309
|
+
if (ts.isNumericLiteral(typeNode.literal)) {
|
|
310
|
+
return Number(typeNode.literal.text);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return undefined;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Extract a referenced type name from an import type qualifier.
|
|
317
|
+
*/
|
|
318
|
+
static extractImportTypeName(qualifier) {
|
|
319
|
+
if (!qualifier) {
|
|
320
|
+
return undefined;
|
|
321
|
+
}
|
|
322
|
+
if (ts.isIdentifier(qualifier)) {
|
|
323
|
+
return qualifier.text;
|
|
324
|
+
}
|
|
325
|
+
return qualifier.right.text;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
//# sourceMappingURL=importTypeQuerySchemaResolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"importTypeQuerySchemaResolver.js","sourceRoot":"","sources":["../../../src/utils/importTypeQuerySchemaResolver.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,+DAA+D;AAC/D,OAAO,EAAE,EAAE,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAElD,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGzC;;GAEG;AACH,MAAM,OAAO,6BAA6B;IACzC;;OAEG;IACI,MAAM,CAAC,yBAAyB,CACtC,OAAmC,EACnC,QAA2B;QAE3B,IACC,QAAQ,CAAC,QAAQ;YACjB,CAAC,EAAE,CAAC,iBAAiB,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACxC,CAAC,EAAE,CAAC,eAAe,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAC7C,CAAC;YACF,kBAAkB,CAAC,MAAM,CACxB,OAAO,EACP,QAAQ,EACR,wDAAwD,EACxD,EAAE,QAAQ,EAAE,QAAQ,CAAC,OAAO,EAAE,EAAE,CAChC,CAAC;YACF,OAAO,EAAE,CAAC;QACX,CAAC;QAED,MAAM,eAAe,GAAG,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC;QACvD,MAAM,QAAQ,GAAG,6BAA6B,CAAC,qBAAqB,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QACzF,IAAI,CAAC,QAAQ,EAAE,CAAC;YACf,kBAAkB,CAAC,MAAM,CACxB,OAAO,EACP,QAAQ,EACR,4DAA4D,EAC5D,EAAE,QAAQ,EAAE,eAAe,EAAE,CAC7B,CAAC;YACF,OAAO,EAAE,CAAC;QACX,CAAC;QAED,MAAM,KAAK,GAAG,YAAY,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;QACjD,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,2BAA2B,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACvF,MAAM,gBAAgB,GACrB,gBAAgB;YAChB,6BAA6B,CAAC,kCAAkC,CAC/D,OAAO,EACP,eAAe,EACf,QAAQ,EACR,KAAK,CACL,CAAC;QAEH,OAAO;YACN,IAAI,EAAE,gBAAgB,IAAI,GAAG,OAAO,CAAC,SAAS,GAAG,KAAK,EAAE;SACxD,CAAC;IACH,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,wBAAwB,CACrC,OAAmC,EACnC,QAA0B;QAE1B,IAAI,EAAE,CAAC,eAAe,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACtF,MAAM,UAAU,GAAG,iBAAiB,CAAC,+BAA+B,CACnE,OAAO,EACP,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAC3B,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAC5B,CAAC;YACF,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;gBAC9B,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;YAC9B,CAAC;YAED,MAAM,aAAa,GAAG,6BAA6B,CAAC,0BAA0B,CAC7E,OAAO,EACP,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAC3B,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAC5B,CAAC;YACF,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;gBACjC,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;YACjC,CAAC;YAED,kBAAkB,CAAC,MAAM,CACxB,OAAO,EACP,QAAQ,EACR,wDAAwD,EACxD,EAAE,MAAM,EAAE,QAAQ,CAAC,OAAO,EAAE,EAAE,CAC9B,CAAC;YACF,OAAO,EAAE,CAAC;QACX,CAAC;QAED,MAAM,QAAQ,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;QACzF,IAAI,CAAC,QAAQ,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC;YAC5C,kBAAkB,CAAC,MAAM,CACxB,OAAO,EACP,QAAQ,EACR,wDAAwD,EACxD,EAAE,MAAM,EAAE,QAAQ,CAAC,OAAO,EAAE,EAAE,CAC9B,CAAC;YACF,OAAO,EAAE,CAAC;QACX,CAAC;QAED,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,uBAAuB,CACjE,OAAO,CAAC,gBAAgB,EACxB,QAAQ,CACR,CAAC;QACF,IAAI,gBAAgB,EAAE,CAAC;YACtB,IAAI,gBAAgB,CAAC,IAAI,EAAE,CAAC;gBAC3B,OAAO,iBAAiB,CAAC,mBAAmB,CAAC,OAAO,EAAE,gBAAgB,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YACpF,CAAC;YACD,IAAI,gBAAgB,CAAC,WAAW,EAAE,CAAC;gBAClC,OAAO,iBAAiB,CAAC,yBAAyB,CAAC,OAAO,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAC;YAC3F,CAAC;QACF,CAAC;QAED,MAAM,uBAAuB,GAAG,iBAAiB,CAAC,8BAA8B,CAC/E,OAAO,EACP,QAAQ,CACR,CAAC;QACF,IAAI,uBAAuB,EAAE,CAAC;YAC7B,OAAO,uBAAuB,CAAC;QAChC,CAAC;QAED,kBAAkB,CAAC,MAAM,CACxB,OAAO,EACP,QAAQ,EACR,wDAAwD,EACxD,EAAE,MAAM,EAAE,QAAQ,EAAE,CACpB,CAAC;QAEF,OAAO,EAAE,CAAC;IACX,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,kCAAkC,CAC/C,OAAmC,EACnC,eAAuB,EACvB,QAAgB,EAChB,KAAa;QAEb,MAAM,eAAe,GAAG,iBAAiB,CAAC,6BAA6B,CACtE,OAAO,EACP,eAAe,EACf,QAAQ,CACR,CAAC;QAEF,IAAI,eAAe,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrC,IAAI,eAAe,EAAE,QAAQ,EAAE,CAAC;gBAC/B,OAAO,eAAe,CAAC,QAAQ,CAAC;YACjC,CAAC;YAED,MAAM,cAAc,GAAG,OAAO,CAAC,gBAAgB,EAAE,QAAQ,CAAC;YAC1D,IAAI,CAAC,cAAc,EAAE,CAAC;gBACrB,OAAO,SAAS,CAAC;YAClB,CAAC;YAED,MAAM,kBAAkB,GAAG,SAAS,CAAC,2BAA2B,CAC/D,cAAc,EACd,eAAe,CACf,CAAC;YACF,IAAI,CAAC,kBAAkB,EAAE,CAAC;gBACzB,OAAO,SAAS,CAAC;YAClB,CAAC;YAED,MAAM,cAAc,GAAG,SAAS,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC;YAC9D,IAAI,CAAC,cAAc,EAAE,CAAC;gBACrB,OAAO,SAAS,CAAC;YAClB,CAAC;YAED,iBAAiB,CAAC,qBAAqB,CAAC,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,EAAE,CAAC,CAAC;YACzF,OAAO,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC;QAC3D,CAAC;QAED,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC;QACtE,IAAI,cAAc,EAAE,CAAC;YACpB,OAAO,cAAc,CAAC;QACvB,CAAC;QAED,MAAM,iBAAiB,GAAG,QAAQ,CAAC,yBAAyB,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;QACxF,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACxB,OAAO,eAAe,EAAE,QAAQ,CAAC;QAClC,CAAC;QAED,MAAM,eAAe,GAA+B;YACnD,SAAS,EAAE,eAAe,EAAE,SAAS,IAAI,OAAO,CAAC,SAAS;YAC1D,WAAW,EAAE,eAAe;YAC5B,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;YAC1C,OAAO,EAAE,OAAO,CAAC,OAAO;SACxB,CAAC;QAEF,iBAAiB,CAAC,qBAAqB,CACtC,eAAe,EACf,iBAAiB,CAAC,UAAU,CAAC,QAAQ,EACrC,iBAAiB,CAAC,UAAU,CAAC,WAAW,EAAE,EAC1C,EAAE,CACF,CAAC;QAEF,OAAO,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,eAAe,EAAE,QAAQ,CAAC;IACpF,CAAC;IAED;;OAEG;IACK,MAAM,CAAC,0BAA0B,CACxC,OAAmC,EACnC,UAAkB,EAClB,YAAoB;QAEpB,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC;YAC/B,OAAO,SAAS,CAAC;QAClB,CAAC;QAED,MAAM,eAAe,GAAG,6BAA6B,CAAC,0BAA0B,CAC/E,OAAO,CAAC,gBAAgB,EACxB,UAAU,CACV,CAAC;QACF,IAAI,CAAC,eAAe,EAAE,CAAC;YACtB,OAAO,SAAS,CAAC;QAClB,CAAC;QAED,MAAM,YAAY,GAAG,6BAA6B,CAAC,kCAAkC,CACpF,OAAO,CAAC,gBAAgB,CAAC,QAAQ,EACjC,eAAe,CAAC,eAAe,CAC/B,CAAC;QACF,IAAI,CAAC,YAAY,EAAE,CAAC;YACnB,OAAO,SAAS,CAAC;QAClB,CAAC;QAED,MAAM,cAAc,GAAG,SAAS,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QACxD,IAAI,CAAC,cAAc,EAAE,CAAC;YACrB,OAAO,SAAS,CAAC;QAClB,CAAC;QAED,MAAM,kBAAkB,GAAG,EAAE,CAAC,gBAAgB,CAC7C,YAAY,EACZ,cAAc,EACd,EAAE,CAAC,YAAY,CAAC,MAAM,EACtB,IAAI,CACJ,CAAC;QAEF,IAAI,OAAO,GAAG,kBAAkB,CAAC,UAAU;aACzC,MAAM,CAAC,CAAC,IAAI,EAAgC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;aAC5E,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;aACvD,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,eAAe,CAAC,YAAY,CAAC,CAAC;QAE9F,OAAO,KAAK,6BAA6B,CAAC,oCAAoC,CAC7E,YAAY,EACZ,eAAe,CAAC,YAAY,EAC5B,IAAI,GAAG,EAAU,CACjB,CAAC;QAEF,IAAI,CAAC,OAAO,EAAE,CAAC;YACd,OAAO,SAAS,CAAC;QAClB,CAAC;QAED,MAAM,oBAAoB,GACzB,6BAA6B,CAAC,oDAAoD,CACjF,OAAO,EACP,YAAY,CACZ,CAAC;QACH,IAAI,oBAAoB,KAAK,SAAS,EAAE,CAAC;YACxC,OAAO,oBAAoB,CAAC;QAC7B,CAAC;QAED,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YAClB,OAAO,6BAA6B,CAAC,6CAA6C,CACjF,OAAO,CAAC,IAAI,EACZ,YAAY,CACZ,CAAC;QACH,CAAC;QAED,OAAO,SAAS,CAAC;IAClB,CAAC;IAED;;OAEG;IACK,MAAM,CAAC,oCAAoC,CAClD,cAAsB,EACtB,YAAoB,EACpB,YAAyB;QAEzB,MAAM,wBAAwB,GAAG,SAAS,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAC;QAC7E,IAAI,YAAY,CAAC,GAAG,CAAC,wBAAwB,CAAC,EAAE,CAAC;YAChD,OAAO,SAAS,CAAC;QAClB,CAAC;QACD,YAAY,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;QAE3C,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,EAAE,CAAC;YACb,OAAO,SAAS,CAAC;QAClB,CAAC;QAED,MAAM,UAAU,GAAG,EAAE,CAAC,gBAAgB,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAE7F,MAAM,WAAW,GAAG,UAAU,CAAC,UAAU;aACvC,MAAM,CAAC,CAAC,IAAI,EAAgC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;aAC5E,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;aACvD,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC;QAC9E,IAAI,WAAW,EAAE,CAAC;YACjB,OAAO,WAAW,CAAC;QACpB,CAAC;QAED,MAAM,eAAe,GAAuB;YAC3C,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ;YAC9B,gBAAgB,EAAE,EAAE,CAAC,oBAAoB,CAAC,QAAQ;YAClD,MAAM,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM;YAC9B,YAAY,EAAE,IAAI;SAClB,CAAC;QAEF,MAAM,gBAAgB,GAAG,UAAU,CAAC,UAAU;aAC5C,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC;aAC3F,OAAO,CAAC,SAAS,CAAC,EAAE;YACpB,MAAM,eAAe,GAAG,SAAS,CAAC,eAAe,CAAC;YAClD,OAAO,eAAe,IAAI,EAAE,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7F,CAAC,CAAC,CAAC;QAEJ,KAAK,MAAM,eAAe,IAAI,gBAAgB,EAAE,CAAC;YAChD,MAAM,kBAAkB,GAAG,EAAE,CAAC,iBAAiB,CAC9C,eAAe,EACf,cAAc,EACd,eAAe,EACf,EAAE,CAAC,GAAG,CACN,CAAC,cAAc,EAAE,gBAAgB,CAAC;YAEnC,IAAI,kBAAkB,EAAE,CAAC;gBACxB,MAAM,mBAAmB,GACxB,6BAA6B,CAAC,oCAAoC,CACjE,kBAAkB,EAClB,YAAY,EACZ,YAAY,CACZ,CAAC;gBACH,IAAI,mBAAmB,EAAE,CAAC;oBACzB,OAAO,mBAAmB,CAAC;gBAC5B,CAAC;YACF,CAAC;QACF,CAAC;QAED,OAAO,SAAS,CAAC;IAClB,CAAC;IAED;;OAEG;IACK,MAAM,CAAC,0BAA0B,CACxC,UAAyB,EACzB,SAAiB;QAOjB,KAAK,MAAM,SAAS,IAAI,UAAU,CAAC,UAAU,EAAE,CAAC;YAC/C,IAAI,EAAE,CAAC,mBAAmB,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,eAAe,CAAC,SAAS,CAAC,eAAe,CAAC,EAAE,CAAC;gBACxF,MAAM,QAAQ,GAAG,SAAS,CAAC,YAAY,EAAE,aAAa,CAAC;gBACvD,IAAI,QAAQ,IAAI,EAAE,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAC7C,MAAM,aAAa,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;oBAC/E,IAAI,aAAa,EAAE,CAAC;wBACnB,OAAO;4BACN,eAAe,EAAE,SAAS,CAAC,eAAe,CAAC,IAAI;4BAC/C,YAAY,EAAE,aAAa,CAAC,YAAY,EAAE,IAAI,IAAI,aAAa,CAAC,IAAI,CAAC,IAAI;yBACzE,CAAC;oBACH,CAAC;gBACF,CAAC;YACF,CAAC;QACF,CAAC;QAED,OAAO,SAAS,CAAC;IAClB,CAAC;IAED;;OAEG;IACK,MAAM,CAAC,kCAAkC,CAChD,wBAAgC,EAChC,eAAuB;QAEvB,MAAM,gCAAgC,GAAG,SAAS,CAAC,WAAW,CAAC,wBAAwB,CAAC,CAAC;QAEzF,IAAI,eAAe,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrC,OAAO,CACN,SAAS,CAAC,2BAA2B,CAAC,gCAAgC,EAAE,eAAe,CAAC;gBACxF,CAAC,eAAe,CAAC,QAAQ,CAAC,KAAK,CAAC;oBAC/B,CAAC,CAAC,SAAS,CAAC,2BAA2B,CACrC,gCAAgC,EAChC,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CACpC;oBACF,CAAC,CAAC,SAAS,CAAC,CACb,CAAC;QACH,CAAC;QAED,MAAM,eAAe,GAAuB;YAC3C,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ;YAC9B,gBAAgB,EAAE,EAAE,CAAC,oBAAoB,CAAC,QAAQ;YAClD,MAAM,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM;YAC9B,YAAY,EAAE,IAAI;SAClB,CAAC;QAEF,OAAO,EAAE,CAAC,iBAAiB,CAC1B,eAAe,EACf,gCAAgC,EAChC,eAAe,EACf,EAAE,CAAC,GAAG,CACN,CAAC,cAAc,EAAE,gBAAgB,CAAC;IACpC,CAAC;IAED;;OAEG;IACK,MAAM,CAAC,oDAAoD,CAClE,iBAAyC,EACzC,YAAoB;QAEpB,IAAI,CAAC,iBAAiB,CAAC,WAAW,EAAE,CAAC;YACpC,OAAO,SAAS,CAAC;QAClB,CAAC;QAED,IAAI,UAAkD,CAAC;QACvD,IAAI,EAAE,CAAC,yBAAyB,CAAC,iBAAiB,CAAC,WAAW,CAAC,EAAE,CAAC;YACjE,UAAU,GAAG,iBAAiB,CAAC,WAAW,CAAC;QAC5C,CAAC;aAAM,IACN,EAAE,CAAC,cAAc,CAAC,iBAAiB,CAAC,WAAW,CAAC;YAChD,EAAE,CAAC,yBAAyB,CAAC,iBAAiB,CAAC,WAAW,CAAC,UAAU,CAAC,EACrE,CAAC;YACF,UAAU,GAAG,iBAAiB,CAAC,WAAW,CAAC,UAAU,CAAC;QACvD,CAAC;QAED,IAAI,CAAC,UAAU,EAAE,CAAC;YACjB,OAAO,SAAS,CAAC;QAClB,CAAC;QAED,MAAM,IAAI,GAAG,UAAU,CAAC,UAAU;aAChC,MAAM,CAAC,CAAC,CAAC,EAA8B,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;aACrE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC;QAErE,IAAI,CAAC,IAAI,EAAE,CAAC;YACX,OAAO,SAAS,CAAC;QAClB,CAAC;QAED,IAAI,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;YAC1C,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;QAC9B,CAAC;QACD,IAAI,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;YAC3C,OAAO,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QACtC,CAAC;QAED,OAAO,SAAS,CAAC;IAClB,CAAC;IAED;;OAEG;IACK,MAAM,CAAC,6CAA6C,CAC3D,mBAAgC,EAChC,YAAoB;QAEpB,IAAI,EAAE,CAAC,uBAAuB,CAAC,mBAAmB,CAAC,EAAE,CAAC;YACrD,OAAO,6BAA6B,CAAC,6CAA6C,CACjF,mBAAmB,CAAC,IAAI,EACxB,YAAY,CACZ,CAAC;QACH,CAAC;QAED,IACC,EAAE,CAAC,kBAAkB,CAAC,mBAAmB,CAAC;YAC1C,mBAAmB,CAAC,QAAQ,KAAK,EAAE,CAAC,UAAU,CAAC,eAAe,EAC7D,CAAC;YACF,OAAO,6BAA6B,CAAC,6CAA6C,CACjF,mBAAmB,CAAC,IAAI,EACxB,YAAY,CACZ,CAAC;QACH,CAAC;QAED,IACC,EAAE,CAAC,mBAAmB,CAAC,mBAAmB,CAAC;YAC3C,EAAE,CAAC,YAAY,CAAC,mBAAmB,CAAC,QAAQ,CAAC;YAC7C,mBAAmB,CAAC,QAAQ,CAAC,IAAI,KAAK,UAAU;YAChD,EAAE,CAAC,UAAU,CAAC,mBAAmB,CAAC,aAAa,CAAC,EAC/C,CAAC;YACF,OAAO,6BAA6B,CAAC,6CAA6C,CACjF,mBAAmB,CAAC,aAAa,CAAC,CAAC,CAAC,EACpC,YAAY,CACZ,CAAC;QACH,CAAC;QAED,IAAI,EAAE,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,EAAE,CAAC;YAC/C,MAAM,iBAAiB,GAAG,mBAAmB,CAAC,OAAO,CAAC,IAAI,CACzD,CAAC,MAAM,EAAkC,EAAE;gBAC1C,IAAI,CAAC,EAAE,CAAC,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;oBACrD,OAAO,KAAK,CAAC;gBACd,CAAC;gBAED,OAAO,CACN,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,KAAK,YAAY,CAAC;oBACnE,CAAC,EAAE,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,KAAK,YAAY,CAAC;oBACtE,CAAC,EAAE,CAAC,gBAAgB,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,KAAK,YAAY,CAAC,CACvE,CAAC;YACH,CAAC,CACD,CAAC;YAEF,IAAI,iBAAiB,EAAE,IAAI,EAAE,CAAC;gBAC7B,OAAO,6BAA6B,CAAC,+BAA+B,CACnE,iBAAiB,CAAC,IAAI,CACtB,CAAC;YACH,CAAC;QACF,CAAC;QAED,OAAO,SAAS,CAAC;IAClB,CAAC;IAED;;OAEG;IACK,MAAM,CAAC,+BAA+B,CAC7C,QAAqB;QAErB,IAAI,EAAE,CAAC,iBAAiB,CAAC,QAAQ,CAAC,EAAE,CAAC;YACpC,IAAI,EAAE,CAAC,eAAe,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC1C,OAAO,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC;YAC9B,CAAC;YAED,IAAI,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC3C,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACtC,CAAC;QACF,CAAC;QAED,OAAO,SAAS,CAAC;IAClB,CAAC;IAED;;OAEG;IACK,MAAM,CAAC,qBAAqB,CAAC,SAAoC;QACxE,IAAI,CAAC,SAAS,EAAE,CAAC;YAChB,OAAO,SAAS,CAAC;QAClB,CAAC;QAED,IAAI,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,EAAE,CAAC;YAChC,OAAO,SAAS,CAAC,IAAI,CAAC;QACvB,CAAC;QAED,OAAO,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC;IAC7B,CAAC;CACD","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n/* eslint-disable jsdoc/require-param, jsdoc/require-returns */\nimport { Is, StringHelper } from \"@twin.org/core\";\nimport type { IJsonSchema } from \"@twin.org/tools-models\";\nimport * as ts from \"typescript\";\nimport { DiagnosticReporter } from \"./diagnosticReporter.js\";\nimport { FileUtils } from \"./fileUtils.js\";\nimport { JsonSchemaBuilder } from \"./jsonSchemaBuilder.js\";\nimport { Resolver } from \"./resolver.js\";\nimport type { ITypeScriptToSchemaContext } from \"../models/ITypeScriptToSchemaContext.js\";\n\n/**\n * Static helpers for import type and type query schema resolution.\n */\nexport class ImportTypeQuerySchemaResolver {\n\t/**\n\t * Map import type nodes (e.g. import(\"pkg\").Type) to schema references.\n\t */\n\tpublic static mapImportTypeNodeToSchema(\n\t\tcontext: ITypeScriptToSchemaContext,\n\t\ttypeNode: ts.ImportTypeNode\n\t): IJsonSchema | undefined {\n\t\tif (\n\t\t\ttypeNode.isTypeOf ||\n\t\t\t!ts.isLiteralTypeNode(typeNode.argument) ||\n\t\t\t!ts.isStringLiteral(typeNode.argument.literal)\n\t\t) {\n\t\t\tDiagnosticReporter.report(\n\t\t\t\tcontext,\n\t\t\t\ttypeNode,\n\t\t\t\t\"jsonSchemaBuilder.diagnostic.unsupportedImportTypeForm\",\n\t\t\t\t{ argument: typeNode.getText() }\n\t\t\t);\n\t\t\treturn {};\n\t\t}\n\n\t\tconst moduleSpecifier = typeNode.argument.literal.text;\n\t\tconst typeName = ImportTypeQuerySchemaResolver.extractImportTypeName(typeNode.qualifier);\n\t\tif (!typeName) {\n\t\t\tDiagnosticReporter.report(\n\t\t\t\tcontext,\n\t\t\t\ttypeNode,\n\t\t\t\t\"jsonSchemaBuilder.diagnostic.unresolvedImportTypeQualifier\",\n\t\t\t\t{ argument: moduleSpecifier }\n\t\t\t);\n\t\t\treturn {};\n\t\t}\n\n\t\tconst title = StringHelper.stripPrefix(typeName);\n\t\tconst existingSchemaId = JsonSchemaBuilder.findExistingSchemaIdByTitle(context, title);\n\t\tconst resolvedSchemaId =\n\t\t\texistingSchemaId ??\n\t\t\tImportTypeQuerySchemaResolver.resolveImportTypeReferenceSchemaId(\n\t\t\t\tcontext,\n\t\t\t\tmoduleSpecifier,\n\t\t\t\ttypeName,\n\t\t\t\ttitle\n\t\t\t);\n\n\t\treturn {\n\t\t\t$ref: resolvedSchemaId ?? `${context.namespace}${title}`\n\t\t};\n\t}\n\n\t/**\n\t * Map a type query node (typeof expr) to schema by resolving the referenced variable.\n\t */\n\tpublic static mapTypeQueryNodeToSchema(\n\t\tcontext: ITypeScriptToSchemaContext,\n\t\ttypeNode: ts.TypeQueryNode\n\t): IJsonSchema {\n\t\tif (ts.isQualifiedName(typeNode.exprName) && ts.isIdentifier(typeNode.exprName.left)) {\n\t\t\tconst localValue = JsonSchemaBuilder.resolveLocalConstObjectProperty(\n\t\t\t\tcontext,\n\t\t\t\ttypeNode.exprName.left.text,\n\t\t\t\ttypeNode.exprName.right.text\n\t\t\t);\n\t\t\tif (localValue !== undefined) {\n\t\t\t\treturn { const: localValue };\n\t\t\t}\n\n\t\t\tconst importedValue = ImportTypeQuerySchemaResolver.resolveConstObjectProperty(\n\t\t\t\tcontext,\n\t\t\t\ttypeNode.exprName.left.text,\n\t\t\t\ttypeNode.exprName.right.text\n\t\t\t);\n\t\t\tif (importedValue !== undefined) {\n\t\t\t\treturn { const: importedValue };\n\t\t\t}\n\n\t\t\tDiagnosticReporter.report(\n\t\t\t\tcontext,\n\t\t\t\ttypeNode,\n\t\t\t\t\"jsonSchemaBuilder.diagnostic.unresolvedTypeQueryTarget\",\n\t\t\t\t{ target: typeNode.getText() }\n\t\t\t);\n\t\t\treturn {};\n\t\t}\n\n\t\tconst exprName = ts.isIdentifier(typeNode.exprName) ? typeNode.exprName.text : undefined;\n\t\tif (!exprName || !context.activeSourceFile) {\n\t\t\tDiagnosticReporter.report(\n\t\t\t\tcontext,\n\t\t\t\ttypeNode,\n\t\t\t\t\"jsonSchemaBuilder.diagnostic.unresolvedTypeQueryTarget\",\n\t\t\t\t{ target: typeNode.getText() }\n\t\t\t);\n\t\t\treturn {};\n\t\t}\n\n\t\tconst localDeclaration = JsonSchemaBuilder.findVariableDeclaration(\n\t\t\tcontext.activeSourceFile,\n\t\t\texprName\n\t\t);\n\t\tif (localDeclaration) {\n\t\t\tif (localDeclaration.type) {\n\t\t\t\treturn JsonSchemaBuilder.mapTypeNodeToSchema(context, localDeclaration.type) ?? {};\n\t\t\t}\n\t\t\tif (localDeclaration.initializer) {\n\t\t\t\treturn JsonSchemaBuilder.inferSchemaFromExpression(context, localDeclaration.initializer);\n\t\t\t}\n\t\t}\n\n\t\tconst importedTypeQuerySchema = JsonSchemaBuilder.resolveImportedTypeQuerySchema(\n\t\t\tcontext,\n\t\t\texprName\n\t\t);\n\t\tif (importedTypeQuerySchema) {\n\t\t\treturn importedTypeQuerySchema;\n\t\t}\n\n\t\tDiagnosticReporter.report(\n\t\t\tcontext,\n\t\t\ttypeNode,\n\t\t\t\"jsonSchemaBuilder.diagnostic.unresolvedTypeQueryTarget\",\n\t\t\t{ target: exprName }\n\t\t);\n\n\t\treturn {};\n\t}\n\n\t/**\n\t * Resolve import-type references to local or external schema ids.\n\t */\n\tpublic static resolveImportTypeReferenceSchemaId(\n\t\tcontext: ITypeScriptToSchemaContext,\n\t\tmoduleSpecifier: string,\n\t\ttypeName: string,\n\t\ttitle: string\n\t): string | undefined {\n\t\tconst mappedReference = JsonSchemaBuilder.resolveReferenceMappingTarget(\n\t\t\tcontext,\n\t\t\tmoduleSpecifier,\n\t\t\ttypeName\n\t\t);\n\n\t\tif (moduleSpecifier.startsWith(\".\")) {\n\t\t\tif (mappedReference?.schemaId) {\n\t\t\t\treturn mappedReference.schemaId;\n\t\t\t}\n\n\t\t\tconst activeFilePath = context.activeSourceFile?.fileName;\n\t\t\tif (!activeFilePath) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tconst resolvedImportPath = FileUtils.resolveImportSourceFilePath(\n\t\t\t\tactiveFilePath,\n\t\t\t\tmoduleSpecifier\n\t\t\t);\n\t\t\tif (!resolvedImportPath) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tconst importedSource = FileUtils.readFile(resolvedImportPath);\n\t\t\tif (!importedSource) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tJsonSchemaBuilder.parseAllObjectSchemas(context, resolvedImportPath, importedSource, []);\n\t\t\treturn context.schemas[context.packageName]?.[title]?.$id;\n\t\t}\n\n\t\tconst cachedSchemaId = context.schemas[moduleSpecifier]?.[title]?.$id;\n\t\tif (cachedSchemaId) {\n\t\t\treturn cachedSchemaId;\n\t\t}\n\n\t\tconst declarationResult = Resolver.resolveTypeDeclarationAst(moduleSpecifier, typeName);\n\t\tif (!declarationResult) {\n\t\t\treturn mappedReference?.schemaId;\n\t\t}\n\n\t\tconst externalContext: ITypeScriptToSchemaContext = {\n\t\t\tnamespace: mappedReference?.namespace ?? context.namespace,\n\t\t\tpackageName: moduleSpecifier,\n\t\t\tschemas: context.schemas,\n\t\t\tactiveSourceFile: context.activeSourceFile,\n\t\t\toptions: context.options\n\t\t};\n\n\t\tJsonSchemaBuilder.parseAllObjectSchemas(\n\t\t\texternalContext,\n\t\t\tdeclarationResult.sourceFile.fileName,\n\t\t\tdeclarationResult.sourceFile.getFullText(),\n\t\t\t[]\n\t\t);\n\n\t\treturn context.schemas[moduleSpecifier]?.[title]?.$id ?? mappedReference?.schemaId;\n\t}\n\n\t/**\n\t * Resolve a property value from a const object declaration in an imported source file.\n\t */\n\tprivate static resolveConstObjectProperty(\n\t\tcontext: ITypeScriptToSchemaContext,\n\t\tobjectName: string,\n\t\tpropertyName: string\n\t): string | number | undefined {\n\t\tif (!context.activeSourceFile) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst importReference = ImportTypeQuerySchemaResolver.findImportedValueReference(\n\t\t\tcontext.activeSourceFile,\n\t\t\tobjectName\n\t\t);\n\t\tif (!importReference) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst resolvedPath = ImportTypeQuerySchemaResolver.resolveImportDeclarationSourceFile(\n\t\t\tcontext.activeSourceFile.fileName,\n\t\t\timportReference.moduleSpecifier\n\t\t);\n\t\tif (!resolvedPath) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst importedSource = FileUtils.readFile(resolvedPath);\n\t\tif (!importedSource) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst importedSourceFile = ts.createSourceFile(\n\t\t\tresolvedPath,\n\t\t\timportedSource,\n\t\t\tts.ScriptTarget.Latest,\n\t\t\ttrue\n\t\t);\n\n\t\tlet objDecl = importedSourceFile.statements\n\t\t\t.filter((stmt): stmt is ts.VariableStatement => ts.isVariableStatement(stmt))\n\t\t\t.flatMap(stmt => [...stmt.declarationList.declarations])\n\t\t\t.find(decl => ts.isIdentifier(decl.name) && decl.name.text === importReference.importedName);\n\n\t\tobjDecl ??= ImportTypeQuerySchemaResolver.findVariableDeclarationInModuleGraph(\n\t\t\tresolvedPath,\n\t\t\timportReference.importedName,\n\t\t\tnew Set<string>()\n\t\t);\n\n\t\tif (!objDecl) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst valueFromInitializer =\n\t\t\tImportTypeQuerySchemaResolver.extractConstObjectPropertyFromDeclarationInitializer(\n\t\t\t\tobjDecl,\n\t\t\t\tpropertyName\n\t\t\t);\n\t\tif (valueFromInitializer !== undefined) {\n\t\t\treturn valueFromInitializer;\n\t\t}\n\n\t\tif (objDecl.type) {\n\t\t\treturn ImportTypeQuerySchemaResolver.extractConstObjectPropertyFromDeclarationType(\n\t\t\t\tobjDecl.type,\n\t\t\t\tpropertyName\n\t\t\t);\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Find a variable declaration by traversing import and export chains.\n\t */\n\tprivate static findVariableDeclarationInModuleGraph(\n\t\tsourceFilePath: string,\n\t\tvariableName: string,\n\t\tvisitedFiles: Set<string>\n\t): ts.VariableDeclaration | undefined {\n\t\tconst normalizedSourceFilePath = FileUtils.normalizeFilePath(sourceFilePath);\n\t\tif (visitedFiles.has(normalizedSourceFilePath)) {\n\t\t\treturn undefined;\n\t\t}\n\t\tvisitedFiles.add(normalizedSourceFilePath);\n\n\t\tconst source = FileUtils.readFile(sourceFilePath);\n\t\tif (!source) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst sourceFile = ts.createSourceFile(sourceFilePath, source, ts.ScriptTarget.Latest, true);\n\n\t\tconst declaration = sourceFile.statements\n\t\t\t.filter((stmt): stmt is ts.VariableStatement => ts.isVariableStatement(stmt))\n\t\t\t.flatMap(stmt => [...stmt.declarationList.declarations])\n\t\t\t.find(decl => ts.isIdentifier(decl.name) && decl.name.text === variableName);\n\t\tif (declaration) {\n\t\t\treturn declaration;\n\t\t}\n\n\t\tconst compilerOptions: ts.CompilerOptions = {\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\n\t\tconst moduleSpecifiers = sourceFile.statements\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\treturn moduleSpecifier && ts.isStringLiteral(moduleSpecifier) ? [moduleSpecifier.text] : [];\n\t\t\t});\n\n\t\tfor (const moduleSpecifier of moduleSpecifiers) {\n\t\t\tconst resolvedModulePath = ts.resolveModuleName(\n\t\t\t\tmoduleSpecifier,\n\t\t\t\tsourceFilePath,\n\t\t\t\tcompilerOptions,\n\t\t\t\tts.sys\n\t\t\t).resolvedModule?.resolvedFileName;\n\n\t\t\tif (resolvedModulePath) {\n\t\t\t\tconst declarationInModule =\n\t\t\t\t\tImportTypeQuerySchemaResolver.findVariableDeclarationInModuleGraph(\n\t\t\t\t\t\tresolvedModulePath,\n\t\t\t\t\t\tvariableName,\n\t\t\t\t\t\tvisitedFiles\n\t\t\t\t\t);\n\t\t\t\tif (declarationInModule) {\n\t\t\t\t\treturn declarationInModule;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Find an imported symbol reference by local identifier name.\n\t */\n\tprivate static findImportedValueReference(\n\t\tsourceFile: ts.SourceFile,\n\t\tlocalName: string\n\t):\n\t\t| {\n\t\t\t\tmoduleSpecifier: string;\n\t\t\t\timportedName: string;\n\t\t }\n\t\t| undefined {\n\t\tfor (const statement of sourceFile.statements) {\n\t\t\tif (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier)) {\n\t\t\t\tconst bindings = statement.importClause?.namedBindings;\n\t\t\t\tif (bindings && ts.isNamedImports(bindings)) {\n\t\t\t\t\tconst importElement = bindings.elements.find(el => el.name.text === localName);\n\t\t\t\t\tif (importElement) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tmoduleSpecifier: statement.moduleSpecifier.text,\n\t\t\t\t\t\t\timportedName: importElement.propertyName?.text ?? importElement.name.text\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Resolve an import declaration module specifier to a source file.\n\t */\n\tprivate static resolveImportDeclarationSourceFile(\n\t\tcontainingSourceFilePath: string,\n\t\tmoduleSpecifier: string\n\t): string | undefined {\n\t\tconst resolvedContainingSourceFilePath = FileUtils.resolvePath(containingSourceFilePath);\n\n\t\tif (moduleSpecifier.startsWith(\".\")) {\n\t\t\treturn (\n\t\t\t\tFileUtils.resolveImportSourceFilePath(resolvedContainingSourceFilePath, moduleSpecifier) ??\n\t\t\t\t(moduleSpecifier.endsWith(\".js\")\n\t\t\t\t\t? FileUtils.resolveImportSourceFilePath(\n\t\t\t\t\t\t\tresolvedContainingSourceFilePath,\n\t\t\t\t\t\t\t`${moduleSpecifier.slice(0, -3)}.ts`\n\t\t\t\t\t\t)\n\t\t\t\t\t: undefined)\n\t\t\t);\n\t\t}\n\n\t\tconst compilerOptions: ts.CompilerOptions = {\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\n\t\treturn ts.resolveModuleName(\n\t\t\tmoduleSpecifier,\n\t\t\tresolvedContainingSourceFilePath,\n\t\t\tcompilerOptions,\n\t\t\tts.sys\n\t\t).resolvedModule?.resolvedFileName;\n\t}\n\n\t/**\n\t * Extract a const-object property value from a declaration initializer.\n\t */\n\tprivate static extractConstObjectPropertyFromDeclarationInitializer(\n\t\tobjectDeclaration: ts.VariableDeclaration,\n\t\tpropertyName: string\n\t): string | number | undefined {\n\t\tif (!objectDeclaration.initializer) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tlet objLiteral: ts.ObjectLiteralExpression | undefined;\n\t\tif (ts.isObjectLiteralExpression(objectDeclaration.initializer)) {\n\t\t\tobjLiteral = objectDeclaration.initializer;\n\t\t} else if (\n\t\t\tts.isAsExpression(objectDeclaration.initializer) &&\n\t\t\tts.isObjectLiteralExpression(objectDeclaration.initializer.expression)\n\t\t) {\n\t\t\tobjLiteral = objectDeclaration.initializer.expression;\n\t\t}\n\n\t\tif (!objLiteral) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst prop = objLiteral.properties\n\t\t\t.filter((p): p is ts.PropertyAssignment => ts.isPropertyAssignment(p))\n\t\t\t.find(p => ts.isIdentifier(p.name) && p.name.text === propertyName);\n\n\t\tif (!prop) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (ts.isStringLiteral(prop.initializer)) {\n\t\t\treturn prop.initializer.text;\n\t\t}\n\t\tif (ts.isNumericLiteral(prop.initializer)) {\n\t\t\treturn Number(prop.initializer.text);\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Extract a const-object property value from a declaration type annotation.\n\t */\n\tprivate static extractConstObjectPropertyFromDeclarationType(\n\t\tdeclarationTypeNode: ts.TypeNode,\n\t\tpropertyName: string\n\t): string | number | undefined {\n\t\tif (ts.isParenthesizedTypeNode(declarationTypeNode)) {\n\t\t\treturn ImportTypeQuerySchemaResolver.extractConstObjectPropertyFromDeclarationType(\n\t\t\t\tdeclarationTypeNode.type,\n\t\t\t\tpropertyName\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\tts.isTypeOperatorNode(declarationTypeNode) &&\n\t\t\tdeclarationTypeNode.operator === ts.SyntaxKind.ReadonlyKeyword\n\t\t) {\n\t\t\treturn ImportTypeQuerySchemaResolver.extractConstObjectPropertyFromDeclarationType(\n\t\t\t\tdeclarationTypeNode.type,\n\t\t\t\tpropertyName\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\tts.isTypeReferenceNode(declarationTypeNode) &&\n\t\t\tts.isIdentifier(declarationTypeNode.typeName) &&\n\t\t\tdeclarationTypeNode.typeName.text === \"Readonly\" &&\n\t\t\tIs.arrayValue(declarationTypeNode.typeArguments)\n\t\t) {\n\t\t\treturn ImportTypeQuerySchemaResolver.extractConstObjectPropertyFromDeclarationType(\n\t\t\t\tdeclarationTypeNode.typeArguments[0],\n\t\t\t\tpropertyName\n\t\t\t);\n\t\t}\n\n\t\tif (ts.isTypeLiteralNode(declarationTypeNode)) {\n\t\t\tconst propertySignature = declarationTypeNode.members.find(\n\t\t\t\t(member): member is ts.PropertySignature => {\n\t\t\t\t\tif (!ts.isPropertySignature(member) || !member.name) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn (\n\t\t\t\t\t\t(ts.isIdentifier(member.name) && member.name.text === propertyName) ||\n\t\t\t\t\t\t(ts.isStringLiteral(member.name) && member.name.text === propertyName) ||\n\t\t\t\t\t\t(ts.isNumericLiteral(member.name) && member.name.text === propertyName)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t);\n\n\t\t\tif (propertySignature?.type) {\n\t\t\t\treturn ImportTypeQuerySchemaResolver.extractLiteralValueFromTypeNode(\n\t\t\t\t\tpropertySignature.type\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Extract a literal value from a type node when possible.\n\t */\n\tprivate static extractLiteralValueFromTypeNode(\n\t\ttypeNode: ts.TypeNode\n\t): string | number | undefined {\n\t\tif (ts.isLiteralTypeNode(typeNode)) {\n\t\t\tif (ts.isStringLiteral(typeNode.literal)) {\n\t\t\t\treturn typeNode.literal.text;\n\t\t\t}\n\n\t\t\tif (ts.isNumericLiteral(typeNode.literal)) {\n\t\t\t\treturn Number(typeNode.literal.text);\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Extract a referenced type name from an import type qualifier.\n\t */\n\tprivate static extractImportTypeName(qualifier: ts.EntityName | undefined): string | undefined {\n\t\tif (!qualifier) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (ts.isIdentifier(qualifier)) {\n\t\t\treturn qualifier.text;\n\t\t}\n\n\t\treturn qualifier.right.text;\n\t}\n}\n"]}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// Copyright 2026 IOTA Stiftung.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
3
|
+
import * as ts from "typescript";
|
|
4
|
+
import { TemplateLiteralPatternBuilder } from "./templateLiteralPatternBuilder.js";
|
|
5
|
+
/**
|
|
6
|
+
* Resolves regex patterns for index signature key types.
|
|
7
|
+
*/
|
|
8
|
+
export class IndexSignaturePatternResolver {
|
|
9
|
+
/**
|
|
10
|
+
* Determine whether an index signature can be represented as JSON object additionalProperties.
|
|
11
|
+
* @param member The index signature declaration.
|
|
12
|
+
* @returns True if supported.
|
|
13
|
+
*/
|
|
14
|
+
static isSupportedIndexSignature(member) {
|
|
15
|
+
// [key: string]: Value (index signature, first parameter is the key)
|
|
16
|
+
const indexParameter = member.parameters[0];
|
|
17
|
+
if (!indexParameter?.type) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
// [key: string]: Value or [key: number]: Value (string or numeric key)
|
|
21
|
+
return (indexParameter.type.kind === ts.SyntaxKind.StringKeyword ||
|
|
22
|
+
indexParameter.type.kind === ts.SyntaxKind.NumberKeyword);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Extract a regex pattern for an index signature key type when representable.
|
|
26
|
+
* @param context The generation context.
|
|
27
|
+
* @param member The index signature declaration.
|
|
28
|
+
* @param getTypeParameterBinding Callback for resolving generic bindings.
|
|
29
|
+
* @returns The property-name pattern, if derivable.
|
|
30
|
+
*/
|
|
31
|
+
static extractIndexSignaturePattern(context, member, getTypeParameterBinding) {
|
|
32
|
+
const indexParameterType = member.parameters[0]?.type;
|
|
33
|
+
if (!indexParameterType) {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
const resolvedTemplateType = IndexSignaturePatternResolver.resolveTemplateLiteralTypeNode(context, indexParameterType, new Set(), getTypeParameterBinding);
|
|
37
|
+
return resolvedTemplateType
|
|
38
|
+
? TemplateLiteralPatternBuilder.buildTemplateLiteralPattern(resolvedTemplateType)
|
|
39
|
+
: undefined;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Resolve a template literal type node from a key-type expression.
|
|
43
|
+
* Handles parenthesised, readonly-wrapped, and type-aliased variants by recursing.
|
|
44
|
+
* A cycle guard via resolvingTypeNames prevents unbounded recursion on self-referential types.
|
|
45
|
+
* @param context The generation context.
|
|
46
|
+
* @param typeNode The key type node.
|
|
47
|
+
* @param resolvingTypeNames Type names currently being resolved.
|
|
48
|
+
* @param getTypeParameterBinding Callback for resolving generic bindings.
|
|
49
|
+
* @returns A template literal type node when resolvable.
|
|
50
|
+
* @internal
|
|
51
|
+
*/
|
|
52
|
+
static resolveTemplateLiteralTypeNode(context, typeNode, resolvingTypeNames, getTypeParameterBinding) {
|
|
53
|
+
// `prefix-${T}` or `${K}` (already a template literal type)
|
|
54
|
+
if (ts.isTemplateLiteralTypeNode(typeNode)) {
|
|
55
|
+
return typeNode;
|
|
56
|
+
}
|
|
57
|
+
// (KeyType) (parenthesised type, unwrap and recurse)
|
|
58
|
+
if (ts.isParenthesizedTypeNode(typeNode)) {
|
|
59
|
+
return IndexSignaturePatternResolver.resolveTemplateLiteralTypeNode(context, typeNode.type, resolvingTypeNames, getTypeParameterBinding);
|
|
60
|
+
}
|
|
61
|
+
// readonly KeyType (readonly-wrapped type operator, strip modifier and recurse)
|
|
62
|
+
if (ts.isTypeOperatorNode(typeNode) && typeNode.operator === ts.SyntaxKind.ReadonlyKeyword) {
|
|
63
|
+
return IndexSignaturePatternResolver.resolveTemplateLiteralTypeNode(context, typeNode.type, resolvingTypeNames, getTypeParameterBinding);
|
|
64
|
+
}
|
|
65
|
+
// MyKeyType (named type reference, resolve via binding or type alias in source file)
|
|
66
|
+
if (ts.isTypeReferenceNode(typeNode)) {
|
|
67
|
+
// Namespace.TypeName (qualified name) or TypeName (plain identifier)
|
|
68
|
+
const typeName = ts.isIdentifier(typeNode.typeName)
|
|
69
|
+
? typeNode.typeName.text
|
|
70
|
+
: typeNode.typeName.right.text;
|
|
71
|
+
if (resolvingTypeNames.has(typeName)) {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
const typeParameterBinding = getTypeParameterBinding(context, typeName);
|
|
75
|
+
if (typeParameterBinding) {
|
|
76
|
+
return IndexSignaturePatternResolver.resolveTemplateLiteralTypeNode(context, typeParameterBinding, resolvingTypeNames, getTypeParameterBinding);
|
|
77
|
+
}
|
|
78
|
+
const sourceFile = context.activeSourceFile;
|
|
79
|
+
if (!sourceFile) {
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
// type MyKeyType = `prefix-${string}` (look up a type alias in the active source file)
|
|
83
|
+
const typeAlias = sourceFile.statements.find((statement) => ts.isTypeAliasDeclaration(statement) && statement.name.text === typeName);
|
|
84
|
+
if (typeAlias) {
|
|
85
|
+
resolvingTypeNames.add(typeName);
|
|
86
|
+
const resolvedTemplateType = IndexSignaturePatternResolver.resolveTemplateLiteralTypeNode(context, typeAlias.type, resolvingTypeNames, getTypeParameterBinding);
|
|
87
|
+
resolvingTypeNames.delete(typeName);
|
|
88
|
+
return resolvedTemplateType;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=indexSignaturePatternResolver.js.map
|