@davars/graphql-codegen-zod 0.1.0

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.
@@ -0,0 +1,211 @@
1
+ import { Kind, valueFromASTUntyped } from 'graphql';
2
+ import { isConvertableRegexp } from './regexp.js';
3
+ function isFormattedDirectiveObjectArguments(arg) {
4
+ return arg !== undefined && !Array.isArray(arg);
5
+ }
6
+ // ```yml
7
+ // directives:
8
+ // required:
9
+ // msg: required
10
+ // constraint:
11
+ // minLength: min
12
+ // format:
13
+ // uri: url
14
+ // email: email
15
+ // ```
16
+ //
17
+ // This function convterts to like below
18
+ // {
19
+ // 'required': {
20
+ // 'msg': ['required', '$1'],
21
+ // },
22
+ // 'constraint': {
23
+ // 'minLength': ['min', '$1'],
24
+ // 'format': {
25
+ // 'uri': ['url', '$2'],
26
+ // 'email': ['email', '$2'],
27
+ // }
28
+ // }
29
+ // }
30
+ export function formatDirectiveConfig(config) {
31
+ return Object.fromEntries(Object.entries(config).map(([directive, arg]) => {
32
+ const formatted = Object.fromEntries(Object.entries(arg).map(([arg, val]) => {
33
+ if (Array.isArray(val))
34
+ return [arg, val];
35
+ if (typeof val === 'string')
36
+ return [arg, [val, '$1']];
37
+ return [arg, formatDirectiveObjectArguments(val)];
38
+ }));
39
+ return [directive, formatted];
40
+ }));
41
+ }
42
+ // ```yml
43
+ // format:
44
+ // # For example, `@constraint(format: "uri")`. this case $1 will be "uri".
45
+ // # Therefore the generator generates yup schema `.url()` followed by `uri: 'url'`
46
+ // # If $1 does not match anywhere, the generator will ignore.
47
+ // uri: url
48
+ // email: ["email", "$2"]
49
+ // ```
50
+ //
51
+ // This function convterts to like below
52
+ // {
53
+ // 'uri': ['url', '$2'],
54
+ // 'email': ['email'],
55
+ // }
56
+ export function formatDirectiveObjectArguments(args) {
57
+ const formatted = Object.entries(args).map(([arg, val]) => {
58
+ if (Array.isArray(val))
59
+ return [arg, val];
60
+ return [arg, [val, '$2']];
61
+ });
62
+ return Object.fromEntries(formatted);
63
+ }
64
+ // This function generates `.required("message").min(100).email()`
65
+ //
66
+ // config
67
+ // {
68
+ // 'required': {
69
+ // 'msg': ['required', '$1'],
70
+ // },
71
+ // 'constraint': {
72
+ // 'minLength': ['min', '$1'],
73
+ // 'format': {
74
+ // 'uri': ['url', '$2'],
75
+ // 'email': ['email', '$2'],
76
+ // }
77
+ // }
78
+ // }
79
+ //
80
+ // GraphQL schema
81
+ // ```graphql
82
+ // input ExampleInput {
83
+ // email: String! @required(msg: "message") @constraint(minLength: 100, format: "email")
84
+ // }
85
+ // ```
86
+ export function buildApi(config, directives) {
87
+ return directives
88
+ .filter(directive => config[directive.name.value] !== undefined)
89
+ .map((directive) => {
90
+ const directiveName = directive.name.value;
91
+ const argsConfig = config[directiveName];
92
+ return buildApiFromDirectiveArguments(argsConfig, directive.arguments ?? []);
93
+ })
94
+ .join('');
95
+ }
96
+ // This function generates `[v.minLength(100), v.email()]`
97
+ // NOTE: valibot's API is not a method chain, so it is prepared separately from buildApi.
98
+ //
99
+ // config
100
+ // {
101
+ // 'constraint': {
102
+ // 'minLength': ['minLength', '$1'],
103
+ // 'format': {
104
+ // 'uri': ['url', '$2'],
105
+ // 'email': ['email', '$2'],
106
+ // }
107
+ // }
108
+ // }
109
+ //
110
+ // GraphQL schema
111
+ // ```graphql
112
+ // input ExampleInput {
113
+ // email: String! @required(msg: "message") @constraint(minLength: 100, format: "email")
114
+ // }
115
+ // ```
116
+ //
117
+ // FIXME: v.required() is not supported yet. v.required() is classified as `Methods` and must wrap the schema. ex) `v.required(v.object({...}))`
118
+ export function buildApiForValibot(config, directives) {
119
+ return directives
120
+ .filter(directive => config[directive.name.value] !== undefined)
121
+ .map((directive) => {
122
+ const directiveName = directive.name.value;
123
+ const argsConfig = config[directiveName];
124
+ const apis = _buildApiFromDirectiveArguments(argsConfig, directive.arguments ?? []);
125
+ return apis.map(api => `v${api}`);
126
+ })
127
+ .flat();
128
+ }
129
+ function buildApiSchema(validationSchema, argValue) {
130
+ if (!validationSchema)
131
+ return '';
132
+ const schemaApi = validationSchema[0];
133
+ const schemaApiArgs = validationSchema.slice(1).map((templateArg) => {
134
+ const gqlSchemaArgs = apiArgsFromConstValueNode(argValue);
135
+ return applyArgToApiSchemaTemplate(templateArg, gqlSchemaArgs);
136
+ });
137
+ return `.${schemaApi}(${schemaApiArgs.join(', ')})`;
138
+ }
139
+ function buildApiFromDirectiveArguments(config, args) {
140
+ return _buildApiFromDirectiveArguments(config, args).join('');
141
+ }
142
+ function _buildApiFromDirectiveArguments(config, args) {
143
+ return args
144
+ .map((arg) => {
145
+ const argName = arg.name.value;
146
+ const validationSchema = config[argName];
147
+ if (isFormattedDirectiveObjectArguments(validationSchema))
148
+ return buildApiFromDirectiveObjectArguments(validationSchema, arg.value);
149
+ return buildApiSchema(validationSchema, arg.value);
150
+ });
151
+ }
152
+ function buildApiFromDirectiveObjectArguments(config, argValue) {
153
+ if (argValue.kind !== Kind.STRING && argValue.kind !== Kind.ENUM)
154
+ return '';
155
+ const validationSchema = config[argValue.value];
156
+ return buildApiSchema(validationSchema, argValue);
157
+ }
158
+ function applyArgToApiSchemaTemplate(template, apiArgs) {
159
+ const matches = template.matchAll(/\$(\d+)/g);
160
+ for (const match of matches) {
161
+ const placeholder = match[0]; // `$1`
162
+ const idx = Number.parseInt(match[1], 10) - 1; // start with `1 - 1`
163
+ const apiArg = apiArgs[idx];
164
+ if (apiArg === undefined) {
165
+ template = template.replace(placeholder, '');
166
+ continue;
167
+ }
168
+ if (template === placeholder)
169
+ return stringify(apiArg);
170
+ template = template.replace(placeholder, apiArg);
171
+ }
172
+ if (template !== '')
173
+ return stringify(template, true);
174
+ return template;
175
+ }
176
+ function stringify(arg, quoteString) {
177
+ if (Array.isArray(arg))
178
+ return arg.map(v => stringify(v, true)).join(',');
179
+ if (typeof arg === 'string') {
180
+ if (isConvertableRegexp(arg))
181
+ return arg;
182
+ const v = tryEval(arg);
183
+ if (v !== undefined)
184
+ arg = v;
185
+ if (quoteString)
186
+ return JSON.stringify(arg);
187
+ }
188
+ if (typeof arg === 'boolean' || typeof arg === 'number' || typeof arg === 'bigint' || arg === 'undefined' || arg === null)
189
+ return `${arg}`;
190
+ return JSON.stringify(arg);
191
+ }
192
+ function apiArgsFromConstValueNode(value) {
193
+ const val = valueFromASTUntyped(value);
194
+ if (Array.isArray(val))
195
+ return val;
196
+ return [val];
197
+ }
198
+ function tryEval(maybeValidJavaScript) {
199
+ try {
200
+ // eslint-disable-next-line no-eval
201
+ return eval(maybeValidJavaScript);
202
+ }
203
+ catch {
204
+ return undefined;
205
+ }
206
+ }
207
+ export const exportedForTesting = {
208
+ applyArgToApiSchemaTemplate,
209
+ buildApiFromDirectiveObjectArguments,
210
+ buildApiFromDirectiveArguments,
211
+ };
@@ -0,0 +1,21 @@
1
+ import type { DocumentNode, GraphQLSchema, InterfaceTypeDefinitionNode, ListTypeNode, NamedTypeNode, NonNullTypeNode, ObjectTypeDefinitionNode, TypeNode } from 'graphql';
2
+ import { Graph } from 'graphlib';
3
+ export declare const isListType: (typ?: TypeNode) => typ is ListTypeNode;
4
+ export declare const isNonNullType: (typ?: TypeNode) => typ is NonNullTypeNode;
5
+ export declare const isNamedType: (typ?: TypeNode) => typ is NamedTypeNode;
6
+ export declare const isInput: (kind: string) => boolean;
7
+ type ObjectTypeDefinitionFn = (node: ObjectTypeDefinitionNode) => any;
8
+ type InterfaceTypeDefinitionFn = (node: InterfaceTypeDefinitionNode) => any;
9
+ export declare function ObjectTypeDefinitionBuilder(useObjectTypes: boolean | undefined, callback: ObjectTypeDefinitionFn): ObjectTypeDefinitionFn | undefined;
10
+ export declare function InterfaceTypeDefinitionBuilder(useInterfaceTypes: boolean | undefined, callback: InterfaceTypeDefinitionFn): InterfaceTypeDefinitionFn | undefined;
11
+ export declare function topologicalSortAST(schema: GraphQLSchema, ast: DocumentNode): DocumentNode;
12
+ /**
13
+ * [Re-implemented topsort function][topsort-ref] with cycle handling. This version iterates over
14
+ * all nodes in the graph to ensure every node is visited, even if the graph contains cycles.
15
+ *
16
+ * [topsort-ref]: https://github.com/dagrejs/graphlib/blob/8d27cb89029081c72eb89dde652602805bdd0a34/lib/alg/topsort.js
17
+ */
18
+ export declare function topsort(g: Graph): string[];
19
+ export declare function isGeneratedByIntrospection(schema: GraphQLSchema): boolean;
20
+ export declare function escapeGraphQLCharacters(input: string): string;
21
+ export {};
@@ -0,0 +1,167 @@
1
+ import { Graph } from 'graphlib';
2
+ import { isSpecifiedScalarType, Kind, visit, } from 'graphql';
3
+ /**
4
+ * Recursively unwraps a GraphQL type until it reaches the NamedType.
5
+ *
6
+ * Since a GraphQL type is defined as either a NamedTypeNode, ListTypeNode, or NonNullTypeNode,
7
+ * this implementation safely recurses until the underlying NamedTypeNode is reached.
8
+ */
9
+ function getNamedType(typeNode) {
10
+ return typeNode.kind === Kind.NAMED_TYPE ? typeNode : getNamedType(typeNode.type);
11
+ }
12
+ export const isListType = (typ) => typ?.kind === Kind.LIST_TYPE;
13
+ export const isNonNullType = (typ) => typ?.kind === Kind.NON_NULL_TYPE;
14
+ export const isNamedType = (typ) => typ?.kind === Kind.NAMED_TYPE;
15
+ export const isInput = (kind) => kind.includes('Input');
16
+ export function ObjectTypeDefinitionBuilder(useObjectTypes, callback) {
17
+ if (!useObjectTypes)
18
+ return undefined;
19
+ return (node) => {
20
+ if (/^(Query|Mutation|Subscription)$/.test(node.name.value))
21
+ return;
22
+ return callback(node);
23
+ };
24
+ }
25
+ export function InterfaceTypeDefinitionBuilder(useInterfaceTypes, callback) {
26
+ if (!useInterfaceTypes)
27
+ return undefined;
28
+ return (node) => {
29
+ return callback(node);
30
+ };
31
+ }
32
+ export function topologicalSortAST(schema, ast) {
33
+ const dependencyGraph = new Graph();
34
+ const targetKinds = [
35
+ Kind.OBJECT_TYPE_DEFINITION,
36
+ Kind.INPUT_OBJECT_TYPE_DEFINITION,
37
+ Kind.INTERFACE_TYPE_DEFINITION,
38
+ Kind.SCALAR_TYPE_DEFINITION,
39
+ Kind.ENUM_TYPE_DEFINITION,
40
+ Kind.UNION_TYPE_DEFINITION,
41
+ ];
42
+ visit(ast, {
43
+ enter: (node) => {
44
+ switch (node.kind) {
45
+ case Kind.OBJECT_TYPE_DEFINITION:
46
+ case Kind.INPUT_OBJECT_TYPE_DEFINITION:
47
+ case Kind.INTERFACE_TYPE_DEFINITION: {
48
+ const typeName = node.name.value;
49
+ dependencyGraph.setNode(typeName);
50
+ if (node.fields) {
51
+ node.fields.forEach((field) => {
52
+ // Unwrap the type
53
+ const namedTypeNode = getNamedType(field.type);
54
+ const dependency = namedTypeNode.name.value;
55
+ const namedType = schema.getType(dependency);
56
+ if (namedType?.astNode?.kind === undefined
57
+ || !targetKinds.includes(namedType.astNode.kind)) {
58
+ return;
59
+ }
60
+ if (!dependencyGraph.hasNode(dependency)) {
61
+ dependencyGraph.setNode(dependency);
62
+ }
63
+ dependencyGraph.setEdge(typeName, dependency);
64
+ });
65
+ }
66
+ break;
67
+ }
68
+ case Kind.SCALAR_TYPE_DEFINITION:
69
+ case Kind.ENUM_TYPE_DEFINITION: {
70
+ dependencyGraph.setNode(node.name.value);
71
+ break;
72
+ }
73
+ case Kind.UNION_TYPE_DEFINITION: {
74
+ const dependency = node.name.value;
75
+ if (!dependencyGraph.hasNode(dependency))
76
+ dependencyGraph.setNode(dependency);
77
+ node.types?.forEach((type) => {
78
+ const dependency = type.name.value;
79
+ const typ = schema.getType(dependency);
80
+ if (typ?.astNode?.kind === undefined || !targetKinds.includes(typ.astNode.kind))
81
+ return;
82
+ dependencyGraph.setEdge(node.name.value, dependency);
83
+ });
84
+ break;
85
+ }
86
+ default:
87
+ break;
88
+ }
89
+ },
90
+ });
91
+ const sorted = topsort(dependencyGraph);
92
+ // Create a map of definitions for quick access, using the definition's name as the key.
93
+ const definitionsMap = new Map();
94
+ // SCHEMA_DEFINITION does not have a name.
95
+ // https://spec.graphql.org/October2021/#sec-Schema
96
+ const astDefinitions = ast.definitions.filter(def => def.kind !== Kind.SCHEMA_DEFINITION);
97
+ astDefinitions.forEach((definition) => {
98
+ if (hasNameField(definition) && definition.name)
99
+ definitionsMap.set(definition.name.value, definition);
100
+ });
101
+ // Two arrays to store sorted and unsorted definitions.
102
+ const sortedDefinitions = [];
103
+ const notSortedDefinitions = [];
104
+ // Iterate over sorted type names and retrieve their corresponding definitions.
105
+ sorted.forEach((sortedType) => {
106
+ const definition = definitionsMap.get(sortedType);
107
+ if (definition) {
108
+ sortedDefinitions.push(definition);
109
+ definitionsMap.delete(sortedType);
110
+ }
111
+ });
112
+ // Definitions that are left in the map were not included in sorted list
113
+ // Add them to notSortedDefinitions.
114
+ definitionsMap.forEach(definition => notSortedDefinitions.push(definition));
115
+ const newDefinitions = [...sortedDefinitions, ...notSortedDefinitions];
116
+ if (newDefinitions.length !== astDefinitions.length) {
117
+ throw new Error(`Unexpected definition length after sorting: want ${astDefinitions.length} but got ${newDefinitions.length}`);
118
+ }
119
+ return {
120
+ ...ast,
121
+ definitions: newDefinitions,
122
+ };
123
+ }
124
+ function hasNameField(node) {
125
+ return 'name' in node;
126
+ }
127
+ /**
128
+ * [Re-implemented topsort function][topsort-ref] with cycle handling. This version iterates over
129
+ * all nodes in the graph to ensure every node is visited, even if the graph contains cycles.
130
+ *
131
+ * [topsort-ref]: https://github.com/dagrejs/graphlib/blob/8d27cb89029081c72eb89dde652602805bdd0a34/lib/alg/topsort.js
132
+ */
133
+ export function topsort(g) {
134
+ const visited = new Set();
135
+ const results = [];
136
+ function visit(node) {
137
+ if (visited.has(node))
138
+ return;
139
+ visited.add(node);
140
+ // Recursively visit all predecessors of the node.
141
+ g.predecessors(node)?.forEach(visit);
142
+ results.push(node);
143
+ }
144
+ // Visit every node in the graph (instead of only sinks)
145
+ g.nodes().forEach(visit);
146
+ return results.reverse();
147
+ }
148
+ export function isGeneratedByIntrospection(schema) {
149
+ return Object.entries(schema.getTypeMap())
150
+ .filter(([name, type]) => !name.startsWith('__') && !isSpecifiedScalarType(type))
151
+ .every(([, type]) => type.astNode === undefined);
152
+ }
153
+ // https://spec.graphql.org/October2021/#EscapedCharacter
154
+ const escapeMap = {
155
+ '\"': '\\\"',
156
+ '\\': '\\\\',
157
+ '\/': '\\/',
158
+ '\b': '\\b',
159
+ '\f': '\\f',
160
+ '\n': '\\n',
161
+ '\r': '\\r',
162
+ '\t': '\\t',
163
+ };
164
+ export function escapeGraphQLCharacters(input) {
165
+ // eslint-disable-next-line regexp/no-escape-backspace
166
+ return input.replace(/["\\/\f\n\r\t\b]/g, match => escapeMap[match]);
167
+ }
@@ -0,0 +1,4 @@
1
+ import type { PluginFunction, Types } from '@graphql-codegen/plugin-helpers';
2
+ import type { ValidationSchemaPluginConfig } from './config.js';
3
+ export declare const plugin: PluginFunction<ValidationSchemaPluginConfig, Types.ComplexPluginOutput>;
4
+ export type { ValidationSchemaPluginConfig };
package/dist/index.js ADDED
@@ -0,0 +1,37 @@
1
+ import { transformSchemaAST } from '@graphql-codegen/schema-ast';
2
+ import { buildSchema, printSchema, visit } from 'graphql';
3
+ import { isGeneratedByIntrospection, topologicalSortAST } from './graphql.js';
4
+ import { loadTransforms } from './transforms.js';
5
+ import { ZodSchemaVisitor } from './zod.js';
6
+ export const plugin = (schema, _documents, config, info) => {
7
+ const { schema: _schema, ast } = _transformSchemaAST(schema, config);
8
+ let resolvedTransforms = {};
9
+ if (config.transforms) {
10
+ const outputFile = info?.outputFile ?? 'output.ts';
11
+ resolvedTransforms = loadTransforms(config.transforms, outputFile);
12
+ }
13
+ const visitor = new ZodSchemaVisitor(_schema, config, resolvedTransforms);
14
+ const result = visit(ast, visitor);
15
+ const generated = result.definitions.filter(def => typeof def === 'string');
16
+ return {
17
+ prepend: visitor.buildImports(),
18
+ content: [visitor.initialEmit(), ...generated].join('\n'),
19
+ };
20
+ };
21
+ function _transformSchemaAST(schema, config) {
22
+ const { schema: _schema, ast } = transformSchemaAST(schema, config);
23
+ // See: https://github.com/Code-Hex/graphql-codegen-typescript-validation-schema/issues/394
24
+ const __schema = isGeneratedByIntrospection(_schema) ? buildSchema(printSchema(_schema)) : _schema;
25
+ // This affects the performance of code generation, so it is
26
+ // enabled only when this option is selected.
27
+ if (config.validationSchemaExportType === 'const') {
28
+ return {
29
+ schema: __schema,
30
+ ast: topologicalSortAST(__schema, ast),
31
+ };
32
+ }
33
+ return {
34
+ schema: __schema,
35
+ ast,
36
+ };
37
+ }
@@ -0,0 +1 @@
1
+ export declare const isConvertableRegexp: (maybeRegexp: string) => boolean;
package/dist/regexp.js ADDED
@@ -0,0 +1,2 @@
1
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#advanced_searching_with_flags
2
+ export const isConvertableRegexp = (maybeRegexp) => /^\/.*\/[dgimsuy]*$/.test(maybeRegexp);
@@ -0,0 +1,17 @@
1
+ import type { FieldDefinitionNode, GraphQLSchema, InputValueDefinitionNode, InterfaceTypeDefinitionNode, ObjectTypeDefinitionNode } from 'graphql';
2
+ import type { ValidationSchemaPluginConfig } from './config.js';
3
+ import type { SchemaVisitor } from './types.js';
4
+ import { Visitor } from './visitor.js';
5
+ export declare abstract class BaseSchemaVisitor implements SchemaVisitor {
6
+ protected schema: GraphQLSchema;
7
+ protected config: ValidationSchemaPluginConfig;
8
+ protected importTypes: string[];
9
+ protected enumDeclarations: string[];
10
+ constructor(schema: GraphQLSchema, config: ValidationSchemaPluginConfig);
11
+ abstract importValidationSchema(): string;
12
+ buildImports(): string[];
13
+ abstract initialEmit(): string;
14
+ createVisitor(scalarDirection: 'input' | 'output' | 'both'): Visitor;
15
+ protected abstract buildInputFields(fields: readonly (FieldDefinitionNode | InputValueDefinitionNode)[], visitor: Visitor, name: string): string;
16
+ protected buildTypeDefinitionArguments(node: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, visitor: Visitor): string | undefined;
17
+ }
@@ -0,0 +1,33 @@
1
+ import { Visitor } from './visitor.js';
2
+ export class BaseSchemaVisitor {
3
+ schema;
4
+ config;
5
+ importTypes = [];
6
+ enumDeclarations = [];
7
+ constructor(schema, config) {
8
+ this.schema = schema;
9
+ this.config = config;
10
+ }
11
+ buildImports() {
12
+ if (this.config.importFrom && this.importTypes.length > 0) {
13
+ const namedImportPrefix = this.config.useTypeImports ? 'type ' : '';
14
+ const importCore = this.config.schemaNamespacedImportName
15
+ ? `* as ${this.config.schemaNamespacedImportName}`
16
+ : `${namedImportPrefix}{ ${this.importTypes.join(', ')} }`;
17
+ return [
18
+ this.importValidationSchema(),
19
+ `import ${importCore} from '${this.config.importFrom}'`,
20
+ ];
21
+ }
22
+ return [this.importValidationSchema()];
23
+ }
24
+ createVisitor(scalarDirection) {
25
+ return new Visitor(scalarDirection, this.schema, this.config);
26
+ }
27
+ buildTypeDefinitionArguments(node, visitor) {
28
+ return visitor.buildArgumentsSchemaBlock(node, (typeName, field) => {
29
+ this.importTypes.push(typeName);
30
+ return this.buildInputFields(field.arguments ?? [], visitor, typeName);
31
+ });
32
+ }
33
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * A transform function that converts a plain parsed object into a custom type.
3
+ * Used with Zod's `.transform()` to produce class instances from generated schemas.
4
+ */
5
+ export type TransformFn = (raw: any) => unknown;
6
+ /**
7
+ * Maps GraphQL type names to their transform functions.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import type { TransformConfig } from '@heath/codegen-plugin/transform_config'
12
+ * import { transformDateRange } from './models/DateRange'
13
+ *
14
+ * const config: TransformConfig = {
15
+ * DateRange: transformDateRange,
16
+ * }
17
+ * export default config
18
+ * ```
19
+ */
20
+ export type TransformConfig = Record<string, TransformFn>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,35 @@
1
+ import ts from 'typescript';
2
+ export interface ResolvedTransform {
3
+ /** The function name to import in generated code */
4
+ symbolName: string;
5
+ /** The module path to import from (relative to output file) */
6
+ importPath: string;
7
+ }
8
+ /**
9
+ * Loads and resolves transform configuration using pure static analysis.
10
+ *
11
+ * Parses the TypeScript config file's AST to extract:
12
+ * 1. Import declarations → symbol name to module path mapping
13
+ * 2. Default export object → GraphQL type name to symbol name mapping
14
+ * 3. Rebased import paths → adjusted for the output file location
15
+ */
16
+ export declare function loadTransforms(configPath: string, outputPath: string): Record<string, ResolvedTransform>;
17
+ /**
18
+ * Extracts a map of imported symbol names to their module paths.
19
+ * Skips `import type` declarations since we need value imports.
20
+ */
21
+ export declare function extractImportMap(sourceFile: ts.SourceFile): Map<string, string>;
22
+ /**
23
+ * Extracts the default export object literal, mapping property names to
24
+ * their identifier values (the imported symbol names).
25
+ *
26
+ * Supports these patterns:
27
+ * export default { TypeName: transformFn }
28
+ * const config = { TypeName: transformFn }; export default config;
29
+ */
30
+ export declare function extractDefaultExportMap(sourceFile: ts.SourceFile): Map<string, string>;
31
+ /**
32
+ * Adjusts a relative import path so it's correct relative to the output file
33
+ * rather than the config file. Non-relative paths (aliases, packages) pass through unchanged.
34
+ */
35
+ export declare function rebasePath(importPath: string, configPath: string, outputPath: string): string;