zinfer 0.0.1 → 0.1.1

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 (79) hide show
  1. package/README.md +477 -28
  2. package/bin/zinfer +2 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +484 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/core/brand-detector.d.ts +32 -0
  8. package/dist/core/brand-detector.d.ts.map +1 -0
  9. package/dist/core/brand-detector.js +121 -0
  10. package/dist/core/brand-detector.js.map +1 -0
  11. package/dist/core/config-loader.d.ts +85 -0
  12. package/dist/core/config-loader.d.ts.map +1 -0
  13. package/dist/core/config-loader.js +105 -0
  14. package/dist/core/config-loader.js.map +1 -0
  15. package/dist/core/description-extractor.d.ts +54 -0
  16. package/dist/core/description-extractor.d.ts.map +1 -0
  17. package/dist/core/description-extractor.js +180 -0
  18. package/dist/core/description-extractor.js.map +1 -0
  19. package/dist/core/errors.d.ts +35 -0
  20. package/dist/core/errors.d.ts.map +1 -0
  21. package/dist/core/errors.js +96 -0
  22. package/dist/core/errors.js.map +1 -0
  23. package/dist/core/extractor.d.ts +121 -0
  24. package/dist/core/extractor.d.ts.map +1 -0
  25. package/dist/core/extractor.js +494 -0
  26. package/dist/core/extractor.js.map +1 -0
  27. package/dist/core/file-resolver.d.ts +39 -0
  28. package/dist/core/file-resolver.d.ts.map +1 -0
  29. package/dist/core/file-resolver.js +88 -0
  30. package/dist/core/file-resolver.js.map +1 -0
  31. package/dist/core/getter-resolver.d.ts +67 -0
  32. package/dist/core/getter-resolver.d.ts.map +1 -0
  33. package/dist/core/getter-resolver.js +234 -0
  34. package/dist/core/getter-resolver.js.map +1 -0
  35. package/dist/core/import-resolver.d.ts +51 -0
  36. package/dist/core/import-resolver.d.ts.map +1 -0
  37. package/dist/core/import-resolver.js +158 -0
  38. package/dist/core/import-resolver.js.map +1 -0
  39. package/dist/core/index.d.ts +14 -0
  40. package/dist/core/index.d.ts.map +1 -0
  41. package/dist/core/index.js +13 -0
  42. package/dist/core/index.js.map +1 -0
  43. package/dist/core/logger.d.ts +20 -0
  44. package/dist/core/logger.d.ts.map +1 -0
  45. package/dist/core/logger.js +36 -0
  46. package/dist/core/logger.js.map +1 -0
  47. package/dist/core/name-mapper.d.ts +45 -0
  48. package/dist/core/name-mapper.d.ts.map +1 -0
  49. package/dist/core/name-mapper.js +82 -0
  50. package/dist/core/name-mapper.js.map +1 -0
  51. package/dist/core/normalizer.d.ts +24 -0
  52. package/dist/core/normalizer.d.ts.map +1 -0
  53. package/dist/core/normalizer.js +50 -0
  54. package/dist/core/normalizer.js.map +1 -0
  55. package/dist/core/schema-detector.d.ts +49 -0
  56. package/dist/core/schema-detector.d.ts.map +1 -0
  57. package/dist/core/schema-detector.js +272 -0
  58. package/dist/core/schema-detector.js.map +1 -0
  59. package/dist/core/schema-reference-analyzer.d.ts +77 -0
  60. package/dist/core/schema-reference-analyzer.d.ts.map +1 -0
  61. package/dist/core/schema-reference-analyzer.js +269 -0
  62. package/dist/core/schema-reference-analyzer.js.map +1 -0
  63. package/dist/core/test-generator.d.ts +97 -0
  64. package/dist/core/test-generator.d.ts.map +1 -0
  65. package/dist/core/test-generator.js +177 -0
  66. package/dist/core/test-generator.js.map +1 -0
  67. package/dist/core/type-printer.d.ts +46 -0
  68. package/dist/core/type-printer.d.ts.map +1 -0
  69. package/dist/core/type-printer.js +424 -0
  70. package/dist/core/type-printer.js.map +1 -0
  71. package/dist/core/types.d.ts +124 -0
  72. package/dist/core/types.d.ts.map +1 -0
  73. package/dist/core/types.js +5 -0
  74. package/dist/core/types.js.map +1 -0
  75. package/dist/index.d.ts +66 -0
  76. package/dist/index.d.ts.map +1 -0
  77. package/dist/index.js +79 -0
  78. package/dist/index.js.map +1 -0
  79. package/package.json +63 -7
