@constructive-io/graphql-codegen 2.19.0 → 2.20.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.
- package/README.md +1818 -113
- package/__tests__/codegen/input-types-generator.test.d.ts +1 -0
- package/__tests__/codegen/input-types-generator.test.js +635 -0
- package/cli/codegen/barrel.d.ts +27 -0
- package/cli/codegen/barrel.js +163 -0
- package/cli/codegen/client.d.ts +4 -0
- package/cli/codegen/client.js +170 -0
- package/cli/codegen/custom-mutations.d.ts +38 -0
- package/cli/codegen/custom-mutations.js +149 -0
- package/cli/codegen/custom-queries.d.ts +38 -0
- package/cli/codegen/custom-queries.js +358 -0
- package/cli/codegen/filters.d.ts +27 -0
- package/cli/codegen/filters.js +357 -0
- package/cli/codegen/gql-ast.d.ts +41 -0
- package/cli/codegen/gql-ast.js +329 -0
- package/cli/codegen/index.d.ts +71 -0
- package/cli/codegen/index.js +147 -0
- package/cli/codegen/mutations.d.ts +30 -0
- package/cli/codegen/mutations.js +410 -0
- package/cli/codegen/orm/barrel.d.ts +18 -0
- package/cli/codegen/orm/barrel.js +48 -0
- package/cli/codegen/orm/client-generator.d.ts +45 -0
- package/cli/codegen/orm/client-generator.js +646 -0
- package/cli/codegen/orm/custom-ops-generator.d.ts +30 -0
- package/cli/codegen/orm/custom-ops-generator.js +350 -0
- package/cli/codegen/orm/index.d.ts +38 -0
- package/cli/codegen/orm/index.js +88 -0
- package/cli/codegen/orm/input-types-generator.d.ts +21 -0
- package/cli/codegen/orm/input-types-generator.js +705 -0
- package/cli/codegen/orm/input-types-generator.test.d.ts +1 -0
- package/cli/codegen/orm/input-types-generator.test.js +75 -0
- package/cli/codegen/orm/model-generator.d.ts +32 -0
- package/cli/codegen/orm/model-generator.js +264 -0
- package/cli/codegen/orm/query-builder.d.ts +161 -0
- package/cli/codegen/orm/query-builder.js +366 -0
- package/cli/codegen/orm/select-types.d.ts +169 -0
- package/cli/codegen/orm/select-types.js +16 -0
- package/cli/codegen/orm/select-types.test.d.ts +11 -0
- package/cli/codegen/orm/select-types.test.js +22 -0
- package/cli/codegen/queries.d.ts +25 -0
- package/cli/codegen/queries.js +438 -0
- package/cli/codegen/scalars.d.ts +12 -0
- package/cli/codegen/scalars.js +71 -0
- package/cli/codegen/schema-gql-ast.d.ts +51 -0
- package/cli/codegen/schema-gql-ast.js +385 -0
- package/cli/codegen/ts-ast.d.ts +122 -0
- package/cli/codegen/ts-ast.js +280 -0
- package/cli/codegen/type-resolver.d.ts +96 -0
- package/cli/codegen/type-resolver.js +246 -0
- package/cli/codegen/types.d.ts +12 -0
- package/cli/codegen/types.js +69 -0
- package/cli/codegen/utils.d.ts +163 -0
- package/cli/codegen/utils.js +326 -0
- package/cli/commands/generate-orm.d.ts +37 -0
- package/cli/commands/generate-orm.js +195 -0
- package/cli/commands/generate.d.ts +39 -0
- package/cli/commands/generate.js +299 -0
- package/cli/commands/index.d.ts +7 -0
- package/cli/commands/index.js +12 -0
- package/cli/commands/init.d.ts +35 -0
- package/cli/commands/init.js +176 -0
- package/cli/index.d.ts +4 -0
- package/cli/index.js +291 -0
- package/cli/introspect/fetch-meta.d.ts +31 -0
- package/cli/introspect/fetch-meta.js +108 -0
- package/cli/introspect/fetch-schema.d.ts +21 -0
- package/cli/introspect/fetch-schema.js +86 -0
- package/cli/introspect/index.d.ts +8 -0
- package/cli/introspect/index.js +16 -0
- package/cli/introspect/meta-query.d.ts +111 -0
- package/cli/introspect/meta-query.js +191 -0
- package/cli/introspect/schema-query.d.ts +20 -0
- package/cli/introspect/schema-query.js +123 -0
- package/cli/introspect/transform-schema.d.ts +74 -0
- package/cli/introspect/transform-schema.js +269 -0
- package/cli/introspect/transform-schema.test.d.ts +1 -0
- package/cli/introspect/transform-schema.test.js +67 -0
- package/cli/introspect/transform.d.ts +21 -0
- package/cli/introspect/transform.js +216 -0
- package/cli/watch/cache.d.ts +45 -0
- package/cli/watch/cache.js +111 -0
- package/cli/watch/debounce.d.ts +19 -0
- package/cli/watch/debounce.js +89 -0
- package/cli/watch/hash.d.ts +17 -0
- package/cli/watch/hash.js +48 -0
- package/cli/watch/index.d.ts +10 -0
- package/cli/watch/index.js +22 -0
- package/cli/watch/orchestrator.d.ts +63 -0
- package/cli/watch/orchestrator.js +228 -0
- package/cli/watch/poller.d.ts +65 -0
- package/cli/watch/poller.js +203 -0
- package/cli/watch/types.d.ts +67 -0
- package/cli/watch/types.js +5 -0
- package/client/error.d.ts +95 -0
- package/client/error.js +255 -0
- package/client/execute.d.ts +57 -0
- package/client/execute.js +124 -0
- package/client/index.d.ts +6 -0
- package/client/index.js +18 -0
- package/client/typed-document.d.ts +31 -0
- package/client/typed-document.js +44 -0
- package/core/ast.d.ts +10 -0
- package/core/ast.js +593 -0
- package/core/custom-ast.d.ts +35 -0
- package/core/custom-ast.js +204 -0
- package/core/index.d.ts +8 -0
- package/core/index.js +33 -0
- package/core/meta-object/convert.d.ts +65 -0
- package/core/meta-object/convert.js +63 -0
- package/core/meta-object/format.json +93 -0
- package/core/meta-object/index.d.ts +2 -0
- package/core/meta-object/index.js +18 -0
- package/core/meta-object/validate.d.ts +9 -0
- package/core/meta-object/validate.js +34 -0
- package/core/query-builder.d.ts +46 -0
- package/core/query-builder.js +412 -0
- package/core/types.d.ts +139 -0
- package/core/types.js +28 -0
- package/esm/__tests__/codegen/input-types-generator.test.d.ts +1 -0
- package/esm/__tests__/codegen/input-types-generator.test.js +633 -0
- package/esm/cli/codegen/barrel.d.ts +27 -0
- package/esm/cli/codegen/barrel.js +156 -0
- package/esm/cli/codegen/client.d.ts +4 -0
- package/esm/cli/codegen/client.js +167 -0
- package/esm/cli/codegen/custom-mutations.d.ts +38 -0
- package/esm/cli/codegen/custom-mutations.js +145 -0
- package/esm/cli/codegen/custom-queries.d.ts +38 -0
- package/esm/cli/codegen/custom-queries.js +354 -0
- package/esm/cli/codegen/filters.d.ts +27 -0
- package/esm/cli/codegen/filters.js +351 -0
- package/esm/cli/codegen/gql-ast.d.ts +41 -0
- package/esm/cli/codegen/gql-ast.js +288 -0
- package/esm/cli/codegen/index.d.ts +71 -0
- package/esm/cli/codegen/index.js +124 -0
- package/esm/cli/codegen/mutations.d.ts +30 -0
- package/esm/cli/codegen/mutations.js +404 -0
- package/esm/cli/codegen/orm/barrel.d.ts +18 -0
- package/esm/cli/codegen/orm/barrel.js +44 -0
- package/esm/cli/codegen/orm/client-generator.d.ts +45 -0
- package/esm/cli/codegen/orm/client-generator.js +640 -0
- package/esm/cli/codegen/orm/custom-ops-generator.d.ts +30 -0
- package/esm/cli/codegen/orm/custom-ops-generator.js +346 -0
- package/esm/cli/codegen/orm/index.d.ts +38 -0
- package/esm/cli/codegen/orm/index.js +75 -0
- package/esm/cli/codegen/orm/input-types-generator.d.ts +21 -0
- package/esm/cli/codegen/orm/input-types-generator.js +700 -0
- package/esm/cli/codegen/orm/input-types-generator.test.d.ts +1 -0
- package/esm/cli/codegen/orm/input-types-generator.test.js +73 -0
- package/esm/cli/codegen/orm/model-generator.d.ts +32 -0
- package/esm/cli/codegen/orm/model-generator.js +260 -0
- package/esm/cli/codegen/orm/query-builder.d.ts +161 -0
- package/esm/cli/codegen/orm/query-builder.js +353 -0
- package/esm/cli/codegen/orm/select-types.d.ts +169 -0
- package/esm/cli/codegen/orm/select-types.js +15 -0
- package/esm/cli/codegen/orm/select-types.test.d.ts +11 -0
- package/esm/cli/codegen/orm/select-types.test.js +21 -0
- package/esm/cli/codegen/queries.d.ts +25 -0
- package/esm/cli/codegen/queries.js +433 -0
- package/esm/cli/codegen/scalars.d.ts +12 -0
- package/esm/cli/codegen/scalars.js +66 -0
- package/esm/cli/codegen/schema-gql-ast.d.ts +51 -0
- package/esm/cli/codegen/schema-gql-ast.js +343 -0
- package/esm/cli/codegen/ts-ast.d.ts +122 -0
- package/esm/cli/codegen/ts-ast.js +260 -0
- package/esm/cli/codegen/type-resolver.d.ts +96 -0
- package/esm/cli/codegen/type-resolver.js +224 -0
- package/esm/cli/codegen/types.d.ts +12 -0
- package/esm/cli/codegen/types.js +65 -0
- package/esm/cli/codegen/utils.d.ts +163 -0
- package/esm/cli/codegen/utils.js +288 -0
- package/esm/cli/commands/generate-orm.d.ts +37 -0
- package/esm/cli/commands/generate-orm.js +192 -0
- package/esm/cli/commands/generate.d.ts +39 -0
- package/esm/cli/commands/generate.js +262 -0
- package/esm/cli/commands/index.d.ts +7 -0
- package/esm/cli/commands/index.js +5 -0
- package/esm/cli/commands/init.d.ts +35 -0
- package/esm/cli/commands/init.js +138 -0
- package/esm/cli/index.d.ts +4 -0
- package/esm/cli/index.js +256 -0
- package/esm/cli/introspect/fetch-meta.d.ts +31 -0
- package/esm/cli/introspect/fetch-meta.js +104 -0
- package/esm/cli/introspect/fetch-schema.d.ts +21 -0
- package/esm/cli/introspect/fetch-schema.js +83 -0
- package/esm/cli/introspect/index.d.ts +8 -0
- package/esm/cli/introspect/index.js +6 -0
- package/esm/cli/introspect/meta-query.d.ts +111 -0
- package/esm/cli/introspect/meta-query.js +188 -0
- package/esm/cli/introspect/schema-query.d.ts +20 -0
- package/esm/cli/introspect/schema-query.js +120 -0
- package/esm/cli/introspect/transform-schema.d.ts +74 -0
- package/esm/cli/introspect/transform-schema.js +259 -0
- package/esm/cli/introspect/transform-schema.test.d.ts +1 -0
- package/esm/cli/introspect/transform-schema.test.js +65 -0
- package/esm/cli/introspect/transform.d.ts +21 -0
- package/esm/cli/introspect/transform.js +210 -0
- package/esm/cli/watch/cache.d.ts +45 -0
- package/esm/cli/watch/cache.js +73 -0
- package/esm/cli/watch/debounce.d.ts +19 -0
- package/esm/cli/watch/debounce.js +85 -0
- package/esm/cli/watch/hash.d.ts +17 -0
- package/esm/cli/watch/hash.js +43 -0
- package/esm/cli/watch/index.d.ts +10 -0
- package/esm/cli/watch/index.js +8 -0
- package/esm/cli/watch/orchestrator.d.ts +63 -0
- package/esm/cli/watch/orchestrator.js +223 -0
- package/esm/cli/watch/poller.d.ts +65 -0
- package/esm/cli/watch/poller.js +198 -0
- package/esm/cli/watch/types.d.ts +67 -0
- package/esm/cli/watch/types.js +4 -0
- package/esm/client/error.d.ts +95 -0
- package/esm/client/error.js +249 -0
- package/esm/client/execute.d.ts +57 -0
- package/esm/client/execute.js +120 -0
- package/esm/client/index.d.ts +6 -0
- package/esm/client/index.js +6 -0
- package/esm/client/typed-document.d.ts +31 -0
- package/esm/client/typed-document.js +40 -0
- package/esm/core/ast.d.ts +10 -0
- package/esm/core/ast.js +549 -0
- package/esm/core/custom-ast.d.ts +35 -0
- package/esm/core/custom-ast.js +161 -0
- package/esm/core/index.d.ts +8 -0
- package/esm/core/index.js +12 -0
- package/esm/core/meta-object/convert.d.ts +65 -0
- package/esm/core/meta-object/convert.js +60 -0
- package/esm/core/meta-object/format.json +93 -0
- package/esm/core/meta-object/index.d.ts +2 -0
- package/esm/core/meta-object/index.js +2 -0
- package/esm/core/meta-object/validate.d.ts +9 -0
- package/esm/core/meta-object/validate.js +28 -0
- package/esm/core/query-builder.d.ts +46 -0
- package/esm/core/query-builder.js +375 -0
- package/esm/core/types.d.ts +139 -0
- package/esm/core/types.js +24 -0
- package/esm/generators/field-selector.d.ts +30 -0
- package/esm/generators/field-selector.js +355 -0
- package/esm/generators/index.d.ts +6 -0
- package/esm/generators/index.js +9 -0
- package/esm/generators/mutations.d.ts +31 -0
- package/esm/generators/mutations.js +197 -0
- package/esm/generators/select.d.ts +50 -0
- package/esm/generators/select.js +636 -0
- package/esm/index.d.ts +12 -0
- package/esm/index.js +17 -3
- package/esm/react/index.d.ts +5 -0
- package/esm/react/index.js +6 -0
- package/esm/types/config.d.ts +199 -0
- package/esm/types/config.js +106 -0
- package/esm/types/index.d.ts +9 -0
- package/esm/types/index.js +4 -0
- package/esm/types/introspection.d.ts +121 -0
- package/esm/types/introspection.js +54 -0
- package/esm/types/mutation.d.ts +45 -0
- package/esm/types/mutation.js +4 -0
- package/esm/types/query.d.ts +82 -0
- package/esm/types/query.js +4 -0
- package/esm/types/schema.d.ts +253 -0
- package/esm/types/schema.js +5 -0
- package/esm/types/selection.d.ts +43 -0
- package/esm/types/selection.js +4 -0
- package/esm/utils/index.d.ts +4 -0
- package/esm/utils/index.js +4 -0
- package/generators/field-selector.d.ts +30 -0
- package/generators/field-selector.js +361 -0
- package/generators/index.d.ts +6 -0
- package/generators/index.js +27 -0
- package/generators/mutations.d.ts +31 -0
- package/generators/mutations.js +235 -0
- package/generators/select.d.ts +50 -0
- package/generators/select.js +679 -0
- package/index.d.ts +12 -3
- package/index.js +19 -3
- package/package.json +59 -38
- package/react/index.d.ts +5 -0
- package/react/index.js +9 -0
- package/types/config.d.ts +199 -0
- package/types/config.js +111 -0
- package/types/index.d.ts +9 -0
- package/types/index.js +10 -0
- package/types/introspection.d.ts +121 -0
- package/types/introspection.js +62 -0
- package/types/mutation.d.ts +45 -0
- package/types/mutation.js +5 -0
- package/types/query.d.ts +82 -0
- package/types/query.js +5 -0
- package/types/schema.d.ts +253 -0
- package/types/schema.js +6 -0
- package/types/selection.d.ts +43 -0
- package/types/selection.js +5 -0
- package/utils/index.d.ts +4 -0
- package/utils/index.js +7 -0
- package/codegen.d.ts +0 -13
- package/codegen.js +0 -293
- package/esm/codegen.js +0 -253
- package/esm/gql.js +0 -939
- package/esm/options.js +0 -27
- package/gql.d.ts +0 -188
- package/gql.js +0 -992
- package/options.d.ts +0 -45
- package/options.js +0 -31
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dynamic GraphQL AST builders for custom operations
|
|
3
|
+
*
|
|
4
|
+
* Generates GraphQL query/mutation documents from CleanOperation data
|
|
5
|
+
* using gql-ast library for proper AST construction.
|
|
6
|
+
*/
|
|
7
|
+
import * as t from 'gql-ast';
|
|
8
|
+
import { print } from 'graphql';
|
|
9
|
+
import { getBaseTypeKind, shouldSkipField } from './type-resolver';
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Type Node Builders (GraphQL Type AST)
|
|
12
|
+
// ============================================================================
|
|
13
|
+
/**
|
|
14
|
+
* Build a GraphQL type node from CleanTypeRef
|
|
15
|
+
* Handles NON_NULL, LIST, and named types
|
|
16
|
+
*/
|
|
17
|
+
function buildTypeNode(typeRef) {
|
|
18
|
+
switch (typeRef.kind) {
|
|
19
|
+
case 'NON_NULL':
|
|
20
|
+
if (typeRef.ofType) {
|
|
21
|
+
const innerType = buildTypeNode(typeRef.ofType);
|
|
22
|
+
// Can't wrap NON_NULL in NON_NULL
|
|
23
|
+
if (innerType.kind === 'NonNullType') {
|
|
24
|
+
return innerType;
|
|
25
|
+
}
|
|
26
|
+
return t.nonNullType({ type: innerType });
|
|
27
|
+
}
|
|
28
|
+
return t.namedType({ type: 'String' });
|
|
29
|
+
case 'LIST':
|
|
30
|
+
if (typeRef.ofType) {
|
|
31
|
+
return t.listType({ type: buildTypeNode(typeRef.ofType) });
|
|
32
|
+
}
|
|
33
|
+
return t.listType({ type: t.namedType({ type: 'String' }) });
|
|
34
|
+
case 'SCALAR':
|
|
35
|
+
case 'ENUM':
|
|
36
|
+
case 'OBJECT':
|
|
37
|
+
case 'INPUT_OBJECT':
|
|
38
|
+
return t.namedType({ type: typeRef.name ?? 'String' });
|
|
39
|
+
default:
|
|
40
|
+
return t.namedType({ type: typeRef.name ?? 'String' });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// ============================================================================
|
|
44
|
+
// Variable Definition Builders
|
|
45
|
+
// ============================================================================
|
|
46
|
+
/**
|
|
47
|
+
* Build variable definitions from operation arguments
|
|
48
|
+
*/
|
|
49
|
+
export function buildVariableDefinitions(args) {
|
|
50
|
+
return args.map((arg) => t.variableDefinition({
|
|
51
|
+
variable: t.variable({ name: arg.name }),
|
|
52
|
+
type: buildTypeNode(arg.type),
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Build argument nodes that reference variables
|
|
57
|
+
*/
|
|
58
|
+
function buildArgumentNodes(args) {
|
|
59
|
+
return args.map((arg) => t.argument({
|
|
60
|
+
name: arg.name,
|
|
61
|
+
value: t.variable({ name: arg.name }),
|
|
62
|
+
}));
|
|
63
|
+
}
|
|
64
|
+
// ============================================================================
|
|
65
|
+
// Field Selection Builders
|
|
66
|
+
// ============================================================================
|
|
67
|
+
/**
|
|
68
|
+
* Check if a type should have selections (is an object type)
|
|
69
|
+
*/
|
|
70
|
+
function typeNeedsSelections(typeRef) {
|
|
71
|
+
const baseKind = getBaseTypeKind(typeRef);
|
|
72
|
+
return baseKind === 'OBJECT';
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Get the resolved fields for a type reference
|
|
76
|
+
* Uses type registry for deep resolution
|
|
77
|
+
*/
|
|
78
|
+
function getResolvedFields(typeRef, typeRegistry) {
|
|
79
|
+
// First check if fields are directly on the typeRef
|
|
80
|
+
if (typeRef.fields) {
|
|
81
|
+
return typeRef.fields;
|
|
82
|
+
}
|
|
83
|
+
// For wrapper types, unwrap and check
|
|
84
|
+
if (typeRef.ofType) {
|
|
85
|
+
return getResolvedFields(typeRef.ofType, typeRegistry);
|
|
86
|
+
}
|
|
87
|
+
// Look up in type registry
|
|
88
|
+
if (typeRegistry && typeRef.name) {
|
|
89
|
+
const resolved = typeRegistry.get(typeRef.name);
|
|
90
|
+
if (resolved?.fields) {
|
|
91
|
+
return resolved.fields;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Build field selections for an object type
|
|
98
|
+
* Recursively handles nested objects up to maxDepth
|
|
99
|
+
*/
|
|
100
|
+
export function buildFieldSelections(typeRef, config, currentDepth = 0) {
|
|
101
|
+
const { maxDepth, skipQueryField, typeRegistry } = config;
|
|
102
|
+
// Stop recursion at max depth
|
|
103
|
+
if (currentDepth >= maxDepth) {
|
|
104
|
+
return [];
|
|
105
|
+
}
|
|
106
|
+
const fields = getResolvedFields(typeRef, typeRegistry);
|
|
107
|
+
if (!fields || fields.length === 0) {
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
const selections = [];
|
|
111
|
+
for (const field of fields) {
|
|
112
|
+
// Skip internal fields
|
|
113
|
+
if (shouldSkipField(field.name, skipQueryField)) {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
const fieldKind = getBaseTypeKind(field.type);
|
|
117
|
+
// For scalar and enum types, just add the field
|
|
118
|
+
if (fieldKind === 'SCALAR' || fieldKind === 'ENUM') {
|
|
119
|
+
selections.push(t.field({ name: field.name }));
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
// For object types, recurse if within depth limit
|
|
123
|
+
if (fieldKind === 'OBJECT' && currentDepth < maxDepth - 1) {
|
|
124
|
+
const nestedSelections = buildFieldSelections(field.type, config, currentDepth + 1);
|
|
125
|
+
if (nestedSelections.length > 0) {
|
|
126
|
+
selections.push(t.field({
|
|
127
|
+
name: field.name,
|
|
128
|
+
selectionSet: t.selectionSet({ selections: nestedSelections }),
|
|
129
|
+
}));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return selections;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Build selections for a return type, handling connections and payloads
|
|
137
|
+
*/
|
|
138
|
+
function buildReturnTypeSelections(returnType, config) {
|
|
139
|
+
const fields = getResolvedFields(returnType, config.typeRegistry);
|
|
140
|
+
if (!fields || fields.length === 0) {
|
|
141
|
+
return [];
|
|
142
|
+
}
|
|
143
|
+
// Check if this is a connection type
|
|
144
|
+
const hasNodes = fields.some((f) => f.name === 'nodes');
|
|
145
|
+
const hasTotalCount = fields.some((f) => f.name === 'totalCount');
|
|
146
|
+
if (hasNodes && hasTotalCount) {
|
|
147
|
+
return buildConnectionSelections(fields, config);
|
|
148
|
+
}
|
|
149
|
+
// Check if this is a mutation payload (has clientMutationId)
|
|
150
|
+
const hasClientMutationId = fields.some((f) => f.name === 'clientMutationId');
|
|
151
|
+
if (hasClientMutationId) {
|
|
152
|
+
return buildPayloadSelections(fields, config);
|
|
153
|
+
}
|
|
154
|
+
// Regular object - build normal selections
|
|
155
|
+
return buildFieldSelections(returnType, config);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Build selections for a connection type
|
|
159
|
+
*/
|
|
160
|
+
function buildConnectionSelections(fields, config) {
|
|
161
|
+
const selections = [];
|
|
162
|
+
// Add totalCount
|
|
163
|
+
const totalCountField = fields.find((f) => f.name === 'totalCount');
|
|
164
|
+
if (totalCountField) {
|
|
165
|
+
selections.push(t.field({ name: 'totalCount' }));
|
|
166
|
+
}
|
|
167
|
+
// Add nodes with nested selections
|
|
168
|
+
const nodesField = fields.find((f) => f.name === 'nodes');
|
|
169
|
+
if (nodesField) {
|
|
170
|
+
const nodeSelections = buildFieldSelections(nodesField.type, config);
|
|
171
|
+
if (nodeSelections.length > 0) {
|
|
172
|
+
selections.push(t.field({
|
|
173
|
+
name: 'nodes',
|
|
174
|
+
selectionSet: t.selectionSet({ selections: nodeSelections }),
|
|
175
|
+
}));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// Add pageInfo
|
|
179
|
+
const pageInfoField = fields.find((f) => f.name === 'pageInfo');
|
|
180
|
+
if (pageInfoField) {
|
|
181
|
+
selections.push(t.field({
|
|
182
|
+
name: 'pageInfo',
|
|
183
|
+
selectionSet: t.selectionSet({
|
|
184
|
+
selections: [
|
|
185
|
+
t.field({ name: 'hasNextPage' }),
|
|
186
|
+
t.field({ name: 'hasPreviousPage' }),
|
|
187
|
+
t.field({ name: 'startCursor' }),
|
|
188
|
+
t.field({ name: 'endCursor' }),
|
|
189
|
+
],
|
|
190
|
+
}),
|
|
191
|
+
}));
|
|
192
|
+
}
|
|
193
|
+
return selections;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Build selections for a mutation payload type
|
|
197
|
+
*/
|
|
198
|
+
function buildPayloadSelections(fields, config) {
|
|
199
|
+
const selections = [];
|
|
200
|
+
for (const field of fields) {
|
|
201
|
+
// Skip query field
|
|
202
|
+
if (shouldSkipField(field.name, config.skipQueryField)) {
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
const fieldKind = getBaseTypeKind(field.type);
|
|
206
|
+
// Add scalar fields directly
|
|
207
|
+
if (fieldKind === 'SCALAR' || fieldKind === 'ENUM') {
|
|
208
|
+
selections.push(t.field({ name: field.name }));
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
// For object fields (like the returned entity), add with selections
|
|
212
|
+
if (fieldKind === 'OBJECT') {
|
|
213
|
+
const nestedSelections = buildFieldSelections(field.type, config);
|
|
214
|
+
if (nestedSelections.length > 0) {
|
|
215
|
+
selections.push(t.field({
|
|
216
|
+
name: field.name,
|
|
217
|
+
selectionSet: t.selectionSet({ selections: nestedSelections }),
|
|
218
|
+
}));
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return selections;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Build a custom query AST from a CleanOperation
|
|
226
|
+
*/
|
|
227
|
+
export function buildCustomQueryAST(config) {
|
|
228
|
+
const { operation, typeRegistry, maxDepth = 2, skipQueryField = true, } = config;
|
|
229
|
+
const operationName = `${ucFirst(operation.name)}Query`;
|
|
230
|
+
// Build variable definitions
|
|
231
|
+
const variableDefinitions = buildVariableDefinitions(operation.args);
|
|
232
|
+
// Build arguments that reference the variables
|
|
233
|
+
const args = buildArgumentNodes(operation.args);
|
|
234
|
+
// Build return type selections
|
|
235
|
+
const fieldSelectionConfig = {
|
|
236
|
+
maxDepth,
|
|
237
|
+
skipQueryField,
|
|
238
|
+
typeRegistry,
|
|
239
|
+
};
|
|
240
|
+
const returnTypeNeedsSelections = typeNeedsSelections(operation.returnType);
|
|
241
|
+
let selections = [];
|
|
242
|
+
if (returnTypeNeedsSelections) {
|
|
243
|
+
selections = buildReturnTypeSelections(operation.returnType, fieldSelectionConfig);
|
|
244
|
+
}
|
|
245
|
+
// Build the query field
|
|
246
|
+
const queryField = selections.length > 0
|
|
247
|
+
? t.field({
|
|
248
|
+
name: operation.name,
|
|
249
|
+
args: args.length > 0 ? args : undefined,
|
|
250
|
+
selectionSet: t.selectionSet({ selections }),
|
|
251
|
+
})
|
|
252
|
+
: t.field({
|
|
253
|
+
name: operation.name,
|
|
254
|
+
args: args.length > 0 ? args : undefined,
|
|
255
|
+
});
|
|
256
|
+
return t.document({
|
|
257
|
+
definitions: [
|
|
258
|
+
t.operationDefinition({
|
|
259
|
+
operation: 'query',
|
|
260
|
+
name: operationName,
|
|
261
|
+
variableDefinitions: variableDefinitions.length > 0 ? variableDefinitions : undefined,
|
|
262
|
+
selectionSet: t.selectionSet({
|
|
263
|
+
selections: [queryField],
|
|
264
|
+
}),
|
|
265
|
+
}),
|
|
266
|
+
],
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Build a custom mutation AST from a CleanOperation
|
|
271
|
+
*/
|
|
272
|
+
export function buildCustomMutationAST(config) {
|
|
273
|
+
const { operation, typeRegistry, maxDepth = 2, skipQueryField = true, } = config;
|
|
274
|
+
const operationName = `${ucFirst(operation.name)}Mutation`;
|
|
275
|
+
// Build variable definitions
|
|
276
|
+
const variableDefinitions = buildVariableDefinitions(operation.args);
|
|
277
|
+
// Build arguments that reference the variables
|
|
278
|
+
const args = buildArgumentNodes(operation.args);
|
|
279
|
+
// Build return type selections
|
|
280
|
+
const fieldSelectionConfig = {
|
|
281
|
+
maxDepth,
|
|
282
|
+
skipQueryField,
|
|
283
|
+
typeRegistry,
|
|
284
|
+
};
|
|
285
|
+
const returnTypeNeedsSelections = typeNeedsSelections(operation.returnType);
|
|
286
|
+
let selections = [];
|
|
287
|
+
if (returnTypeNeedsSelections) {
|
|
288
|
+
selections = buildReturnTypeSelections(operation.returnType, fieldSelectionConfig);
|
|
289
|
+
}
|
|
290
|
+
// Build the mutation field
|
|
291
|
+
const mutationField = selections.length > 0
|
|
292
|
+
? t.field({
|
|
293
|
+
name: operation.name,
|
|
294
|
+
args: args.length > 0 ? args : undefined,
|
|
295
|
+
selectionSet: t.selectionSet({ selections }),
|
|
296
|
+
})
|
|
297
|
+
: t.field({
|
|
298
|
+
name: operation.name,
|
|
299
|
+
args: args.length > 0 ? args : undefined,
|
|
300
|
+
});
|
|
301
|
+
return t.document({
|
|
302
|
+
definitions: [
|
|
303
|
+
t.operationDefinition({
|
|
304
|
+
operation: 'mutation',
|
|
305
|
+
name: operationName,
|
|
306
|
+
variableDefinitions: variableDefinitions.length > 0 ? variableDefinitions : undefined,
|
|
307
|
+
selectionSet: t.selectionSet({
|
|
308
|
+
selections: [mutationField],
|
|
309
|
+
}),
|
|
310
|
+
}),
|
|
311
|
+
],
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
// ============================================================================
|
|
315
|
+
// Print Utilities
|
|
316
|
+
// ============================================================================
|
|
317
|
+
/**
|
|
318
|
+
* Print a document AST to GraphQL string
|
|
319
|
+
*/
|
|
320
|
+
export function printGraphQL(ast) {
|
|
321
|
+
return print(ast);
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Build and print a custom query in one call
|
|
325
|
+
*/
|
|
326
|
+
export function buildCustomQueryString(config) {
|
|
327
|
+
return printGraphQL(buildCustomQueryAST(config));
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Build and print a custom mutation in one call
|
|
331
|
+
*/
|
|
332
|
+
export function buildCustomMutationString(config) {
|
|
333
|
+
return printGraphQL(buildCustomMutationAST(config));
|
|
334
|
+
}
|
|
335
|
+
// ============================================================================
|
|
336
|
+
// Helper Utilities
|
|
337
|
+
// ============================================================================
|
|
338
|
+
/**
|
|
339
|
+
* Uppercase first character
|
|
340
|
+
*/
|
|
341
|
+
function ucFirst(str) {
|
|
342
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
343
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript AST builders using ts-morph
|
|
3
|
+
*
|
|
4
|
+
* Provides utilities for generating TypeScript code via AST manipulation
|
|
5
|
+
* instead of string concatenation.
|
|
6
|
+
*/
|
|
7
|
+
import { Project, SourceFile, type InterfaceDeclarationStructure, type FunctionDeclarationStructure, type VariableStatementStructure, type ImportDeclarationStructure, type TypeAliasDeclarationStructure } from 'ts-morph';
|
|
8
|
+
/**
|
|
9
|
+
* Create a new ts-morph project for code generation
|
|
10
|
+
*/
|
|
11
|
+
export declare function createProject(): Project;
|
|
12
|
+
/**
|
|
13
|
+
* Create a source file in the project
|
|
14
|
+
*/
|
|
15
|
+
export declare function createSourceFile(project: Project, fileName: string): SourceFile;
|
|
16
|
+
/**
|
|
17
|
+
* Get formatted output from source file
|
|
18
|
+
*/
|
|
19
|
+
export declare function getFormattedOutput(sourceFile: SourceFile): string;
|
|
20
|
+
/**
|
|
21
|
+
* Get output with minimal formatting (preserves intentional blank lines)
|
|
22
|
+
* Post-processes to fix indentation and section comment spacing
|
|
23
|
+
*
|
|
24
|
+
* ts-morph generates type alias bodies with extra indentation:
|
|
25
|
+
* - Properties get 6 spaces (we want 2)
|
|
26
|
+
* - Closing brace gets 4 spaces (we want 0)
|
|
27
|
+
*
|
|
28
|
+
* For interfaces it uses 4 spaces which we convert to 2.
|
|
29
|
+
*/
|
|
30
|
+
export declare function getMinimalFormattedOutput(sourceFile: SourceFile): string;
|
|
31
|
+
/**
|
|
32
|
+
* Create a file header comment
|
|
33
|
+
*/
|
|
34
|
+
export declare function createFileHeader(description: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* Create JSDoc comment for a declaration
|
|
37
|
+
*/
|
|
38
|
+
export declare function createJsDoc(lines: string[]): string;
|
|
39
|
+
export interface ImportSpec {
|
|
40
|
+
moduleSpecifier: string;
|
|
41
|
+
namedImports?: string[];
|
|
42
|
+
typeOnlyNamedImports?: string[];
|
|
43
|
+
defaultImport?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Create import declaration structure
|
|
47
|
+
*/
|
|
48
|
+
export declare function createImport(spec: ImportSpec): ImportDeclarationStructure;
|
|
49
|
+
export interface InterfaceProperty {
|
|
50
|
+
name: string;
|
|
51
|
+
type: string;
|
|
52
|
+
optional?: boolean;
|
|
53
|
+
docs?: string[];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Create interface declaration structure
|
|
57
|
+
*/
|
|
58
|
+
export declare function createInterface(name: string, properties: InterfaceProperty[], options?: {
|
|
59
|
+
docs?: string[];
|
|
60
|
+
isExported?: boolean;
|
|
61
|
+
extends?: string[];
|
|
62
|
+
}): InterfaceDeclarationStructure;
|
|
63
|
+
/**
|
|
64
|
+
* Create filter interface with standard PostGraphile operators
|
|
65
|
+
*/
|
|
66
|
+
export declare function createFilterInterface(name: string, fieldFilters: Array<{
|
|
67
|
+
fieldName: string;
|
|
68
|
+
filterType: string;
|
|
69
|
+
}>): InterfaceDeclarationStructure;
|
|
70
|
+
/**
|
|
71
|
+
* Create type alias declaration structure
|
|
72
|
+
*/
|
|
73
|
+
export declare function createTypeAlias(name: string, type: string, options?: {
|
|
74
|
+
docs?: string[];
|
|
75
|
+
isExported?: boolean;
|
|
76
|
+
}): TypeAliasDeclarationStructure;
|
|
77
|
+
/**
|
|
78
|
+
* Create union type from string literals
|
|
79
|
+
*/
|
|
80
|
+
export declare function createUnionType(values: string[]): string;
|
|
81
|
+
/**
|
|
82
|
+
* Create const variable statement structure
|
|
83
|
+
*/
|
|
84
|
+
export declare function createConst(name: string, initializer: string, options?: {
|
|
85
|
+
docs?: string[];
|
|
86
|
+
isExported?: boolean;
|
|
87
|
+
type?: string;
|
|
88
|
+
}): VariableStatementStructure;
|
|
89
|
+
/**
|
|
90
|
+
* Create a template literal string (for GraphQL documents)
|
|
91
|
+
*/
|
|
92
|
+
export declare function createTemplateLiteral(content: string): string;
|
|
93
|
+
export interface FunctionParameter {
|
|
94
|
+
name: string;
|
|
95
|
+
type: string;
|
|
96
|
+
optional?: boolean;
|
|
97
|
+
initializer?: string;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Create function declaration structure
|
|
101
|
+
*/
|
|
102
|
+
export declare function createFunction(name: string, parameters: FunctionParameter[], returnType: string, body: string, options?: {
|
|
103
|
+
docs?: string[];
|
|
104
|
+
isExported?: boolean;
|
|
105
|
+
isAsync?: boolean;
|
|
106
|
+
}): FunctionDeclarationStructure;
|
|
107
|
+
/**
|
|
108
|
+
* Create re-export statement
|
|
109
|
+
*/
|
|
110
|
+
export declare function createReExport(names: string[], moduleSpecifier: string, isTypeOnly?: boolean): string;
|
|
111
|
+
/**
|
|
112
|
+
* Create barrel export statement
|
|
113
|
+
*/
|
|
114
|
+
export declare function createBarrelExport(moduleSpecifier: string): string;
|
|
115
|
+
/**
|
|
116
|
+
* Create a section divider comment for generated code
|
|
117
|
+
*/
|
|
118
|
+
export declare function createSectionComment(title: string): string;
|
|
119
|
+
/**
|
|
120
|
+
* Add a section comment to source file with proper spacing
|
|
121
|
+
*/
|
|
122
|
+
export declare function addSectionComment(sourceFile: SourceFile, title: string): void;
|