@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.
Files changed (133) hide show
  1. package/README.md +2 -2
  2. package/dist/es/index.js +20 -11
  3. package/dist/es/index.js.map +1 -1
  4. package/dist/es/models/ITypeScriptToSchemaContext.js +2 -0
  5. package/dist/es/models/ITypeScriptToSchemaContext.js.map +1 -0
  6. package/dist/es/models/ITypeScriptToSchemaDiagnostics.js +4 -0
  7. package/dist/es/models/ITypeScriptToSchemaDiagnostics.js.map +1 -0
  8. package/dist/es/models/ITypeScriptToSchemaOptions.js +4 -0
  9. package/dist/es/models/ITypeScriptToSchemaOptions.js.map +1 -0
  10. package/dist/es/utils/constants.js +43 -0
  11. package/dist/es/utils/constants.js.map +1 -0
  12. package/dist/es/utils/diagnosticReporter.js +32 -0
  13. package/dist/es/utils/diagnosticReporter.js.map +1 -0
  14. package/dist/es/utils/disallowedTypeGuard.js +151 -0
  15. package/dist/es/utils/disallowedTypeGuard.js.map +1 -0
  16. package/dist/es/utils/enum.js +152 -0
  17. package/dist/es/utils/enum.js.map +1 -0
  18. package/dist/es/utils/fileUtils.js +130 -0
  19. package/dist/es/utils/fileUtils.js.map +1 -0
  20. package/dist/es/utils/importTypeQuerySchemaResolver.js +328 -0
  21. package/dist/es/utils/importTypeQuerySchemaResolver.js.map +1 -0
  22. package/dist/es/utils/indexSignaturePatternResolver.js +94 -0
  23. package/dist/es/utils/indexSignaturePatternResolver.js.map +1 -0
  24. package/dist/es/utils/intersectionSchemaMerger.js +85 -0
  25. package/dist/es/utils/intersectionSchemaMerger.js.map +1 -0
  26. package/dist/es/utils/jsDoc.js +120 -0
  27. package/dist/es/utils/jsDoc.js.map +1 -0
  28. package/dist/es/utils/jsonSchemaBuilder.js +3373 -0
  29. package/dist/es/utils/jsonSchemaBuilder.js.map +1 -0
  30. package/dist/es/utils/mappedTypeSchemaResolver.js +231 -0
  31. package/dist/es/utils/mappedTypeSchemaResolver.js.map +1 -0
  32. package/dist/es/utils/objectTransformer.js +162 -0
  33. package/dist/es/utils/objectTransformer.js.map +1 -0
  34. package/dist/es/utils/regEx.js +128 -0
  35. package/dist/es/utils/regEx.js.map +1 -0
  36. package/dist/es/utils/resolver.js +164 -0
  37. package/dist/es/utils/resolver.js.map +1 -0
  38. package/dist/es/utils/templateLiteralPatternBuilder.js +94 -0
  39. package/dist/es/utils/templateLiteralPatternBuilder.js.map +1 -0
  40. package/dist/es/utils/typeScriptToSchema.js +112 -0
  41. package/dist/es/utils/typeScriptToSchema.js.map +1 -0
  42. package/dist/es/utils/utilityTypeSchemaMapper.js +412 -0
  43. package/dist/es/utils/utilityTypeSchemaMapper.js.map +1 -0
  44. package/dist/types/index.d.ts +20 -11
  45. package/dist/types/models/ITypeScriptToSchemaContext.d.ts +64 -0
  46. package/dist/types/models/ITypeScriptToSchemaDiagnostics.d.ts +31 -0
  47. package/dist/types/models/ITypeScriptToSchemaOptions.d.ts +22 -0
  48. package/dist/types/utils/constants.d.ts +13 -0
  49. package/dist/types/utils/diagnosticReporter.d.ts +17 -0
  50. package/dist/types/utils/disallowedTypeGuard.d.ts +16 -0
  51. package/dist/types/utils/enum.d.ts +42 -0
  52. package/dist/types/utils/fileUtils.d.ts +66 -0
  53. package/dist/types/utils/importTypeQuerySchemaResolver.d.ts +52 -0
  54. package/dist/types/utils/indexSignaturePatternResolver.d.ts +21 -0
  55. package/dist/types/utils/intersectionSchemaMerger.d.ts +16 -0
  56. package/dist/types/utils/jsDoc.d.ts +46 -0
  57. package/dist/types/utils/jsonSchemaBuilder.d.ts +747 -0
  58. package/dist/types/utils/mappedTypeSchemaResolver.d.ts +46 -0
  59. package/dist/types/utils/objectTransformer.d.ts +33 -0
  60. package/dist/types/utils/regEx.d.ts +24 -0
  61. package/dist/types/utils/resolver.d.ts +16 -0
  62. package/dist/types/utils/templateLiteralPatternBuilder.d.ts +12 -0
  63. package/dist/types/utils/typeScriptToSchema.d.ts +31 -0
  64. package/dist/types/utils/utilityTypeSchemaMapper.d.ts +92 -0
  65. package/docs/changelog.md +176 -1
  66. package/docs/examples.md +87 -1
  67. package/docs/reference/classes/Constants.md +29 -0
  68. package/docs/reference/classes/DiagnosticReporter.md +49 -0
  69. package/docs/reference/classes/DisallowedTypeGuard.md +35 -0
  70. package/docs/reference/classes/Enum.md +93 -0
  71. package/docs/reference/classes/FileUtils.md +237 -0
  72. package/docs/reference/classes/ImportTypeQuerySchemaResolver.md +87 -0
  73. package/docs/reference/classes/IndexSignaturePatternResolver.md +69 -0
  74. package/docs/reference/classes/IntersectionSchemaMerger.md +48 -0
  75. package/docs/reference/classes/JsDoc.md +141 -0
  76. package/docs/reference/classes/JsonSchemaBuilder.md +2870 -0
  77. package/docs/reference/classes/MappedTypeSchemaResolver.md +211 -0
  78. package/docs/reference/classes/ObjectTransformer.md +119 -0
  79. package/docs/reference/classes/RegEx.md +99 -0
  80. package/docs/reference/classes/Resolver.md +41 -0
  81. package/docs/reference/classes/TemplateLiteralPatternBuilder.md +35 -0
  82. package/docs/reference/classes/TypeScriptToSchema.md +91 -0
  83. package/docs/reference/classes/UtilityTypeSchemaMapper.md +341 -0
  84. package/docs/reference/index.md +20 -14
  85. package/docs/reference/interfaces/ITypeScriptToSchemaContext.md +113 -0
  86. package/docs/reference/interfaces/ITypeScriptToSchemaDiagnostics.md +55 -0
  87. package/docs/reference/interfaces/ITypeScriptToSchemaOptions.md +44 -0
  88. package/locales/en.json +32 -1
  89. package/package.json +4 -3
  90. package/dist/es/models/IJsonSchema.js +0 -2
  91. package/dist/es/models/IJsonSchema.js.map +0 -1
  92. package/dist/es/models/IOpenApi.js +0 -2
  93. package/dist/es/models/IOpenApi.js.map +0 -1
  94. package/dist/es/models/IOpenApiExample.js +0 -4
  95. package/dist/es/models/IOpenApiExample.js.map +0 -1
  96. package/dist/es/models/IOpenApiHeader.js +0 -4
  97. package/dist/es/models/IOpenApiHeader.js.map +0 -1
  98. package/dist/es/models/IOpenApiPathMethod.js +0 -2
  99. package/dist/es/models/IOpenApiPathMethod.js.map +0 -1
  100. package/dist/es/models/IOpenApiResponse.js +0 -2
  101. package/dist/es/models/IOpenApiResponse.js.map +0 -1
  102. package/dist/es/models/IOpenApiSecurityScheme.js +0 -4
  103. package/dist/es/models/IOpenApiSecurityScheme.js.map +0 -1
  104. package/dist/es/models/IPackageJson.js +0 -4
  105. package/dist/es/models/IPackageJson.js.map +0 -1
  106. package/dist/es/models/jsonTypeName.js +0 -2
  107. package/dist/es/models/jsonTypeName.js.map +0 -1
  108. package/dist/es/utils/jsonSchemaHelper.js +0 -258
  109. package/dist/es/utils/jsonSchemaHelper.js.map +0 -1
  110. package/dist/es/utils/openApiHelper.js +0 -12
  111. package/dist/es/utils/openApiHelper.js.map +0 -1
  112. package/dist/types/models/IJsonSchema.d.ts +0 -5
  113. package/dist/types/models/IOpenApi.d.ts +0 -54
  114. package/dist/types/models/IOpenApiExample.d.ts +0 -13
  115. package/dist/types/models/IOpenApiHeader.d.ts +0 -19
  116. package/dist/types/models/IOpenApiPathMethod.d.ts +0 -65
  117. package/dist/types/models/IOpenApiResponse.d.ts +0 -32
  118. package/dist/types/models/IOpenApiSecurityScheme.d.ts +0 -25
  119. package/dist/types/models/IPackageJson.d.ts +0 -15
  120. package/dist/types/models/jsonTypeName.d.ts +0 -5
  121. package/dist/types/utils/jsonSchemaHelper.d.ts +0 -78
  122. package/dist/types/utils/openApiHelper.d.ts +0 -9
  123. package/docs/reference/classes/JsonSchemaHelper.md +0 -233
  124. package/docs/reference/classes/OpenApiHelper.md +0 -21
  125. package/docs/reference/interfaces/IOpenApi.md +0 -103
  126. package/docs/reference/interfaces/IOpenApiExample.md +0 -19
  127. package/docs/reference/interfaces/IOpenApiHeader.md +0 -31
  128. package/docs/reference/interfaces/IOpenApiPathMethod.md +0 -119
  129. package/docs/reference/interfaces/IOpenApiResponse.md +0 -35
  130. package/docs/reference/interfaces/IOpenApiSecurityScheme.md +0 -43
  131. package/docs/reference/interfaces/IPackageJson.md +0 -23
  132. package/docs/reference/type-aliases/IJsonSchema.md +0 -5
  133. package/docs/reference/type-aliases/JsonTypeName.md +0 -5