@@ -0,0 +1,39 @@
1
+ import type { OutputOptions } from "./types.js";
2
+ /**
3
+ * Resolves file paths from glob patterns and generates output paths.
4
+ */
5
+ export declare class FileResolver {
6
+ /**
7
+ * Resolves input file paths from a glob pattern or array of patterns.
8
+ *
9
+ * @param pattern - Glob pattern(s) to match
10
+ * @param cwd - Current working directory (default: process.cwd())
11
+ * @returns Array of absolute file paths
12
+ */
13
+ resolveInputFiles(pattern: string | string[], cwd?: string): Promise<string[]>;
14
+ /**
15
+ * Resolves the output path for a given input file.
16
+ *
17
+ * @param inputPath - Absolute path to the input file
18
+ * @param options - Output options
19
+ * @param cwd - Current working directory
20
+ * @returns Absolute path to the output file
21
+ */
22
+ resolveOutputPath(inputPath: string, options: OutputOptions, cwd?: string): string;
23
+ /**
24
+ * Applies a pattern template to generate an output filename.
25
+ *
26
+ * Supported placeholders:
27
+ * - [name]: Input filename without extension
28
+ * - [ext]: Output extension (including dot)
29
+ *
30
+ * @param pattern - Pattern template (e.g., "[name].types[ext]")
31
+ * @param vars - Variables to substitute
32
+ * @returns Generated filename
33
+ */
34
+ applyPattern(pattern: string, vars: {
35
+ name: string;
36
+ ext: string;
37
+ }): string;
38
+ }
39
+ //# sourceMappingURL=file-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-resolver.d.ts","sourceRoot":"","sources":["../../src/core/file-resolver.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;GAEG;AACH,qBAAa,YAAY;IACvB;;;;;;OAMG;IACG,iBAAiB,CACrB,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,EAC1B,GAAG,GAAE,MAAsB,GAC1B,OAAO,CAAC,MAAM,EAAE,CAAC;IAiBpB;;;;;;;OAOG;IACH,iBAAiB,CACf,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,aAAa,EACtB,GAAG,GAAE,MAAsB,GAC1B,MAAM;IAoCT;;;;;;;;;;OAUG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM;CAO3E"}
@@ -0,0 +1,88 @@
1
+ import { glob } from "glob";
2
+ import { resolve, dirname, basename, extname, join } from "pathe";
3
+ /**
4
+ * Resolves file paths from glob patterns and generates output paths.
5
+ */
6
+ export class FileResolver {
7
+ /**
8
+ * Resolves input file paths from a glob pattern or array of patterns.
9
+ *
10
+ * @param pattern - Glob pattern(s) to match
11
+ * @param cwd - Current working directory (default: process.cwd())
12
+ * @returns Array of absolute file paths
13
+ */
14
+ async resolveInputFiles(pattern, cwd = process.cwd()) {
15
+ const patterns = Array.isArray(pattern) ? pattern : [pattern];
16
+ const allFiles = [];
17
+ for (const p of patterns) {
18
+ const files = await glob(p, {
19
+ cwd,
20
+ absolute: true,
21
+ nodir: true,
22
+ });
23
+ allFiles.push(...files);
24
+ }
25
+ // Remove duplicates and sort
26
+ return [...new Set(allFiles)].sort();
27
+ }
28
+ /**
29
+ * Resolves the output path for a given input file.
30
+ *
31
+ * @param inputPath - Absolute path to the input file
32
+ * @param options - Output options
33
+ * @param cwd - Current working directory
34
+ * @returns Absolute path to the output file
35
+ */
36
+ resolveOutputPath(inputPath, options, cwd = process.cwd()) {
37
+ // If outFile is specified, use it directly
38
+ if (options.outFile) {
39
+ return resolve(cwd, options.outFile);
40
+ }
41
+ // Determine base name and extension
42
+ const inputBasename = basename(inputPath);
43
+ const inputExt = extname(inputPath);
44
+ const inputName = inputBasename.slice(0, -inputExt.length);
45
+ // Apply output pattern
46
+ let outputName;
47
+ if (options.outPattern) {
48
+ outputName = this.applyPattern(options.outPattern, {
49
+ name: inputName,
50
+ ext: options.declaration ? ".d.ts" : ".ts",
51
+ });
52
+ }
53
+ else {
54
+ // Default pattern: [name].types.ts or [name].types.d.ts
55
+ const ext = options.declaration ? ".d.ts" : ".ts";
56
+ outputName = `${inputName}.types${ext}`;
57
+ }
58
+ // Determine output directory
59
+ let outputDir;
60
+ if (options.outDir) {
61
+ outputDir = resolve(cwd, options.outDir);
62
+ }
63
+ else {
64
+ // Same directory as input
65
+ outputDir = dirname(inputPath);
66
+ }
67
+ return join(outputDir, outputName);
68
+ }
69
+ /**
70
+ * Applies a pattern template to generate an output filename.
71
+ *
72
+ * Supported placeholders:
73
+ * - [name]: Input filename without extension
74
+ * - [ext]: Output extension (including dot)
75
+ *
76
+ * @param pattern - Pattern template (e.g., "[name].types[ext]")
77
+ * @param vars - Variables to substitute
78
+ * @returns Generated filename
79
+ */
80
+ applyPattern(pattern, vars) {
81
+ // Escape $ in replacement strings to prevent regex special character interpretation
82
+ // In String.replace(), $& means the matched substring, $1 means first capture group, etc.
83
+ const escapedName = vars.name.replace(/\$/g, "$$$$");
84
+ const escapedExt = vars.ext.replace(/\$/g, "$$$$");
85
+ return pattern.replace(/\[name\]/g, escapedName).replace(/\[ext\]/g, escapedExt);
86
+ }
87
+ }
88
+ //# sourceMappingURL=file-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-resolver.js","sourceRoot":"","sources":["../../src/core/file-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAGlE;;GAEG;AACH,MAAM,OAAO,YAAY;IACvB;;;;;;OAMG;IACH,KAAK,CAAC,iBAAiB,CACrB,OAA0B,EAC1B,MAAc,OAAO,CAAC,GAAG,EAAE;QAE3B,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QAC9D,MAAM,QAAQ,GAAa,EAAE,CAAC;QAE9B,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;YACzB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,CAAC,EAAE;gBAC1B,GAAG;gBACH,QAAQ,EAAE,IAAI;gBACd,KAAK,EAAE,IAAI;aACZ,CAAC,CAAC;YACH,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;QAC1B,CAAC;QAED,6BAA6B;QAC7B,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACvC,CAAC;IAED;;;;;;;OAOG;IACH,iBAAiB,CACf,SAAiB,EACjB,OAAsB,EACtB,MAAc,OAAO,CAAC,GAAG,EAAE;QAE3B,2CAA2C;QAC3C,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QACvC,CAAC;QAED,oCAAoC;QACpC,MAAM,aAAa,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;QACpC,MAAM,SAAS,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAE3D,uBAAuB;QACvB,IAAI,UAAkB,CAAC;QACvB,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YACvB,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,UAAU,EAAE;gBACjD,IAAI,EAAE,SAAS;gBACf,GAAG,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK;aAC3C,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,wDAAwD;YACxD,MAAM,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;YAClD,UAAU,GAAG,GAAG,SAAS,SAAS,GAAG,EAAE,CAAC;QAC1C,CAAC;QAED,6BAA6B;QAC7B,IAAI,SAAiB,CAAC;QACtB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,SAAS,GAAG,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAC3C,CAAC;aAAM,CAAC;YACN,0BAA0B;YAC1B,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;QACjC,CAAC;QAED,OAAO,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IACrC,CAAC;IAED;;;;;;;;;;OAUG;IACH,YAAY,CAAC,OAAe,EAAE,IAAmC;QAC/D,oFAAoF;QACpF,0FAA0F;QAC1F,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACrD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACnD,OAAO,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IACnF,CAAC;CACF"}
@@ -0,0 +1,67 @@
1
+ import { SourceFile } from "ts-morph";
2
+ /**
3
+ * Information about a getter field in a z.object schema.
4
+ */
5
+ export interface GetterFieldInfo {
6
+ /** Referenced schema name */
7
+ refSchema: string;
8
+ /** Whether the reference is wrapped in z.array() */
9
+ isArray: boolean;
10
+ /** Whether the reference is wrapped in z.record() */
11
+ isRecord: boolean;
12
+ /** Whether the field is optional (.optional() or .nullable()) */
13
+ isOptional: boolean;
14
+ /** Whether this is a self-reference */
15
+ isSelfRef: boolean;
16
+ }
17
+ /**
18
+ * Mapping of schema name to its getter field information.
19
+ */
20
+ export type GetterFieldMap = Map<string, Map<string, GetterFieldInfo>>;
21
+ /**
22
+ * Detects and resolves getter-based recursive patterns in Zod schemas.
23
+ */
24
+ export declare class GetterResolver {
25
+ /**
26
+ * Analyzes a source file to find getter field mappings.
27
+ *
28
+ * @param sourceFile - The ts-morph SourceFile to analyze
29
+ * @returns Map of schema name to field info
30
+ */
31
+ analyzeGetterFields(sourceFile: SourceFile): GetterFieldMap;
32
+ /**
33
+ * Extracts getter field info from AST nodes.
34
+ */
35
+ private extractGetterFieldsFromAST;
36
+ /**
37
+ * Parses the return expression AST to extract schema reference info.
38
+ */
39
+ private parseReturnExpressionAST;
40
+ /**
41
+ * Extracts schema reference from an argument node.
42
+ */
43
+ private extractSchemaRef;
44
+ /**
45
+ * Resolves `any` types in extracted type string by replacing with self-references.
46
+ * Uses structured parsing instead of regex.
47
+ *
48
+ * @param typeStr - The extracted type string with `any` placeholders
49
+ * @param getterFields - Map of field name to getter field info
50
+ * @param typeName - The generated type name to use for self-references
51
+ * @returns The resolved type string with proper self-references
52
+ */
53
+ resolveAnyTypes(typeStr: string, getterFields: Map<string, GetterFieldInfo>, typeName: string): string;
54
+ /**
55
+ * Replaces any type in a record field.
56
+ */
57
+ private replaceRecordAny;
58
+ /**
59
+ * Replaces any type in a regular field.
60
+ */
61
+ private replaceFieldAny;
62
+ /**
63
+ * Checks if a schema has getter-based self-references.
64
+ */
65
+ hasSelfReferences(getterFields: Map<string, GetterFieldInfo>): boolean;
66
+ }
67
+ //# sourceMappingURL=getter-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getter-resolver.d.ts","sourceRoot":"","sources":["../../src/core/getter-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAA8D,MAAM,UAAU,CAAC;AAElG;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,6BAA6B;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,OAAO,EAAE,OAAO,CAAC;IACjB,qDAAqD;IACrD,QAAQ,EAAE,OAAO,CAAC;IAClB,iEAAiE;IACjE,UAAU,EAAE,OAAO,CAAC;IACpB,uCAAuC;IACvC,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC;AAEvE;;GAEG;AACH,qBAAa,cAAc;IACzB;;;;;OAKG;IACH,mBAAmB,CAAC,UAAU,EAAE,UAAU,GAAG,cAAc;IAqB3D;;OAEG;IACH,OAAO,CAAC,0BAA0B;IA2BlC;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAyEhC;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAOxB;;;;;;;;OAQG;IACH,eAAe,CACb,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,EAC1C,QAAQ,EAAE,MAAM,GACf,MAAM;IAoBT;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAkCxB;;OAEG;IACH,OAAO,CAAC,eAAe;IAuDvB;;OAEG;IACH,iBAAiB,CAAC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,OAAO;CAGvE"}
@@ -0,0 +1,234 @@
1
+ import { SyntaxKind, Node } from "ts-morph";
2
+ /**
3
+ * Detects and resolves getter-based recursive patterns in Zod schemas.
4
+ */
5
+ export class GetterResolver {
6
+ /**
7
+ * Analyzes a source file to find getter field mappings.
8
+ *
9
+ * @param sourceFile - The ts-morph SourceFile to analyze
10
+ * @returns Map of schema name to field info
11
+ */
12
+ analyzeGetterFields(sourceFile) {
13
+ const result = new Map();
14
+ const statements = sourceFile.getVariableStatements();
15
+ for (const stmt of statements) {
16
+ for (const decl of stmt.getDeclarations()) {
17
+ const schemaName = decl.getName();
18
+ const init = decl.getInitializer();
19
+ if (!init)
20
+ continue;
21
+ const fieldMap = this.extractGetterFieldsFromAST(init, schemaName);
22
+ if (fieldMap.size > 0) {
23
+ result.set(schemaName, fieldMap);
24
+ }
25
+ }
26
+ }
27
+ return result;
28
+ }
29
+ /**
30
+ * Extracts getter field info from AST nodes.
31
+ */
32
+ extractGetterFieldsFromAST(node, schemaName) {
33
+ const fieldMap = new Map();
34
+ // Find all getter declarations within the node
35
+ const getters = node.getDescendantsOfKind(SyntaxKind.GetAccessor);
36
+ for (const getter of getters) {
37
+ const fieldName = getter.getName();
38
+ const body = getter.getBody();
39
+ if (!body)
40
+ continue;
41
+ // Find return statement
42
+ const returnStmt = body.getFirstDescendantByKind(SyntaxKind.ReturnStatement);
43
+ if (!returnStmt)
44
+ continue;
45
+ const returnExpr = returnStmt.getExpression();
46
+ if (!returnExpr)
47
+ continue;
48
+ const info = this.parseReturnExpressionAST(returnExpr, schemaName);
49
+ if (info) {
50
+ fieldMap.set(fieldName, info);
51
+ }
52
+ }
53
+ return fieldMap;
54
+ }
55
+ /**
56
+ * Parses the return expression AST to extract schema reference info.
57
+ */
58
+ parseReturnExpressionAST(expr, schemaName) {
59
+ let isArray = false;
60
+ let isRecord = false;
61
+ let isOptional = false;
62
+ let refSchema = null;
63
+ // Unwrap method chains like .optional(), .nullable(), .array()
64
+ let currentExpr = expr;
65
+ while (Node.isCallExpression(currentExpr)) {
66
+ const callExpr = currentExpr;
67
+ const exprNode = callExpr.getExpression();
68
+ if (Node.isPropertyAccessExpression(exprNode)) {
69
+ const propAccess = exprNode;
70
+ const methodName = propAccess.getName();
71
+ const baseExpr = propAccess.getExpression();
72
+ // Check for .optional() or .nullable() on a schema
73
+ if (methodName === "optional" || methodName === "nullable") {
74
+ isOptional = true;
75
+ currentExpr = baseExpr;
76
+ continue;
77
+ }
78
+ // Check for SchemaName.array() pattern
79
+ if (methodName === "array" && Node.isIdentifier(baseExpr)) {
80
+ const baseName = baseExpr.getText();
81
+ if (baseName !== "z") {
82
+ isArray = true;
83
+ refSchema = baseName;
84
+ break;
85
+ }
86
+ }
87
+ // Check for z.array(SchemaName) or z.record(key, SchemaName)
88
+ if (Node.isIdentifier(baseExpr) && baseExpr.getText() === "z") {
89
+ const args = callExpr.getArguments();
90
+ if (methodName === "array" && args.length > 0) {
91
+ isArray = true;
92
+ refSchema = this.extractSchemaRef(args[0]);
93
+ break;
94
+ }
95
+ if (methodName === "record" && args.length >= 2) {
96
+ isRecord = true;
97
+ refSchema = this.extractSchemaRef(args[1]);
98
+ break;
99
+ }
100
+ }
101
+ }
102
+ break;
103
+ }
104
+ // If we haven't found a ref yet, check if currentExpr is an identifier
105
+ if (!refSchema && Node.isIdentifier(currentExpr)) {
106
+ refSchema = currentExpr.getText();
107
+ }
108
+ if (!refSchema) {
109
+ return null;
110
+ }
111
+ return {
112
+ refSchema,
113
+ isArray,
114
+ isRecord,
115
+ isOptional,
116
+ isSelfRef: refSchema === schemaName,
117
+ };
118
+ }
119
+ /**
120
+ * Extracts schema reference from an argument node.
121
+ */
122
+ extractSchemaRef(node) {
123
+ if (Node.isIdentifier(node)) {
124
+ return node.getText();
125
+ }
126
+ return null;
127
+ }
128
+ /**
129
+ * Resolves `any` types in extracted type string by replacing with self-references.
130
+ * Uses structured parsing instead of regex.
131
+ *
132
+ * @param typeStr - The extracted type string with `any` placeholders
133
+ * @param getterFields - Map of field name to getter field info
134
+ * @param typeName - The generated type name to use for self-references
135
+ * @returns The resolved type string with proper self-references
136
+ */
137
+ resolveAnyTypes(typeStr, getterFields, typeName) {
138
+ let result = typeStr;
139
+ for (const [fieldName, info] of getterFields) {
140
+ if (!info.isSelfRef) {
141
+ continue;
142
+ }
143
+ // For z.record pattern: { [x: string]: any } -> { [x: string]: TypeName }
144
+ if (info.isRecord) {
145
+ result = this.replaceRecordAny(result, fieldName, typeName);
146
+ }
147
+ // Handle any field (array or single reference)
148
+ result = this.replaceFieldAny(result, fieldName, typeName, info.isArray);
149
+ }
150
+ return result;
151
+ }
152
+ /**
153
+ * Replaces any type in a record field.
154
+ */
155
+ replaceRecordAny(typeStr, fieldName, typeName) {
156
+ // Find "fieldName: { [x: string]: any" or "fieldName?: { [x: string]: any"
157
+ const fieldPatterns = [`${fieldName}: {`, `${fieldName}?: {`];
158
+ const indexSigPattern = "[x: string]:";
159
+ for (const pattern of fieldPatterns) {
160
+ let idx = typeStr.indexOf(pattern);
161
+ while (idx !== -1) {
162
+ // Find the index signature pattern
163
+ const afterBrace = idx + pattern.length;
164
+ const indexSigStart = typeStr.indexOf(indexSigPattern, afterBrace);
165
+ if (indexSigStart !== -1 && indexSigStart < afterBrace + 20) {
166
+ const colonPos = indexSigStart + indexSigPattern.length;
167
+ // Find "any" after the colon - count whitespace explicitly
168
+ let scanPos = colonPos;
169
+ while (scanPos < typeStr.length && /\s/.test(typeStr[scanPos])) {
170
+ scanPos++;
171
+ }
172
+ if (typeStr.substring(scanPos, scanPos + 3) === "any") {
173
+ const anyStart = scanPos;
174
+ const anyEnd = anyStart + 3;
175
+ typeStr = typeStr.substring(0, anyStart) + typeName + typeStr.substring(anyEnd);
176
+ }
177
+ }
178
+ idx = typeStr.indexOf(pattern, idx + 1);
179
+ }
180
+ }
181
+ return typeStr;
182
+ }
183
+ /**
184
+ * Replaces any type in a regular field.
185
+ */
186
+ replaceFieldAny(typeStr, fieldName, typeName, isArray) {
187
+ // Find "fieldName: any" or "fieldName?: any" patterns
188
+ const fieldPatterns = [`${fieldName}: `, `${fieldName}?: `];
189
+ for (const pattern of fieldPatterns) {
190
+ let idx = typeStr.indexOf(pattern);
191
+ while (idx !== -1) {
192
+ const valueStart = idx + pattern.length;
193
+ const restOfType = typeStr.substring(valueStart);
194
+ // Check for "readonly any" or just "any"
195
+ let anyIdx = -1;
196
+ let prefixLen = 0;
197
+ if (restOfType.startsWith("readonly ")) {
198
+ prefixLen = "readonly ".length;
199
+ if (restOfType.substring(prefixLen).startsWith("any")) {
200
+ anyIdx = valueStart + prefixLen;
201
+ }
202
+ }
203
+ else if (restOfType.startsWith("any")) {
204
+ anyIdx = valueStart;
205
+ }
206
+ if (anyIdx !== -1) {
207
+ // Check what comes after "any"
208
+ const afterAny = typeStr.substring(anyIdx + 3);
209
+ const hasArrayBrackets = afterAny.startsWith("[]");
210
+ // Build replacement
211
+ let replacement = typeName;
212
+ if (isArray || hasArrayBrackets) {
213
+ replacement = `${typeName}[]`;
214
+ }
215
+ // Calculate end position (include [] if present)
216
+ let endPos = anyIdx + 3;
217
+ if (hasArrayBrackets) {
218
+ endPos += 2;
219
+ }
220
+ typeStr = typeStr.substring(0, anyIdx) + replacement + typeStr.substring(endPos);
221
+ }
222
+ idx = typeStr.indexOf(pattern, idx + 1);
223
+ }
224
+ }
225
+ return typeStr;
226
+ }
227
+ /**
228
+ * Checks if a schema has getter-based self-references.
229
+ */
230
+ hasSelfReferences(getterFields) {
231
+ return Array.from(getterFields.values()).some((info) => info.isSelfRef);
232
+ }
233
+ }
234
+ //# sourceMappingURL=getter-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getter-resolver.js","sourceRoot":"","sources":["../../src/core/getter-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,UAAU,EAAE,IAAI,EAA4C,MAAM,UAAU,CAAC;AAuBlG;;GAEG;AACH,MAAM,OAAO,cAAc;IACzB;;;;;OAKG;IACH,mBAAmB,CAAC,UAAsB;QACxC,MAAM,MAAM,GAAmB,IAAI,GAAG,EAAE,CAAC;QAEzC,MAAM,UAAU,GAAG,UAAU,CAAC,qBAAqB,EAAE,CAAC;QACtD,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;YAC9B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;gBAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;gBAClC,MAAM,IAAI,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;gBACnC,IAAI,CAAC,IAAI;oBAAE,SAAS;gBAEpB,MAAM,QAAQ,GAAG,IAAI,CAAC,0BAA0B,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;gBAEnE,IAAI,QAAQ,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;oBACtB,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;gBACnC,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACK,0BAA0B,CAAC,IAAU,EAAE,UAAkB;QAC/D,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA2B,CAAC;QAEpD,+CAA+C;QAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,oBAAoB,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;QAElE,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;YAC9B,IAAI,CAAC,IAAI;gBAAE,SAAS;YAEpB,wBAAwB;YACxB,MAAM,UAAU,GAAG,IAAI,CAAC,wBAAwB,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;YAC7E,IAAI,CAAC,UAAU;gBAAE,SAAS;YAE1B,MAAM,UAAU,GAAG,UAAU,CAAC,aAAa,EAAE,CAAC;YAC9C,IAAI,CAAC,UAAU;gBAAE,SAAS;YAE1B,MAAM,IAAI,GAAG,IAAI,CAAC,wBAAwB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;YACnE,IAAI,IAAI,EAAE,CAAC;gBACT,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;OAEG;IACK,wBAAwB,CAAC,IAAU,EAAE,UAAkB;QAC7D,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,IAAI,UAAU,GAAG,KAAK,CAAC;QACvB,IAAI,SAAS,GAAkB,IAAI,CAAC;QAEpC,+DAA+D;QAC/D,IAAI,WAAW,GAAG,IAAI,CAAC;QACvB,OAAO,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC,EAAE,CAAC;YAC1C,MAAM,QAAQ,GAAG,WAA6B,CAAC;YAC/C,MAAM,QAAQ,GAAG,QAAQ,CAAC,aAAa,EAAE,CAAC;YAE1C,IAAI,IAAI,CAAC,0BAA0B,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC9C,MAAM,UAAU,GAAG,QAAoC,CAAC;gBACxD,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,EAAE,CAAC;gBACxC,MAAM,QAAQ,GAAG,UAAU,CAAC,aAAa,EAAE,CAAC;gBAE5C,mDAAmD;gBACnD,IAAI,UAAU,KAAK,UAAU,IAAI,UAAU,KAAK,UAAU,EAAE,CAAC;oBAC3D,UAAU,GAAG,IAAI,CAAC;oBAClB,WAAW,GAAG,QAAQ,CAAC;oBACvB,SAAS;gBACX,CAAC;gBAED,uCAAuC;gBACvC,IAAI,UAAU,KAAK,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAC1D,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;oBACpC,IAAI,QAAQ,KAAK,GAAG,EAAE,CAAC;wBACrB,OAAO,GAAG,IAAI,CAAC;wBACf,SAAS,GAAG,QAAQ,CAAC;wBACrB,MAAM;oBACR,CAAC;gBACH,CAAC;gBAED,6DAA6D;gBAC7D,IAAI,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,OAAO,EAAE,KAAK,GAAG,EAAE,CAAC;oBAC9D,MAAM,IAAI,GAAG,QAAQ,CAAC,YAAY,EAAE,CAAC;oBAErC,IAAI,UAAU,KAAK,OAAO,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBAC9C,OAAO,GAAG,IAAI,CAAC;wBACf,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;wBAC3C,MAAM;oBACR,CAAC;oBAED,IAAI,UAAU,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;wBAChD,QAAQ,GAAG,IAAI,CAAC;wBAChB,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;wBAC3C,MAAM;oBACR,CAAC;gBACH,CAAC;YACH,CAAC;YAED,MAAM;QACR,CAAC;QAED,uEAAuE;QACvE,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,EAAE,CAAC;YACjD,SAAS,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC;QACpC,CAAC;QAED,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO;YACL,SAAS;YACT,OAAO;YACP,QAAQ;YACR,UAAU;YACV,SAAS,EAAE,SAAS,KAAK,UAAU;SACpC,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,gBAAgB,CAAC,IAAU;QACjC,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5B,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;QACxB,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;;;OAQG;IACH,eAAe,CACb,OAAe,EACf,YAA0C,EAC1C,QAAgB;QAEhB,IAAI,MAAM,GAAG,OAAO,CAAC;QAErB,KAAK,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,YAAY,EAAE,CAAC;YAC7C,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;gBACpB,SAAS;YACX,CAAC;YAED,0EAA0E;YAC1E,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClB,MAAM,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;YAC9D,CAAC;YAED,+CAA+C;YAC/C,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3E,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACK,gBAAgB,CAAC,OAAe,EAAE,SAAiB,EAAE,QAAgB;QAC3E,2EAA2E;QAC3E,MAAM,aAAa,GAAG,CAAC,GAAG,SAAS,KAAK,EAAE,GAAG,SAAS,MAAM,CAAC,CAAC;QAC9D,MAAM,eAAe,GAAG,cAAc,CAAC;QAEvC,KAAK,MAAM,OAAO,IAAI,aAAa,EAAE,CAAC;YACpC,IAAI,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACnC,OAAO,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;gBAClB,mCAAmC;gBACnC,MAAM,UAAU,GAAG,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC;gBACxC,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;gBAEnE,IAAI,aAAa,KAAK,CAAC,CAAC,IAAI,aAAa,GAAG,UAAU,GAAG,EAAE,EAAE,CAAC;oBAC5D,MAAM,QAAQ,GAAG,aAAa,GAAG,eAAe,CAAC,MAAM,CAAC;oBACxD,2DAA2D;oBAC3D,IAAI,OAAO,GAAG,QAAQ,CAAC;oBACvB,OAAO,OAAO,GAAG,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;wBAC/D,OAAO,EAAE,CAAC;oBACZ,CAAC;oBAED,IAAI,OAAO,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,CAAC,CAAC,KAAK,KAAK,EAAE,CAAC;wBACtD,MAAM,QAAQ,GAAG,OAAO,CAAC;wBACzB,MAAM,MAAM,GAAG,QAAQ,GAAG,CAAC,CAAC;wBAC5B,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;oBAClF,CAAC;gBACH,CAAC;gBAED,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACK,eAAe,CACrB,OAAe,EACf,SAAiB,EACjB,QAAgB,EAChB,OAAgB;QAEhB,sDAAsD;QACtD,MAAM,aAAa,GAAG,CAAC,GAAG,SAAS,IAAI,EAAE,GAAG,SAAS,KAAK,CAAC,CAAC;QAE5D,KAAK,MAAM,OAAO,IAAI,aAAa,EAAE,CAAC;YACpC,IAAI,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACnC,OAAO,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;gBAClB,MAAM,UAAU,GAAG,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC;gBACxC,MAAM,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;gBAEjD,yCAAyC;gBACzC,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC;gBAChB,IAAI,SAAS,GAAG,CAAC,CAAC;gBAElB,IAAI,UAAU,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;oBACvC,SAAS,GAAG,WAAW,CAAC,MAAM,CAAC;oBAC/B,IAAI,UAAU,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;wBACtD,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;oBAClC,CAAC;gBACH,CAAC;qBAAM,IAAI,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;oBACxC,MAAM,GAAG,UAAU,CAAC;gBACtB,CAAC;gBAED,IAAI,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;oBAClB,+BAA+B;oBAC/B,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;oBAC/C,MAAM,gBAAgB,GAAG,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;oBAEnD,oBAAoB;oBACpB,IAAI,WAAW,GAAG,QAAQ,CAAC;oBAC3B,IAAI,OAAO,IAAI,gBAAgB,EAAE,CAAC;wBAChC,WAAW,GAAG,GAAG,QAAQ,IAAI,CAAC;oBAChC,CAAC;oBAED,iDAAiD;oBACjD,IAAI,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC;oBACxB,IAAI,gBAAgB,EAAE,CAAC;wBACrB,MAAM,IAAI,CAAC,CAAC;oBACd,CAAC;oBAED,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;gBACnF,CAAC;gBAED,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACH,iBAAiB,CAAC,YAA0C;QAC1D,OAAO,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC1E,CAAC;CACF"}
@@ -0,0 +1,51 @@
1
+ import { SourceFile, Project } from "ts-morph";
2
+ /**
3
+ * Information about an imported schema.
4
+ */
5
+ export interface ImportedSchemaInfo {
6
+ /** Local name used in the importing file */
7
+ localName: string;
8
+ /** Original name in the source file */
9
+ originalName: string;
10
+ /** Resolved source file path */
11
+ sourceFilePath: string;
12
+ /** Whether the schema was successfully resolved */
13
+ resolved: boolean;
14
+ }
15
+ /**
16
+ * Map of local schema name to imported schema info.
17
+ */
18
+ export type ImportedSchemaMap = Map<string, ImportedSchemaInfo>;
19
+ /**
20
+ * Resolves imported schemas from other files.
21
+ */
22
+ export declare class ImportResolver {
23
+ private schemaDetector;
24
+ constructor();
25
+ /**
26
+ * Finds all imported schemas in a source file.
27
+ *
28
+ * @param sourceFile - The source file to analyze
29
+ * @param project - The ts-morph project for module resolution
30
+ * @returns Map of local names to imported schema info
31
+ */
32
+ findImportedSchemas(sourceFile: SourceFile, project: Project): ImportedSchemaMap;
33
+ /**
34
+ * Finds the actual source file containing a schema definition.
35
+ * Follows re-exports (export * from "./other") to find the original.
36
+ */
37
+ private findSchemaSource;
38
+ /**
39
+ * Resolves a module specifier to a source file.
40
+ */
41
+ private resolveModuleSpecifier;
42
+ /**
43
+ * Generates possible file paths for a module specifier and resolves to a source file.
44
+ */
45
+ private resolveFromPossiblePaths;
46
+ /**
47
+ * Resolves an import declaration to its source file.
48
+ */
49
+ private resolveImportedFile;
50
+ }
51
+ //# sourceMappingURL=import-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import-resolver.d.ts","sourceRoot":"","sources":["../../src/core/import-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAqB,OAAO,EAAE,MAAM,UAAU,CAAC;AAKlE;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,gCAAgC;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,mDAAmD;IACnD,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;AAEhE;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,cAAc,CAAiB;;IAMvC;;;;;;OAMG;IACH,mBAAmB,CAAC,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,iBAAiB;IA2ChF;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IA4DxB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAS9B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IA8BhC;;OAEG;IACH,OAAO,CAAC,mBAAmB;CAwB5B"}
@@ -0,0 +1,158 @@
1
+ import { join } from "pathe";
2
+ import { SchemaDetector } from "./schema-detector.js";
3
+ import { logDebugError } from "./logger.js";
4
+ /**
5
+ * Resolves imported schemas from other files.
6
+ */
7
+ export class ImportResolver {
8
+ schemaDetector;
9
+ constructor() {
10
+ this.schemaDetector = new SchemaDetector();
11
+ }
12
+ /**
13
+ * Finds all imported schemas in a source file.
14
+ *
15
+ * @param sourceFile - The source file to analyze
16
+ * @param project - The ts-morph project for module resolution
17
+ * @returns Map of local names to imported schema info
18
+ */
19
+ findImportedSchemas(sourceFile, project) {
20
+ const result = new Map();
21
+ const imports = sourceFile.getImportDeclarations();
22
+ for (const importDecl of imports) {
23
+ const moduleSpecifier = importDecl.getModuleSpecifierValue();
24
+ // Skip node_modules imports
25
+ if (!moduleSpecifier.startsWith(".") && !moduleSpecifier.startsWith("/")) {
26
+ continue;
27
+ }
28
+ // Resolve the module to a source file
29
+ const resolvedSourceFile = this.resolveImportedFile(importDecl, sourceFile, project);
30
+ if (!resolvedSourceFile) {
31
+ continue;
32
+ }
33
+ // Check named imports
34
+ const namedImports = importDecl.getNamedImports();
35
+ for (const namedImport of namedImports) {
36
+ const importedName = namedImport.getName();
37
+ const localName = namedImport.getAliasNode()?.getText() || importedName;
38
+ // Find the actual source file containing the schema definition
39
+ // This handles re-exports from index.ts files
40
+ const actualSource = this.findSchemaSource(resolvedSourceFile, importedName, project);
41
+ if (actualSource) {
42
+ result.set(localName, {
43
+ localName,
44
+ originalName: actualSource.schemaName,
45
+ sourceFilePath: actualSource.sourceFile.getFilePath(),
46
+ resolved: true,
47
+ });
48
+ }
49
+ }
50
+ }
51
+ return result;
52
+ }
53
+ /**
54
+ * Finds the actual source file containing a schema definition.
55
+ * Follows re-exports (export * from "./other") to find the original.
56
+ */
57
+ findSchemaSource(sourceFile, schemaName, project, visited = new Set()) {
58
+ const filePath = sourceFile.getFilePath();
59
+ // Prevent infinite loops
60
+ if (visited.has(filePath)) {
61
+ return undefined;
62
+ }
63
+ visited.add(filePath);
64
+ // Check if the schema is defined directly in this file
65
+ const schemas = this.schemaDetector.detectExportedSchemas(sourceFile);
66
+ if (schemas.some((s) => s.name === schemaName)) {
67
+ return { sourceFile, schemaName };
68
+ }
69
+ // Check export declarations for re-exports
70
+ const exportDecls = sourceFile.getExportDeclarations();
71
+ for (const exportDecl of exportDecls) {
72
+ const moduleSpecifier = exportDecl.getModuleSpecifierValue();
73
+ if (!moduleSpecifier)
74
+ continue;
75
+ // Check if this is "export * from" or "export { name } from"
76
+ const namedExports = exportDecl.getNamedExports();
77
+ if (namedExports.length === 0) {
78
+ // This is "export * from './module'" - follow it
79
+ const reExportedFile = this.resolveModuleSpecifier(sourceFile, moduleSpecifier, project);
80
+ if (reExportedFile) {
81
+ const found = this.findSchemaSource(reExportedFile, schemaName, project, visited);
82
+ if (found) {
83
+ return found;
84
+ }
85
+ }
86
+ }
87
+ else {
88
+ // Check named exports
89
+ for (const namedExport of namedExports) {
90
+ const exportedName = namedExport.getAliasNode()?.getText() || namedExport.getName();
91
+ if (exportedName === schemaName) {
92
+ const originalName = namedExport.getName();
93
+ const reExportedFile = this.resolveModuleSpecifier(sourceFile, moduleSpecifier, project);
94
+ if (reExportedFile) {
95
+ return this.findSchemaSource(reExportedFile, originalName, project, visited);
96
+ }
97
+ }
98
+ }
99
+ }
100
+ }
101
+ return undefined;
102
+ }
103
+ /**
104
+ * Resolves a module specifier to a source file.
105
+ */
106
+ resolveModuleSpecifier(fromFile, moduleSpecifier, project) {
107
+ const sourceDir = fromFile.getDirectoryPath();
108
+ return this.resolveFromPossiblePaths(sourceDir, moduleSpecifier, project);
109
+ }
110
+ /**
111
+ * Generates possible file paths for a module specifier and resolves to a source file.
112
+ */
113
+ resolveFromPossiblePaths(sourceDir, moduleSpecifier, project) {
114
+ const possiblePaths = [
115
+ join(sourceDir, `${moduleSpecifier}.ts`),
116
+ join(sourceDir, moduleSpecifier, "index.ts"),
117
+ join(sourceDir, `${moduleSpecifier}.js`),
118
+ join(sourceDir, moduleSpecifier, "index.js"),
119
+ ];
120
+ for (const possiblePath of possiblePaths) {
121
+ let resolved = project.getSourceFile(possiblePath);
122
+ if (!resolved) {
123
+ try {
124
+ resolved = project.addSourceFileAtPathIfExists(possiblePath);
125
+ }
126
+ catch (error) {
127
+ logDebugError(`Failed to add source file at ${possiblePath}`, error);
128
+ continue;
129
+ }
130
+ }
131
+ if (resolved) {
132
+ return resolved;
133
+ }
134
+ }
135
+ return undefined;
136
+ }
137
+ /**
138
+ * Resolves an import declaration to its source file.
139
+ */
140
+ resolveImportedFile(importDecl, sourceFile, project) {
141
+ const moduleSpecifier = importDecl.getModuleSpecifierValue();
142
+ try {
143
+ // Get the module specifier source file
144
+ const moduleSourceFile = importDecl.getModuleSpecifierSourceFile();
145
+ if (moduleSourceFile) {
146
+ return moduleSourceFile;
147
+ }
148
+ // Try to resolve manually for index.ts patterns
149
+ const sourceDir = sourceFile.getDirectoryPath();
150
+ return this.resolveFromPossiblePaths(sourceDir, moduleSpecifier, project);
151
+ }
152
+ catch (error) {
153
+ logDebugError(`Module resolution failed for ${moduleSpecifier}`, error);
154
+ }
155
+ return undefined;
156
+ }
157
+ }
158
+ //# sourceMappingURL=import-resolver.js.map