@@ -0,0 +1,164 @@
1
+ // Copyright 2026 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ import * as ts from "typescript";
4
+ import { FileUtils } from "./fileUtils.js";
5
+ /**
6
+ * Resolve TypeScript type declarations from package names.
7
+ */
8
+ export class Resolver {
9
+ /**
10
+ * Cache for resolved package entry files.
11
+ * @internal
12
+ */
13
+ static _resolvedModuleFileCache = {};
14
+ /**
15
+ * Cache for parsed source files.
16
+ * @internal
17
+ */
18
+ static _sourceFileCache = {};
19
+ /**
20
+ * Cache for resolved type declarations.
21
+ * @internal
22
+ */
23
+ static _typeDeclarationCache = {};
24
+ /**
25
+ * Resolve a type declaration AST from a package and type name.
26
+ * @param packageName The package to inspect.
27
+ * @param typeName The type to resolve.
28
+ * @returns The resolved declaration AST.
29
+ */
30
+ static resolveTypeDeclarationAst(packageName, typeName) {
31
+ const cacheKey = `${packageName}::${typeName}`;
32
+ const cachedDeclaration = Resolver._typeDeclarationCache[cacheKey];
33
+ if (cachedDeclaration !== undefined) {
34
+ return cachedDeclaration ?? undefined;
35
+ }
36
+ const compilerOptions = Resolver.getModuleResolutionCompilerOptions();
37
+ const containingFile = `${FileUtils.normalizeFilePath(FileUtils.getCurrentWorkingDirectory())}/__typeScriptToSchema__.ts`;
38
+ const resolvedModuleFileName = Resolver.resolvePackageEntryFile(packageName, containingFile, compilerOptions);
39
+ if (!resolvedModuleFileName) {
40
+ Resolver._typeDeclarationCache[cacheKey] = null;
41
+ return undefined;
42
+ }
43
+ const declarationResult = Resolver.findTypeDeclarationInModuleGraph(resolvedModuleFileName, typeName, new Set(), compilerOptions);
44
+ Resolver._typeDeclarationCache[cacheKey] = declarationResult ?? null;
45
+ return declarationResult;
46
+ }
47
+ /**
48
+ * Resolve and cache the package entry file for a module name.
49
+ * @param packageName The package to resolve.
50
+ * @param containingFile The containing file for module resolution.
51
+ * @param compilerOptions Compiler options for module resolution.
52
+ * @returns The resolved entry file path.
53
+ * @internal
54
+ */
55
+ static resolvePackageEntryFile(packageName, containingFile, compilerOptions) {
56
+ const cachedResolvedModuleFile = Resolver._resolvedModuleFileCache[packageName];
57
+ if (cachedResolvedModuleFile !== undefined) {
58
+ return cachedResolvedModuleFile ?? undefined;
59
+ }
60
+ const resolvedModule = ts.resolveModuleName(packageName, containingFile, compilerOptions, ts.sys).resolvedModule;
61
+ const resolvedModuleFileName = resolvedModule?.resolvedFileName;
62
+ if (!resolvedModuleFileName) {
63
+ Resolver._resolvedModuleFileCache[packageName] = null;
64
+ return undefined;
65
+ }
66
+ Resolver._resolvedModuleFileCache[packageName] = resolvedModuleFileName;
67
+ return resolvedModuleFileName;
68
+ }
69
+ /**
70
+ * Resolve compiler options for module lookup.
71
+ * @returns The compiler options.
72
+ * @internal
73
+ */
74
+ static getModuleResolutionCompilerOptions() {
75
+ return {
76
+ module: ts.ModuleKind.NodeNext,
77
+ moduleResolution: ts.ModuleResolutionKind.NodeNext,
78
+ target: ts.ScriptTarget.ESNext,
79
+ skipLibCheck: true
80
+ };
81
+ }
82
+ /**
83
+ * Find a type declaration by walking a module's import/export graph.
84
+ * @param sourceFilePath The source file path to inspect.
85
+ * @param typeName The type name to find.
86
+ * @param visitedFiles The visited file set.
87
+ * @param compilerOptions Compiler options for module resolution.
88
+ * @returns The matched declaration with its source file.
89
+ * @internal
90
+ */
91
+ static findTypeDeclarationInModuleGraph(sourceFilePath, typeName, visitedFiles, compilerOptions) {
92
+ const absoluteSourcePath = FileUtils.normalizeFilePath(sourceFilePath);
93
+ if (visitedFiles.has(absoluteSourcePath)) {
94
+ return undefined;
95
+ }
96
+ visitedFiles.add(absoluteSourcePath);
97
+ const sourceFile = Resolver.getOrCreateSourceFile(sourceFilePath);
98
+ if (!sourceFile) {
99
+ return undefined;
100
+ }
101
+ for (const statement of sourceFile.statements) {
102
+ // interface IFoo { ... } or type Foo = ... (the declaration we are searching for)
103
+ if ((ts.isInterfaceDeclaration(statement) || ts.isTypeAliasDeclaration(statement)) &&
104
+ statement.name.text === typeName) {
105
+ return {
106
+ sourceFile,
107
+ declaration: statement
108
+ };
109
+ }
110
+ }
111
+ const moduleSpecifiers = sourceFile.statements
112
+ // import { ... } from "..." or export { ... } from "..." (re-export and import chains)
113
+ .filter(statement => ts.isExportDeclaration(statement) || ts.isImportDeclaration(statement))
114
+ .flatMap(statement => {
115
+ const moduleSpecifier = statement.moduleSpecifier;
116
+ // "./module.js" (string literal module specifier)
117
+ return moduleSpecifier && ts.isStringLiteral(moduleSpecifier) ? [moduleSpecifier.text] : [];
118
+ });
119
+ for (const moduleSpecifier of moduleSpecifiers) {
120
+ const resolvedImportPath = Resolver.resolveModuleSpecifierFromFile(moduleSpecifier, sourceFilePath, compilerOptions);
121
+ if (resolvedImportPath) {
122
+ const declarationResult = Resolver.findTypeDeclarationInModuleGraph(resolvedImportPath, typeName, visitedFiles, compilerOptions);
123
+ if (declarationResult) {
124
+ return declarationResult;
125
+ }
126
+ }
127
+ }
128
+ return undefined;
129
+ }
130
+ /**
131
+ * Read and cache a parsed source file.
132
+ * @param sourceFilePath The source file path.
133
+ * @returns The parsed source file.
134
+ * @internal
135
+ */
136
+ static getOrCreateSourceFile(sourceFilePath) {
137
+ const normalizedPath = FileUtils.normalizeFilePath(sourceFilePath);
138
+ const cachedSourceFile = Resolver._sourceFileCache[normalizedPath];
139
+ if (cachedSourceFile !== undefined) {
140
+ return cachedSourceFile ?? undefined;
141
+ }
142
+ const source = FileUtils.readFile(sourceFilePath);
143
+ if (!source) {
144
+ Resolver._sourceFileCache[normalizedPath] = null;
145
+ return undefined;
146
+ }
147
+ const sourceFile = ts.createSourceFile(sourceFilePath, source, ts.ScriptTarget.Latest, true);
148
+ Resolver._sourceFileCache[normalizedPath] = sourceFile;
149
+ return sourceFile;
150
+ }
151
+ /**
152
+ * Resolve a module specifier from a containing file.
153
+ * @param moduleSpecifier The module specifier text.
154
+ * @param containingFilePath The file containing the import/export.
155
+ * @param compilerOptions Compiler options for module resolution.
156
+ * @returns The resolved file path.
157
+ * @internal
158
+ */
159
+ static resolveModuleSpecifierFromFile(moduleSpecifier, containingFilePath, compilerOptions) {
160
+ return ts.resolveModuleName(moduleSpecifier, containingFilePath, compilerOptions, ts.sys)
161
+ .resolvedModule?.resolvedFileName;
162
+ }
163
+ }
164
+ //# sourceMappingURL=resolver.js.map
@@ -0,0 +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"]}
@@ -0,0 +1,94 @@
1
+ // Copyright 2026 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ import { Is } from "@twin.org/core";
4
+ import * as ts from "typescript";
5
+ /**
6
+ * Builds regex patterns for TypeScript template literal types.
7
+ */
8
+ export class TemplateLiteralPatternBuilder {
9
+ /**
10
+ * Build a regular-expression pattern for a template literal type.
11
+ * @param typeNode The template literal type node.
12
+ * @returns The regex pattern, or undefined if a safe pattern cannot be derived.
13
+ */
14
+ static buildTemplateLiteralPattern(typeNode) {
15
+ // The head is the fixed prefix text before the first interpolation, e.g. "prefix-" in
16
+ // `prefix-${T}-suffix`
17
+ let templatePattern = `^${TemplateLiteralPatternBuilder.escapeRegexPattern(typeNode.head.text)}`;
18
+ // Each span is one ${T} interpolation plus the literal text that follows it
19
+ for (const templateSpan of typeNode.templateSpans) {
20
+ const spanPattern = TemplateLiteralPatternBuilder.buildTemplateLiteralSpanPattern(templateSpan.type);
21
+ if (!spanPattern) {
22
+ return undefined;
23
+ }
24
+ templatePattern += `${spanPattern}${TemplateLiteralPatternBuilder.escapeRegexPattern(templateSpan.literal.text)}`;
25
+ }
26
+ return `${templatePattern}$`;
27
+ }
28
+ /**
29
+ * Build a regex fragment for a template literal placeholder type.
30
+ * @param typeNode The placeholder type node.
31
+ * @returns The regex fragment, or undefined if unsupported.
32
+ * @internal
33
+ */
34
+ static buildTemplateLiteralSpanPattern(typeNode) {
35
+ // string (string keyword lets any content through)
36
+ if (typeNode.kind === ts.SyntaxKind.StringKeyword) {
37
+ return ".*";
38
+ }
39
+ // MyAlias (plain type reference with no type arguments is treated as open string)
40
+ if (ts.isTypeReferenceNode(typeNode) &&
41
+ ts.isIdentifier(typeNode.typeName) &&
42
+ (typeNode.typeArguments?.length ?? 0) === 0) {
43
+ return ".*";
44
+ }
45
+ // number (number keyword matches optional sign, digits, and optional decimal)
46
+ if (typeNode.kind === ts.SyntaxKind.NumberKeyword) {
47
+ return "-?(?:0|[1-9]\\d*)(?:\\.\\d+)?";
48
+ }
49
+ // boolean (boolean keyword matches the two literal words)
50
+ if (typeNode.kind === ts.SyntaxKind.BooleanKeyword) {
51
+ return "(?:true|false)";
52
+ }
53
+ // "hello" or 42 or true or false (literal type node)
54
+ if (ts.isLiteralTypeNode(typeNode)) {
55
+ // "hello" or 42 (string or numeric literal)
56
+ if (ts.isStringLiteral(typeNode.literal) || ts.isNumericLiteral(typeNode.literal)) {
57
+ return TemplateLiteralPatternBuilder.escapeRegexPattern(typeNode.literal.text);
58
+ }
59
+ // true (true keyword literal)
60
+ if (typeNode.literal.kind === ts.SyntaxKind.TrueKeyword) {
61
+ return "true";
62
+ }
63
+ // false (false keyword literal)
64
+ if (typeNode.literal.kind === ts.SyntaxKind.FalseKeyword) {
65
+ return "false";
66
+ }
67
+ }
68
+ // "a" | "b" | "c" (union of literal types)
69
+ if (ts.isUnionTypeNode(typeNode)) {
70
+ const unionPatterns = typeNode.types
71
+ .map(unionType => TemplateLiteralPatternBuilder.buildTemplateLiteralSpanPattern(unionType))
72
+ .filter((pattern) => Is.stringValue(pattern));
73
+ if (unionPatterns.length === typeNode.types.length) {
74
+ return `(?:${unionPatterns.join("|")})`;
75
+ }
76
+ }
77
+ // `prefix-${T}` (nested template literal type, strip outer anchors)
78
+ if (ts.isTemplateLiteralTypeNode(typeNode)) {
79
+ const nestedPattern = TemplateLiteralPatternBuilder.buildTemplateLiteralPattern(typeNode);
80
+ return nestedPattern ? nestedPattern.replace(/^\^/, "").replace(/\$$/, "") : undefined;
81
+ }
82
+ return undefined;
83
+ }
84
+ /**
85
+ * Escape regex metacharacters in a literal text fragment so it matches verbatim.
86
+ * @param value The text to escape.
87
+ * @returns The escaped regex text.
88
+ * @internal
89
+ */
90
+ static escapeRegexPattern(value) {
91
+ return value.replace(/[$()*+.?[\\\]^{|}-]/g, "\\$&");
92
+ }
93
+ }
94
+ //# sourceMappingURL=templateLiteralPatternBuilder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templateLiteralPatternBuilder.js","sourceRoot":"","sources":["../../../src/utils/templateLiteralPatternBuilder.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { Is } from \"@twin.org/core\";\nimport * as ts from \"typescript\";\n\n/**\n * Builds regex patterns for TypeScript template literal types.\n */\nexport class TemplateLiteralPatternBuilder {\n\t/**\n\t * Build a regular-expression pattern for a template literal type.\n\t * @param typeNode The template literal type node.\n\t * @returns The regex pattern, or undefined if a safe pattern cannot be derived.\n\t */\n\tpublic static buildTemplateLiteralPattern(\n\t\ttypeNode: ts.TemplateLiteralTypeNode\n\t): string | undefined {\n\t\t// The head is the fixed prefix text before the first interpolation, e.g. \"prefix-\" in\n\t\t// `prefix-${T}-suffix`\n\t\tlet templatePattern = `^${TemplateLiteralPatternBuilder.escapeRegexPattern(typeNode.head.text)}`;\n\n\t\t// Each span is one ${T} interpolation plus the literal text that follows it\n\t\tfor (const templateSpan of typeNode.templateSpans) {\n\t\t\tconst spanPattern = TemplateLiteralPatternBuilder.buildTemplateLiteralSpanPattern(\n\t\t\t\ttemplateSpan.type\n\t\t\t);\n\t\t\tif (!spanPattern) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\ttemplatePattern += `${spanPattern}${TemplateLiteralPatternBuilder.escapeRegexPattern(templateSpan.literal.text)}`;\n\t\t}\n\n\t\treturn `${templatePattern}$`;\n\t}\n\n\t/**\n\t * Build a regex fragment for a template literal placeholder type.\n\t * @param typeNode The placeholder type node.\n\t * @returns The regex fragment, or undefined if unsupported.\n\t * @internal\n\t */\n\tprivate static buildTemplateLiteralSpanPattern(typeNode: ts.TypeNode): string | undefined {\n\t\t// string (string keyword lets any content through)\n\t\tif (typeNode.kind === ts.SyntaxKind.StringKeyword) {\n\t\t\treturn \".*\";\n\t\t}\n\n\t\t// MyAlias (plain type reference with no type arguments is treated as open string)\n\t\tif (\n\t\t\tts.isTypeReferenceNode(typeNode) &&\n\t\t\tts.isIdentifier(typeNode.typeName) &&\n\t\t\t(typeNode.typeArguments?.length ?? 0) === 0\n\t\t) {\n\t\t\treturn \".*\";\n\t\t}\n\n\t\t// number (number keyword matches optional sign, digits, and optional decimal)\n\t\tif (typeNode.kind === ts.SyntaxKind.NumberKeyword) {\n\t\t\treturn \"-?(?:0|[1-9]\\\\d*)(?:\\\\.\\\\d+)?\";\n\t\t}\n\n\t\t// boolean (boolean keyword matches the two literal words)\n\t\tif (typeNode.kind === ts.SyntaxKind.BooleanKeyword) {\n\t\t\treturn \"(?:true|false)\";\n\t\t}\n\n\t\t// \"hello\" or 42 or true or false (literal type node)\n\t\tif (ts.isLiteralTypeNode(typeNode)) {\n\t\t\t// \"hello\" or 42 (string or numeric literal)\n\t\t\tif (ts.isStringLiteral(typeNode.literal) || ts.isNumericLiteral(typeNode.literal)) {\n\t\t\t\treturn TemplateLiteralPatternBuilder.escapeRegexPattern(typeNode.literal.text);\n\t\t\t}\n\n\t\t\t// true (true keyword literal)\n\t\t\tif (typeNode.literal.kind === ts.SyntaxKind.TrueKeyword) {\n\t\t\t\treturn \"true\";\n\t\t\t}\n\n\t\t\t// false (false keyword literal)\n\t\t\tif (typeNode.literal.kind === ts.SyntaxKind.FalseKeyword) {\n\t\t\t\treturn \"false\";\n\t\t\t}\n\t\t}\n\n\t\t// \"a\" | \"b\" | \"c\" (union of literal types)\n\t\tif (ts.isUnionTypeNode(typeNode)) {\n\t\t\tconst unionPatterns = typeNode.types\n\t\t\t\t.map(unionType => TemplateLiteralPatternBuilder.buildTemplateLiteralSpanPattern(unionType))\n\t\t\t\t.filter((pattern): pattern is string => Is.stringValue(pattern));\n\n\t\t\tif (unionPatterns.length === typeNode.types.length) {\n\t\t\t\treturn `(?:${unionPatterns.join(\"|\")})`;\n\t\t\t}\n\t\t}\n\n\t\t// `prefix-${T}` (nested template literal type, strip outer anchors)\n\t\tif (ts.isTemplateLiteralTypeNode(typeNode)) {\n\t\t\tconst nestedPattern = TemplateLiteralPatternBuilder.buildTemplateLiteralPattern(typeNode);\n\t\t\treturn nestedPattern ? nestedPattern.replace(/^\\^/, \"\").replace(/\\$$/, \"\") : undefined;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Escape regex metacharacters in a literal text fragment so it matches verbatim.\n\t * @param value The text to escape.\n\t * @returns The escaped regex text.\n\t * @internal\n\t */\n\tprivate static escapeRegexPattern(value: string): string {\n\t\treturn value.replace(/[$()*+.?[\\\\\\]^{|}-]/g, \"\\\\$&\");\n\t}\n}\n"]}
@@ -0,0 +1,112 @@
1
+ // Copyright 2026 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ import { Is, StringHelper } from "@twin.org/core";
4
+ import { FileUtils } from "./fileUtils.js";
5
+ import { JsonSchemaBuilder } from "./jsonSchemaBuilder.js";
6
+ import { Resolver } from "./resolver.js";
7
+ /**
8
+ * Class for converting TypeScript types to JSON Schema.
9
+ */
10
+ export class TypeScriptToSchema {
11
+ /**
12
+ * Generates a JSON schema from a TypeScript source file or type name.
13
+ * @param namespace The schema namespace.
14
+ * @param packageName The package name.
15
+ * @param schemas The package schema map.
16
+ * @param sourceFileOrTypeName The source file to process or type name to resolve.
17
+ * @param options Additional generation options.
18
+ * @returns The generated JSON schemas indexed by title.
19
+ */
20
+ async generateSchema(namespace, packageName, schemas, sourceFileOrTypeName, options) {
21
+ const suppressPackageWarnings = (options?.suppressPackageWarnings ?? [])
22
+ .filter(packageNameToSkip => Is.stringValue(packageNameToSkip))
23
+ .map(packageNameToSkip => packageNameToSkip.toLowerCase());
24
+ const filteredOptions = {
25
+ ...options,
26
+ onDiagnostic: diagnostic => {
27
+ if (suppressPackageWarnings.some(packageToSkip => this.isDiagnosticFromPackage(diagnostic.path, diagnostic.fileName, packageToSkip))) {
28
+ return;
29
+ }
30
+ options?.onDiagnostic?.(diagnostic);
31
+ }
32
+ };
33
+ const context = {
34
+ namespace,
35
+ packageName,
36
+ schemas,
37
+ options: filteredOptions
38
+ };
39
+ let generatedTitles = [];
40
+ context.schemas[context.packageName] ??= {};
41
+ const visitedFiles = [];
42
+ const sourceFiles = FileUtils.resolveSourceFiles(sourceFileOrTypeName);
43
+ if (sourceFiles.length > 0) {
44
+ for (const sourceFilePath of sourceFiles) {
45
+ const source = FileUtils.readFile(sourceFilePath);
46
+ if (source) {
47
+ const parsedTitles = JsonSchemaBuilder.parseAllObjectSchemas(context, sourceFilePath, source, visitedFiles);
48
+ for (const parsedTitle of parsedTitles) {
49
+ if (!generatedTitles.includes(parsedTitle)) {
50
+ generatedTitles.push(parsedTitle);
51
+ }
52
+ }
53
+ }
54
+ }
55
+ }
56
+ else if (this.isTypeNameInput(sourceFileOrTypeName)) {
57
+ const declarationResult = Resolver.resolveTypeDeclarationAst(context.packageName, sourceFileOrTypeName);
58
+ if (declarationResult) {
59
+ generatedTitles = JsonSchemaBuilder.parseAllObjectSchemas(context, declarationResult.sourceFile.fileName, declarationResult.sourceFile.getFullText(), visitedFiles);
60
+ }
61
+ }
62
+ else {
63
+ return {};
64
+ }
65
+ const generatedSchemas = {};
66
+ for (const generatedTitle of generatedTitles) {
67
+ const generatedSchema = context.schemas[context.packageName][generatedTitle];
68
+ if (generatedSchema) {
69
+ generatedSchemas[generatedTitle] = generatedSchema;
70
+ }
71
+ }
72
+ if (this.isTypeNameInput(sourceFileOrTypeName)) {
73
+ const requestedTitle = StringHelper.stripPrefix(sourceFileOrTypeName);
74
+ const requestedSchema = context.schemas[context.packageName][requestedTitle];
75
+ if (requestedSchema) {
76
+ generatedSchemas[requestedTitle] = requestedSchema;
77
+ }
78
+ }
79
+ return generatedSchemas;
80
+ }
81
+ /**
82
+ * Determine if a diagnostic originates from a specific package.
83
+ * @param path The schema or source path associated with the diagnostic.
84
+ * @param fileName The source filename associated with the diagnostic.
85
+ * @param packageName The package name to check, e.g. jose.
86
+ * @returns True if the diagnostic originated from the package.
87
+ */
88
+ isDiagnosticFromPackage(path, fileName, packageName) {
89
+ if (!Is.stringValue(packageName)) {
90
+ return false;
91
+ }
92
+ const sourcePaths = [fileName, path]
93
+ .filter((value) => Is.stringValue(value))
94
+ .map(value => value.replace(/\\/g, "/").toLowerCase());
95
+ const normalisedPackageName = packageName.toLowerCase();
96
+ const packagePath = `/node_modules/${normalisedPackageName}/`;
97
+ const packagePathNoTrailingSlash = `/node_modules/${normalisedPackageName}`;
98
+ return sourcePaths.some(sourcePath => sourcePath.includes(packagePath) || sourcePath.endsWith(packagePathNoTrailingSlash));
99
+ }
100
+ /**
101
+ * Determine whether an input value is a valid TypeScript type identifier.
102
+ * An identifier must start with a letter, underscore, or dollar sign and contain only
103
+ * alphanumerics, underscores, or dollar signs thereafter.
104
+ * @param value The value to inspect.
105
+ * @returns True if the value looks like a type name.
106
+ * @internal
107
+ */
108
+ isTypeNameInput(value) {
109
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/u.test(value);
110
+ }
111
+ }
112
+ //# sourceMappingURL=typeScriptToSchema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typeScriptToSchema.js","sourceRoot":"","sources":["../../../src/utils/typeScriptToSchema.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { Is, StringHelper } from \"@twin.org/core\";\nimport type { IJsonSchema } from \"@twin.org/tools-models\";\nimport { FileUtils } from \"./fileUtils.js\";\nimport { JsonSchemaBuilder } from \"./jsonSchemaBuilder.js\";\nimport { Resolver } from \"./resolver.js\";\nimport type { ITypeScriptToSchemaContext } from \"../models/ITypeScriptToSchemaContext.js\";\nimport type { ITypeScriptToSchemaOptions } from \"../models/ITypeScriptToSchemaOptions.js\";\n\n/**\n * Class for converting TypeScript types to JSON Schema.\n */\nexport class TypeScriptToSchema {\n\t/**\n\t * Generates a JSON schema from a TypeScript source file or type name.\n\t * @param namespace The schema namespace.\n\t * @param packageName The package name.\n\t * @param schemas The package schema map.\n\t * @param sourceFileOrTypeName The source file to process or type name to resolve.\n\t * @param options Additional generation options.\n\t * @returns The generated JSON schemas indexed by title.\n\t */\n\tpublic async generateSchema(\n\t\tnamespace: string,\n\t\tpackageName: string,\n\t\tschemas: { [id: string]: { [id: string]: IJsonSchema } },\n\t\tsourceFileOrTypeName: string,\n\t\toptions?: ITypeScriptToSchemaOptions\n\t): Promise<{ [id: string]: IJsonSchema }> {\n\t\tconst suppressPackageWarnings = (options?.suppressPackageWarnings ?? [])\n\t\t\t.filter(packageNameToSkip => Is.stringValue(packageNameToSkip))\n\t\t\t.map(packageNameToSkip => packageNameToSkip.toLowerCase());\n\t\tconst filteredOptions: ITypeScriptToSchemaOptions = {\n\t\t\t...options,\n\t\t\tonDiagnostic: diagnostic => {\n\t\t\t\tif (\n\t\t\t\t\tsuppressPackageWarnings.some(packageToSkip =>\n\t\t\t\t\t\tthis.isDiagnosticFromPackage(diagnostic.path, diagnostic.fileName, packageToSkip)\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\toptions?.onDiagnostic?.(diagnostic);\n\t\t\t}\n\t\t};\n\n\t\tconst context: ITypeScriptToSchemaContext = {\n\t\t\tnamespace,\n\t\t\tpackageName,\n\t\t\tschemas,\n\t\t\toptions: filteredOptions\n\t\t};\n\n\t\tlet generatedTitles: string[] = [];\n\t\tcontext.schemas[context.packageName] ??= {};\n\t\tconst visitedFiles: string[] = [];\n\t\tconst sourceFiles = FileUtils.resolveSourceFiles(sourceFileOrTypeName);\n\n\t\tif (sourceFiles.length > 0) {\n\t\t\tfor (const sourceFilePath of sourceFiles) {\n\t\t\t\tconst source = FileUtils.readFile(sourceFilePath);\n\t\t\t\tif (source) {\n\t\t\t\t\tconst parsedTitles = JsonSchemaBuilder.parseAllObjectSchemas(\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\tsourceFilePath,\n\t\t\t\t\t\tsource,\n\t\t\t\t\t\tvisitedFiles\n\t\t\t\t\t);\n\t\t\t\t\tfor (const parsedTitle of parsedTitles) {\n\t\t\t\t\t\tif (!generatedTitles.includes(parsedTitle)) {\n\t\t\t\t\t\t\tgeneratedTitles.push(parsedTitle);\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} else if (this.isTypeNameInput(sourceFileOrTypeName)) {\n\t\t\tconst declarationResult = Resolver.resolveTypeDeclarationAst(\n\t\t\t\tcontext.packageName,\n\t\t\t\tsourceFileOrTypeName\n\t\t\t);\n\t\t\tif (declarationResult) {\n\t\t\t\tgeneratedTitles = JsonSchemaBuilder.parseAllObjectSchemas(\n\t\t\t\t\tcontext,\n\t\t\t\t\tdeclarationResult.sourceFile.fileName,\n\t\t\t\t\tdeclarationResult.sourceFile.getFullText(),\n\t\t\t\t\tvisitedFiles\n\t\t\t\t);\n\t\t\t}\n\t\t} else {\n\t\t\treturn {};\n\t\t}\n\n\t\tconst generatedSchemas: { [id: string]: IJsonSchema } = {};\n\t\tfor (const generatedTitle of generatedTitles) {\n\t\t\tconst generatedSchema = context.schemas[context.packageName][generatedTitle];\n\t\t\tif (generatedSchema) {\n\t\t\t\tgeneratedSchemas[generatedTitle] = generatedSchema;\n\t\t\t}\n\t\t}\n\n\t\tif (this.isTypeNameInput(sourceFileOrTypeName)) {\n\t\t\tconst requestedTitle = StringHelper.stripPrefix(sourceFileOrTypeName);\n\t\t\tconst requestedSchema = context.schemas[context.packageName][requestedTitle];\n\t\t\tif (requestedSchema) {\n\t\t\t\tgeneratedSchemas[requestedTitle] = requestedSchema;\n\t\t\t}\n\t\t}\n\n\t\treturn generatedSchemas;\n\t}\n\n\t/**\n\t * Determine if a diagnostic originates from a specific package.\n\t * @param path The schema or source path associated with the diagnostic.\n\t * @param fileName The source filename associated with the diagnostic.\n\t * @param packageName The package name to check, e.g. jose.\n\t * @returns True if the diagnostic originated from the package.\n\t */\n\tpublic isDiagnosticFromPackage(\n\t\tpath: string,\n\t\tfileName: string | undefined,\n\t\tpackageName: string\n\t): boolean {\n\t\tif (!Is.stringValue(packageName)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst sourcePaths = [fileName, path]\n\t\t\t.filter((value): value is string => Is.stringValue(value))\n\t\t\t.map(value => value.replace(/\\\\/g, \"/\").toLowerCase());\n\t\tconst normalisedPackageName = packageName.toLowerCase();\n\t\tconst packagePath = `/node_modules/${normalisedPackageName}/`;\n\t\tconst packagePathNoTrailingSlash = `/node_modules/${normalisedPackageName}`;\n\n\t\treturn sourcePaths.some(\n\t\t\tsourcePath =>\n\t\t\t\tsourcePath.includes(packagePath) || sourcePath.endsWith(packagePathNoTrailingSlash)\n\t\t);\n\t}\n\n\t/**\n\t * Determine whether an input value is a valid TypeScript type identifier.\n\t * An identifier must start with a letter, underscore, or dollar sign and contain only\n\t * alphanumerics, underscores, or dollar signs thereafter.\n\t * @param value The value to inspect.\n\t * @returns True if the value looks like a type name.\n\t * @internal\n\t */\n\tprivate isTypeNameInput(value: string): boolean {\n\t\treturn /^[A-Za-z_$][A-Za-z0-9_$]*$/u.test(value);\n\t}\n}\n"]}