@gqlkit-ts/cli 0.2.0 → 0.4.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 +143 -0
- package/dist/auto-type-generator/auto-type-generator.d.ts +10 -4
- package/dist/auto-type-generator/auto-type-generator.d.ts.map +1 -1
- package/dist/auto-type-generator/auto-type-generator.js +656 -146
- package/dist/auto-type-generator/auto-type-generator.js.map +1 -1
- package/dist/auto-type-generator/index.d.ts +8 -1
- package/dist/auto-type-generator/index.d.ts.map +1 -1
- package/dist/auto-type-generator/index.js +3 -0
- package/dist/auto-type-generator/index.js.map +1 -1
- package/dist/auto-type-generator/inline-enum-collector.d.ts +13 -5
- package/dist/auto-type-generator/inline-enum-collector.d.ts.map +1 -1
- package/dist/auto-type-generator/inline-enum-collector.js +107 -71
- package/dist/auto-type-generator/inline-enum-collector.js.map +1 -1
- package/dist/auto-type-generator/inline-object-traverser.d.ts +20 -0
- package/dist/auto-type-generator/inline-object-traverser.d.ts.map +1 -0
- package/dist/auto-type-generator/inline-object-traverser.js +22 -0
- package/dist/auto-type-generator/inline-object-traverser.js.map +1 -0
- package/dist/auto-type-generator/inline-union-collector.d.ts +29 -0
- package/dist/auto-type-generator/inline-union-collector.d.ts.map +1 -0
- package/dist/auto-type-generator/inline-union-collector.js +216 -0
- package/dist/auto-type-generator/inline-union-collector.js.map +1 -0
- package/dist/auto-type-generator/inline-union-types.d.ts +29 -0
- package/dist/auto-type-generator/inline-union-types.d.ts.map +1 -0
- package/dist/auto-type-generator/inline-union-types.js +2 -0
- package/dist/auto-type-generator/inline-union-types.js.map +1 -0
- package/dist/auto-type-generator/inline-union-validator.d.ts +76 -0
- package/dist/auto-type-generator/inline-union-validator.d.ts.map +1 -0
- package/dist/auto-type-generator/inline-union-validator.js +329 -0
- package/dist/auto-type-generator/inline-union-validator.js.map +1 -0
- package/dist/auto-type-generator/naming-convention.d.ts +18 -1
- package/dist/auto-type-generator/naming-convention.d.ts.map +1 -1
- package/dist/auto-type-generator/naming-convention.js +16 -0
- package/dist/auto-type-generator/naming-convention.js.map +1 -1
- package/dist/auto-type-generator/resolve-type-generator.d.ts +20 -0
- package/dist/auto-type-generator/resolve-type-generator.d.ts.map +1 -0
- package/dist/auto-type-generator/resolve-type-generator.js +2 -0
- package/dist/auto-type-generator/resolve-type-generator.js.map +1 -0
- package/dist/auto-type-generator/resolver-field-iterator.d.ts +13 -0
- package/dist/auto-type-generator/resolver-field-iterator.d.ts.map +1 -0
- package/dist/auto-type-generator/resolver-field-iterator.js +22 -0
- package/dist/auto-type-generator/resolver-field-iterator.js.map +1 -0
- package/dist/auto-type-generator/typename-extractor.d.ts +26 -0
- package/dist/auto-type-generator/typename-extractor.d.ts.map +1 -0
- package/dist/auto-type-generator/typename-extractor.js +142 -0
- package/dist/auto-type-generator/typename-extractor.js.map +1 -0
- package/dist/auto-type-generator/typename-resolve-type-generator.d.ts +35 -0
- package/dist/auto-type-generator/typename-resolve-type-generator.d.ts.map +1 -0
- package/dist/auto-type-generator/typename-resolve-type-generator.js +177 -0
- package/dist/auto-type-generator/typename-resolve-type-generator.js.map +1 -0
- package/dist/auto-type-generator/typename-types.d.ts +43 -0
- package/dist/auto-type-generator/typename-types.d.ts.map +1 -0
- package/dist/auto-type-generator/typename-types.js +37 -0
- package/dist/auto-type-generator/typename-types.js.map +1 -0
- package/dist/auto-type-generator/typename-validator.d.ts +37 -0
- package/dist/auto-type-generator/typename-validator.d.ts.map +1 -0
- package/dist/auto-type-generator/typename-validator.js +206 -0
- package/dist/auto-type-generator/typename-validator.js.map +1 -0
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/docs.d.ts +51 -0
- package/dist/commands/docs.d.ts.map +1 -0
- package/dist/commands/docs.js +154 -0
- package/dist/commands/docs.js.map +1 -0
- package/dist/config/types.d.ts +13 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config-loader/loader.d.ts +3 -0
- package/dist/config-loader/loader.d.ts.map +1 -1
- package/dist/config-loader/loader.js +1 -0
- package/dist/config-loader/loader.js.map +1 -1
- package/dist/config-loader/validator.d.ts.map +1 -1
- package/dist/config-loader/validator.js +23 -0
- package/dist/config-loader/validator.js.map +1 -1
- package/dist/gen-orchestrator/orchestrator.d.ts.map +1 -1
- package/dist/gen-orchestrator/orchestrator.js +32 -12
- package/dist/gen-orchestrator/orchestrator.js.map +1 -1
- package/dist/resolver-extractor/extract-resolvers.d.ts +19 -1
- package/dist/resolver-extractor/extract-resolvers.d.ts.map +1 -1
- package/dist/resolver-extractor/extractor/define-api-extractor.d.ts +5 -0
- package/dist/resolver-extractor/extractor/define-api-extractor.d.ts.map +1 -1
- package/dist/resolver-extractor/extractor/define-api-extractor.js +18 -65
- package/dist/resolver-extractor/extractor/define-api-extractor.js.map +1 -1
- package/dist/resolver-extractor/index.d.ts +0 -1
- package/dist/resolver-extractor/index.d.ts.map +1 -1
- package/dist/resolver-extractor/validator/abstract-resolver-validator.d.ts +1 -0
- package/dist/resolver-extractor/validator/abstract-resolver-validator.d.ts.map +1 -1
- package/dist/resolver-extractor/validator/abstract-resolver-validator.js +9 -5
- package/dist/resolver-extractor/validator/abstract-resolver-validator.js.map +1 -1
- package/dist/schema-generator/builder/ast-builder.d.ts +2 -2
- package/dist/schema-generator/builder/ast-builder.d.ts.map +1 -1
- package/dist/schema-generator/builder/ast-builder.js +12 -34
- package/dist/schema-generator/builder/ast-builder.js.map +1 -1
- package/dist/schema-generator/emitter/code-emitter.d.ts +3 -1
- package/dist/schema-generator/emitter/code-emitter.d.ts.map +1 -1
- package/dist/schema-generator/emitter/code-emitter.js +42 -12
- package/dist/schema-generator/emitter/code-emitter.js.map +1 -1
- package/dist/schema-generator/emitter/sdl-emitter.d.ts +0 -4
- package/dist/schema-generator/emitter/sdl-emitter.d.ts.map +1 -1
- package/dist/schema-generator/emitter/sdl-emitter.js +0 -4
- package/dist/schema-generator/emitter/sdl-emitter.js.map +1 -1
- package/dist/schema-generator/generate-schema.d.ts +3 -0
- package/dist/schema-generator/generate-schema.d.ts.map +1 -1
- package/dist/schema-generator/generate-schema.js +83 -5
- package/dist/schema-generator/generate-schema.js.map +1 -1
- package/dist/schema-generator/integrator/result-integrator.d.ts +19 -9
- package/dist/schema-generator/integrator/result-integrator.d.ts.map +1 -1
- package/dist/schema-generator/integrator/result-integrator.js +60 -44
- package/dist/schema-generator/integrator/result-integrator.js.map +1 -1
- package/dist/schema-generator/resolver-collector/resolver-collector.d.ts +2 -0
- package/dist/schema-generator/resolver-collector/resolver-collector.d.ts.map +1 -1
- package/dist/schema-generator/resolver-collector/resolver-collector.js +22 -0
- package/dist/schema-generator/resolver-collector/resolver-collector.js.map +1 -1
- package/dist/shared/branded-type-detector.d.ts +43 -0
- package/dist/shared/branded-type-detector.d.ts.map +1 -0
- package/dist/shared/branded-type-detector.js +146 -0
- package/dist/shared/branded-type-detector.js.map +1 -0
- package/dist/shared/enum-prefix-detector.d.ts +63 -0
- package/dist/shared/enum-prefix-detector.d.ts.map +1 -0
- package/dist/shared/enum-prefix-detector.js +80 -0
- package/dist/shared/enum-prefix-detector.js.map +1 -0
- package/dist/shared/ignore-fields-detector.d.ts +26 -0
- package/dist/shared/ignore-fields-detector.d.ts.map +1 -0
- package/dist/shared/ignore-fields-detector.js +83 -0
- package/dist/shared/ignore-fields-detector.js.map +1 -0
- package/dist/shared/ignore-fields-validator.d.ts +29 -0
- package/dist/shared/ignore-fields-validator.d.ts.map +1 -0
- package/dist/shared/ignore-fields-validator.js +43 -0
- package/dist/shared/ignore-fields-validator.js.map +1 -0
- package/dist/shared/index.d.ts +2 -0
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/source-location.d.ts +5 -0
- package/dist/shared/source-location.d.ts.map +1 -1
- package/dist/shared/source-location.js +7 -0
- package/dist/shared/source-location.js.map +1 -1
- package/dist/shared/string-utils.d.ts +2 -0
- package/dist/shared/string-utils.d.ts.map +1 -0
- package/dist/shared/string-utils.js +8 -0
- package/dist/shared/string-utils.js.map +1 -0
- package/dist/type-extractor/converter/field-eligibility.d.ts +8 -6
- package/dist/type-extractor/converter/field-eligibility.d.ts.map +1 -1
- package/dist/type-extractor/converter/field-eligibility.js +7 -28
- package/dist/type-extractor/converter/field-eligibility.js.map +1 -1
- package/dist/type-extractor/converter/graphql-converter.d.ts.map +1 -1
- package/dist/type-extractor/converter/graphql-converter.js +27 -18
- package/dist/type-extractor/converter/graphql-converter.js.map +1 -1
- package/dist/type-extractor/extractor/field-type-resolver.d.ts.map +1 -1
- package/dist/type-extractor/extractor/field-type-resolver.js +81 -7
- package/dist/type-extractor/extractor/field-type-resolver.js.map +1 -1
- package/dist/type-extractor/extractor/type-extractor.d.ts.map +1 -1
- package/dist/type-extractor/extractor/type-extractor.js +88 -23
- package/dist/type-extractor/extractor/type-extractor.js.map +1 -1
- package/dist/type-extractor/types/diagnostics.d.ts +1 -1
- package/dist/type-extractor/types/diagnostics.d.ts.map +1 -1
- package/dist/type-extractor/types/ts-type-reference-factory.d.ts +10 -2
- package/dist/type-extractor/types/ts-type-reference-factory.d.ts.map +1 -1
- package/dist/type-extractor/types/ts-type-reference-factory.js +8 -2
- package/dist/type-extractor/types/ts-type-reference-factory.js.map +1 -1
- package/dist/type-extractor/types/typescript.d.ts +4 -0
- package/dist/type-extractor/types/typescript.d.ts.map +1 -1
- package/dist/type-extractor/validator/type-validator.d.ts +1 -1
- package/dist/type-extractor/validator/type-validator.d.ts.map +1 -1
- package/dist/type-extractor/validator/type-validator.js +2 -10
- package/dist/type-extractor/validator/type-validator.js.map +1 -1
- package/docs/coding-agents.md +64 -0
- package/docs/configuration.md +15 -20
- package/docs/getting-started.md +15 -12
- package/docs/index.md +36 -22
- package/docs/integration/apollo.md +8 -40
- package/docs/integration/drizzle.md +6 -10
- package/docs/integration/prisma.md +196 -0
- package/docs/integration/yoga.md +8 -40
- package/docs/schema/abstract-resolvers.md +117 -0
- package/docs/schema/directives.md +5 -0
- package/docs/schema/documentation.md +5 -0
- package/docs/schema/enums.md +99 -0
- package/docs/schema/fields.md +64 -0
- package/docs/schema/index.md +21 -0
- package/docs/schema/inputs.md +115 -15
- package/docs/schema/interfaces.md +31 -1
- package/docs/schema/objects.md +40 -0
- package/docs/schema/queries-mutations.md +136 -22
- package/docs/schema/scalars.md +5 -0
- package/docs/schema/unions.md +208 -1
- package/docs/what-is-gqlkit.md +13 -8
- package/package.json +6 -4
- package/src/auto-type-generator/auto-type-generator.ts +969 -227
- package/src/auto-type-generator/index.ts +42 -0
- package/src/auto-type-generator/inline-enum-collector.ts +187 -139
- package/src/auto-type-generator/inline-object-traverser.ts +49 -0
- package/src/auto-type-generator/inline-union-collector.ts +402 -0
- package/src/auto-type-generator/inline-union-types.ts +33 -0
- package/src/auto-type-generator/inline-union-validator.ts +482 -0
- package/src/auto-type-generator/naming-convention.ts +38 -1
- package/src/auto-type-generator/resolve-type-generator.ts +21 -0
- package/src/auto-type-generator/resolver-field-iterator.ts +39 -0
- package/src/auto-type-generator/typename-extractor.ts +230 -0
- package/src/auto-type-generator/typename-resolve-type-generator.ts +281 -0
- package/src/auto-type-generator/typename-types.ts +66 -0
- package/src/auto-type-generator/typename-validator.ts +326 -0
- package/src/cli.ts +2 -0
- package/src/commands/docs.ts +211 -0
- package/src/config/types.ts +15 -0
- package/src/config-loader/loader.ts +4 -0
- package/src/config-loader/validator.ts +33 -0
- package/src/gen-orchestrator/orchestrator.ts +50 -17
- package/src/resolver-extractor/extract-resolvers.ts +19 -0
- package/src/resolver-extractor/extractor/define-api-extractor.ts +28 -94
- package/src/resolver-extractor/index.ts +0 -6
- package/src/resolver-extractor/validator/abstract-resolver-validator.ts +16 -8
- package/src/schema-generator/builder/ast-builder.ts +52 -81
- package/src/schema-generator/emitter/code-emitter.ts +82 -11
- package/src/schema-generator/emitter/sdl-emitter.ts +0 -4
- package/src/schema-generator/generate-schema.ts +109 -14
- package/src/schema-generator/integrator/result-integrator.ts +91 -63
- package/src/schema-generator/resolver-collector/resolver-collector.ts +34 -0
- package/src/shared/branded-type-detector.ts +182 -0
- package/src/shared/enum-prefix-detector.ts +99 -0
- package/src/shared/ignore-fields-detector.ts +109 -0
- package/src/shared/ignore-fields-validator.ts +66 -0
- package/src/shared/index.ts +2 -0
- package/src/shared/source-location.ts +11 -0
- package/src/shared/string-utils.ts +7 -0
- package/src/type-extractor/converter/field-eligibility.ts +13 -29
- package/src/type-extractor/converter/graphql-converter.ts +37 -23
- package/src/type-extractor/extractor/field-type-resolver.ts +97 -7
- package/src/type-extractor/extractor/type-extractor.ts +103 -26
- package/src/type-extractor/types/diagnostics.ts +13 -2
- package/src/type-extractor/types/ts-type-reference-factory.ts +18 -5
- package/src/type-extractor/types/typescript.ts +4 -0
- package/src/type-extractor/validator/type-validator.ts +2 -15
- package/dist/resolver-extractor/validator/only-validator.d.ts +0 -61
- package/dist/resolver-extractor/validator/only-validator.d.ts.map +0 -1
- package/dist/resolver-extractor/validator/only-validator.js +0 -76
- package/dist/resolver-extractor/validator/only-validator.js.map +0 -1
- package/src/resolver-extractor/validator/only-validator.ts +0 -158
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
AutoGeneratedType,
|
|
3
|
+
ResolveTypeFieldPattern,
|
|
4
|
+
} from "../../auto-type-generator/index.js";
|
|
5
|
+
import type { TypenameAutoResolveTypeInfo } from "../../auto-type-generator/typename-resolve-type-generator.js";
|
|
6
|
+
import { createFieldNameSet } from "../../auto-type-generator/typename-types.js";
|
|
2
7
|
import type {
|
|
3
8
|
AbstractResolverInfo,
|
|
4
9
|
ExtractResolversResult,
|
|
@@ -121,21 +126,22 @@ export interface StringEnumMappingInfo {
|
|
|
121
126
|
readonly members: ReadonlyArray<StringEnumMember>;
|
|
122
127
|
}
|
|
123
128
|
|
|
129
|
+
export interface AutoGeneratedUnionInfo {
|
|
130
|
+
readonly name: string;
|
|
131
|
+
readonly fieldPattern: ResolveTypeFieldPattern;
|
|
132
|
+
readonly hasAutoResolveType: boolean;
|
|
133
|
+
}
|
|
134
|
+
|
|
124
135
|
export interface IntegratedResult {
|
|
125
136
|
readonly baseTypes: ReadonlyArray<BaseType>;
|
|
126
137
|
readonly inputTypes: ReadonlyArray<InputType>;
|
|
127
138
|
readonly typeExtensions: ReadonlyArray<TypeExtension>;
|
|
128
|
-
/** @deprecated Use customScalars instead */
|
|
129
|
-
readonly customScalarNames: ReadonlyArray<string> | null;
|
|
130
|
-
/** Custom scalars with description information */
|
|
131
139
|
readonly customScalars: ReadonlyArray<CustomScalarInfo> | null;
|
|
132
|
-
/** Directive definitions extracted from type aliases */
|
|
133
140
|
readonly directiveDefinitions: ReadonlyArray<DirectiveDefinitionInfo> | null;
|
|
134
|
-
/** Abstract type resolvers (resolveType and isTypeOf) */
|
|
135
141
|
readonly abstractTypeResolvers: ReadonlyArray<AbstractResolverInfo>;
|
|
136
|
-
|
|
142
|
+
readonly autoGeneratedUnions: ReadonlyArray<AutoGeneratedUnionInfo>;
|
|
143
|
+
readonly typenameAutoResolveTypes: ReadonlyArray<TypenameAutoResolveTypeInfo>;
|
|
137
144
|
readonly numericEnums: ReadonlyArray<NumericEnumInfo>;
|
|
138
|
-
/** String enum mappings for resolver generation */
|
|
139
145
|
readonly stringEnumMappings: ReadonlyArray<StringEnumMappingInfo>;
|
|
140
146
|
readonly hasQuery: boolean;
|
|
141
147
|
readonly hasMutation: boolean;
|
|
@@ -143,6 +149,17 @@ export interface IntegratedResult {
|
|
|
143
149
|
readonly diagnostics: ReadonlyArray<Diagnostic>;
|
|
144
150
|
}
|
|
145
151
|
|
|
152
|
+
function toBaseField(field: BaseField): BaseField {
|
|
153
|
+
return {
|
|
154
|
+
name: field.name,
|
|
155
|
+
type: field.type,
|
|
156
|
+
description: field.description,
|
|
157
|
+
deprecated: field.deprecated,
|
|
158
|
+
directives: field.directives,
|
|
159
|
+
defaultValue: field.defaultValue,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
146
163
|
function convertToExtensionField(
|
|
147
164
|
field: GraphQLFieldDefinition,
|
|
148
165
|
): ExtensionField {
|
|
@@ -250,14 +267,26 @@ function getCompatibleLocations(
|
|
|
250
267
|
}
|
|
251
268
|
}
|
|
252
269
|
|
|
253
|
-
export
|
|
254
|
-
typesResult: ExtractTypesResult
|
|
255
|
-
resolversResult: ExtractResolversResult
|
|
256
|
-
customScalarNames: ReadonlyArray<string> | null
|
|
257
|
-
collectedScalars
|
|
258
|
-
directiveDefinitions
|
|
259
|
-
autoGeneratedTypes
|
|
260
|
-
|
|
270
|
+
export interface IntegrateParams {
|
|
271
|
+
readonly typesResult: ExtractTypesResult;
|
|
272
|
+
readonly resolversResult: ExtractResolversResult;
|
|
273
|
+
readonly customScalarNames: ReadonlyArray<string> | null;
|
|
274
|
+
readonly collectedScalars: ReadonlyArray<CollectedScalarType> | null;
|
|
275
|
+
readonly directiveDefinitions: ReadonlyArray<DirectiveDefinitionInfo> | null;
|
|
276
|
+
readonly autoGeneratedTypes: ReadonlyArray<AutoGeneratedType> | null;
|
|
277
|
+
readonly typenameAutoResolveTypes: ReadonlyArray<TypenameAutoResolveTypeInfo> | null;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export function integrate(params: IntegrateParams): IntegratedResult {
|
|
281
|
+
const {
|
|
282
|
+
typesResult,
|
|
283
|
+
resolversResult,
|
|
284
|
+
customScalarNames,
|
|
285
|
+
collectedScalars,
|
|
286
|
+
directiveDefinitions,
|
|
287
|
+
autoGeneratedTypes,
|
|
288
|
+
typenameAutoResolveTypes,
|
|
289
|
+
} = params;
|
|
261
290
|
const directiveTypeAliasNames = new Set(
|
|
262
291
|
directiveDefinitions?.map((d) => d.typeAliasName) ?? [],
|
|
263
292
|
);
|
|
@@ -281,20 +310,14 @@ export function integrate(
|
|
|
281
310
|
|
|
282
311
|
const baseTypes: BaseType[] = [];
|
|
283
312
|
const inputTypes: InputType[] = [];
|
|
313
|
+
const autoGeneratedUnions: AutoGeneratedUnionInfo[] = [];
|
|
284
314
|
|
|
285
315
|
for (const autoType of autoGeneratedTypes ?? []) {
|
|
286
316
|
if (autoType.kind === "Object") {
|
|
287
317
|
baseTypes.push({
|
|
288
318
|
name: autoType.name,
|
|
289
319
|
kind: "Object",
|
|
290
|
-
fields: autoType.fields!.map(
|
|
291
|
-
name: f.name,
|
|
292
|
-
type: f.type,
|
|
293
|
-
description: f.description,
|
|
294
|
-
deprecated: f.deprecated,
|
|
295
|
-
directives: f.directives,
|
|
296
|
-
defaultValue: f.defaultValue,
|
|
297
|
-
})),
|
|
320
|
+
fields: autoType.fields!.map(toBaseField),
|
|
298
321
|
unionMembers: null,
|
|
299
322
|
enumValues: null,
|
|
300
323
|
isNumericEnum: false,
|
|
@@ -327,17 +350,40 @@ export function integrate(
|
|
|
327
350
|
sourceFile: autoType.sourceLocation.file,
|
|
328
351
|
directives: null,
|
|
329
352
|
});
|
|
353
|
+
} else if (autoType.kind === "Union") {
|
|
354
|
+
baseTypes.push({
|
|
355
|
+
name: autoType.name,
|
|
356
|
+
kind: "Union",
|
|
357
|
+
fields: null,
|
|
358
|
+
unionMembers: autoType.unionMembers ?? [],
|
|
359
|
+
enumValues: null,
|
|
360
|
+
isNumericEnum: false,
|
|
361
|
+
needsStringEnumMapping: false,
|
|
362
|
+
implementedInterfaces: null,
|
|
363
|
+
description: autoType.description,
|
|
364
|
+
deprecated: null,
|
|
365
|
+
sourceFile: autoType.sourceLocation.file,
|
|
366
|
+
directives: null,
|
|
367
|
+
});
|
|
368
|
+
autoGeneratedUnions.push({
|
|
369
|
+
name: autoType.name,
|
|
370
|
+
fieldPattern: autoType.resolveTypeFieldPattern ?? {
|
|
371
|
+
usedFieldNames: createFieldNameSet(["__typename"]),
|
|
372
|
+
},
|
|
373
|
+
hasAutoResolveType: autoType.resolveTypeFieldPattern !== null,
|
|
374
|
+
});
|
|
375
|
+
} else if (autoType.kind === "OneOfInputObject") {
|
|
376
|
+
inputTypes.push({
|
|
377
|
+
name: autoType.name,
|
|
378
|
+
fields: autoType.fields!.map(toBaseField),
|
|
379
|
+
sourceFile: autoType.sourceLocation.file,
|
|
380
|
+
description: autoType.description,
|
|
381
|
+
isOneOf: true,
|
|
382
|
+
});
|
|
330
383
|
} else {
|
|
331
384
|
inputTypes.push({
|
|
332
385
|
name: autoType.name,
|
|
333
|
-
fields: autoType.fields!.map(
|
|
334
|
-
name: f.name,
|
|
335
|
-
type: f.type,
|
|
336
|
-
description: f.description,
|
|
337
|
-
deprecated: f.deprecated,
|
|
338
|
-
directives: f.directives,
|
|
339
|
-
defaultValue: f.defaultValue,
|
|
340
|
-
})),
|
|
386
|
+
fields: autoType.fields!.map(toBaseField),
|
|
341
387
|
sourceFile: autoType.sourceLocation.file,
|
|
342
388
|
description: autoType.description,
|
|
343
389
|
isOneOf: false,
|
|
@@ -353,15 +399,7 @@ export function integrate(
|
|
|
353
399
|
if (type.kind === "InputObject" || type.kind === "OneOfInputObject") {
|
|
354
400
|
inputTypes.push({
|
|
355
401
|
name: type.name,
|
|
356
|
-
fields:
|
|
357
|
-
type.fields?.map((field) => ({
|
|
358
|
-
name: field.name,
|
|
359
|
-
type: field.type,
|
|
360
|
-
description: field.description,
|
|
361
|
-
deprecated: field.deprecated,
|
|
362
|
-
directives: field.directives,
|
|
363
|
-
defaultValue: field.defaultValue,
|
|
364
|
-
})) ?? [],
|
|
402
|
+
fields: type.fields?.map(toBaseField) ?? [],
|
|
365
403
|
sourceFile: type.sourceFile,
|
|
366
404
|
description: type.description,
|
|
367
405
|
isOneOf: type.kind === "OneOfInputObject",
|
|
@@ -385,15 +423,7 @@ export function integrate(
|
|
|
385
423
|
baseTypes.push({
|
|
386
424
|
name: type.name,
|
|
387
425
|
kind: type.kind,
|
|
388
|
-
fields:
|
|
389
|
-
type.fields?.map((field) => ({
|
|
390
|
-
name: field.name,
|
|
391
|
-
type: field.type,
|
|
392
|
-
description: field.description,
|
|
393
|
-
deprecated: field.deprecated,
|
|
394
|
-
directives: field.directives,
|
|
395
|
-
defaultValue: field.defaultValue,
|
|
396
|
-
})) ?? null,
|
|
426
|
+
fields: type.fields?.map(toBaseField) ?? null,
|
|
397
427
|
unionMembers: null,
|
|
398
428
|
enumValues: null,
|
|
399
429
|
isNumericEnum: false,
|
|
@@ -408,15 +438,7 @@ export function integrate(
|
|
|
408
438
|
baseTypes.push({
|
|
409
439
|
name: type.name,
|
|
410
440
|
kind: type.kind,
|
|
411
|
-
fields:
|
|
412
|
-
type.fields?.map((field) => ({
|
|
413
|
-
name: field.name,
|
|
414
|
-
type: field.type,
|
|
415
|
-
description: field.description,
|
|
416
|
-
deprecated: field.deprecated,
|
|
417
|
-
directives: field.directives,
|
|
418
|
-
defaultValue: field.defaultValue,
|
|
419
|
-
})) ?? null,
|
|
441
|
+
fields: type.fields?.map(toBaseField) ?? null,
|
|
420
442
|
unionMembers: null,
|
|
421
443
|
enumValues: null,
|
|
422
444
|
isNumericEnum: false,
|
|
@@ -481,9 +503,17 @@ export function integrate(
|
|
|
481
503
|
});
|
|
482
504
|
}
|
|
483
505
|
|
|
506
|
+
const typenameAutoResolveTypeNames = new Set([
|
|
507
|
+
...(typenameAutoResolveTypes?.map((t) => t.abstractTypeName) ?? []),
|
|
508
|
+
...autoGeneratedUnions
|
|
509
|
+
.filter((u) => u.hasAutoResolveType)
|
|
510
|
+
.map((u) => u.name),
|
|
511
|
+
]);
|
|
512
|
+
|
|
484
513
|
const abstractResolverValidation = validateAbstractResolvers({
|
|
485
514
|
abstractResolvers: resolversResult.abstractTypeResolvers,
|
|
486
515
|
baseTypes,
|
|
516
|
+
typenameAutoResolveTypeNames,
|
|
487
517
|
});
|
|
488
518
|
diagnostics.push(...abstractResolverValidation.diagnostics);
|
|
489
519
|
|
|
@@ -670,16 +700,14 @@ export function integrate(
|
|
|
670
700
|
baseTypes,
|
|
671
701
|
inputTypes,
|
|
672
702
|
typeExtensions,
|
|
673
|
-
customScalarNames:
|
|
674
|
-
customScalarNames && customScalarNames.length > 0
|
|
675
|
-
? customScalarNames
|
|
676
|
-
: null,
|
|
677
703
|
customScalars,
|
|
678
704
|
directiveDefinitions:
|
|
679
705
|
directiveDefinitions && directiveDefinitions.length > 0
|
|
680
706
|
? directiveDefinitions
|
|
681
707
|
: null,
|
|
682
708
|
abstractTypeResolvers: resolversResult.abstractTypeResolvers,
|
|
709
|
+
autoGeneratedUnions,
|
|
710
|
+
typenameAutoResolveTypes: typenameAutoResolveTypes ?? [],
|
|
683
711
|
numericEnums,
|
|
684
712
|
stringEnumMappings,
|
|
685
713
|
hasQuery,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AutoGeneratedResolveType } from "../../auto-type-generator/resolve-type-generator.js";
|
|
1
2
|
import type { AbstractResolverInfo } from "../../resolver-extractor/extractor/define-api-extractor.js";
|
|
2
3
|
import type {
|
|
3
4
|
ExtensionField,
|
|
@@ -28,6 +29,7 @@ export interface ResolverInfo {
|
|
|
28
29
|
readonly types: ReadonlyArray<TypeResolvers>;
|
|
29
30
|
readonly sourceFiles: ReadonlyArray<string>;
|
|
30
31
|
readonly abstractTypeResolvers: ReadonlyArray<AbstractTypeResolverInfo>;
|
|
32
|
+
readonly autoGeneratedResolveTypes: ReadonlyArray<AutoGeneratedResolveType>;
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
function getResolverValueName(typeName: string): string {
|
|
@@ -104,6 +106,37 @@ export function collectResolverInfo(
|
|
|
104
106
|
sourceFilesSet.add(resolver.sourceFile);
|
|
105
107
|
}
|
|
106
108
|
|
|
109
|
+
const manualResolveTypeNames = new Set<string>(
|
|
110
|
+
abstractTypeResolvers
|
|
111
|
+
.filter((r) => r.resolverKey === "__resolveType")
|
|
112
|
+
.map((r) => r.typeName),
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
const inlineUnionResolveTypes: AutoGeneratedResolveType[] =
|
|
116
|
+
integratedResult.autoGeneratedUnions
|
|
117
|
+
.filter(
|
|
118
|
+
(u) => u.hasAutoResolveType && !manualResolveTypeNames.has(u.name),
|
|
119
|
+
)
|
|
120
|
+
.map((u) => ({
|
|
121
|
+
unionTypeName: u.name,
|
|
122
|
+
fieldPattern: u.fieldPattern,
|
|
123
|
+
}));
|
|
124
|
+
|
|
125
|
+
const typenameResolveTypes: AutoGeneratedResolveType[] =
|
|
126
|
+
integratedResult.typenameAutoResolveTypes
|
|
127
|
+
.filter((t) => !manualResolveTypeNames.has(t.abstractTypeName))
|
|
128
|
+
.map((t) => ({
|
|
129
|
+
unionTypeName: t.abstractTypeName,
|
|
130
|
+
fieldPattern: {
|
|
131
|
+
usedFieldNames: t.resolveTypePattern.usedFieldNames,
|
|
132
|
+
},
|
|
133
|
+
}));
|
|
134
|
+
|
|
135
|
+
const autoGeneratedResolveTypes = [
|
|
136
|
+
...inlineUnionResolveTypes,
|
|
137
|
+
...typenameResolveTypes,
|
|
138
|
+
].sort((a, b) => a.unionTypeName.localeCompare(b.unionTypeName));
|
|
139
|
+
|
|
107
140
|
const types: TypeResolvers[] = [...typeMap.entries()]
|
|
108
141
|
.map(([typeName, fields]) => ({
|
|
109
142
|
typeName,
|
|
@@ -119,5 +152,6 @@ export function collectResolverInfo(
|
|
|
119
152
|
types,
|
|
120
153
|
sourceFiles,
|
|
121
154
|
abstractTypeResolvers,
|
|
155
|
+
autoGeneratedResolveTypes,
|
|
122
156
|
};
|
|
123
157
|
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Branded type detector.
|
|
3
|
+
*
|
|
4
|
+
* This module provides functions to detect branded type patterns in TypeScript
|
|
5
|
+
* intersection types and extract the underlying primitive type.
|
|
6
|
+
*
|
|
7
|
+
* Branded types are intersection types combining a primitive with a marker object:
|
|
8
|
+
* - `string & { __brand: 'UserId' }`
|
|
9
|
+
* - `number & { readonly __brand: unique symbol }`
|
|
10
|
+
* - `boolean & { __nominal: true }`
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import ts from "typescript";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Result of branded type detection.
|
|
17
|
+
*/
|
|
18
|
+
export interface BrandedTypeResult {
|
|
19
|
+
/** Whether the type is a branded primitive type */
|
|
20
|
+
readonly isBranded: boolean;
|
|
21
|
+
/** The base primitive type if branded, null otherwise */
|
|
22
|
+
readonly baseType: "string" | "number" | "boolean" | null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Property names commonly used as brand markers.
|
|
27
|
+
* These indicate the type is a branded type, not an actual object.
|
|
28
|
+
*/
|
|
29
|
+
const BRAND_PROPERTY_NAMES: ReadonlySet<string> = new Set([
|
|
30
|
+
"__brand",
|
|
31
|
+
"_brand",
|
|
32
|
+
"brand",
|
|
33
|
+
"__nominal",
|
|
34
|
+
"_nominal",
|
|
35
|
+
"__tag",
|
|
36
|
+
"_tag",
|
|
37
|
+
"__type",
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Property names to exclude from brand detection.
|
|
42
|
+
* These are used by gqlkit for scalar metadata, not branding.
|
|
43
|
+
*/
|
|
44
|
+
const EXCLUDED_BRAND_PROPERTIES: ReadonlySet<string> = new Set([
|
|
45
|
+
" $gqlkitScalar",
|
|
46
|
+
]);
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Detects if a type is a branded primitive type.
|
|
50
|
+
*
|
|
51
|
+
* A branded type is an intersection type where:
|
|
52
|
+
* 1. One member is a primitive type (string, number, or boolean)
|
|
53
|
+
* 2. Other members are pure brand markers (objects with only brand properties)
|
|
54
|
+
*
|
|
55
|
+
* @param type - The TypeScript type to analyze
|
|
56
|
+
* @returns Detection result with isBranded flag and baseType
|
|
57
|
+
*/
|
|
58
|
+
export function detectBrandedType(type: ts.Type): BrandedTypeResult {
|
|
59
|
+
const notBranded: BrandedTypeResult = { isBranded: false, baseType: null };
|
|
60
|
+
|
|
61
|
+
if (!type.isIntersection()) {
|
|
62
|
+
return notBranded;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let primitiveBase: "string" | "number" | "boolean" | null = null;
|
|
66
|
+
let hasNonBrandMember = false;
|
|
67
|
+
|
|
68
|
+
for (const member of type.types) {
|
|
69
|
+
const primitiveType = getPrimitiveType(member);
|
|
70
|
+
if (primitiveType !== null) {
|
|
71
|
+
if (primitiveBase !== null && primitiveBase !== primitiveType) {
|
|
72
|
+
// Multiple different primitive types - not a valid branded type
|
|
73
|
+
return notBranded;
|
|
74
|
+
}
|
|
75
|
+
primitiveBase = primitiveType;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Check if this member is a pure brand marker
|
|
80
|
+
if (!isPureBrandMarker(member)) {
|
|
81
|
+
hasNonBrandMember = true;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (hasNonBrandMember || primitiveBase === null) {
|
|
87
|
+
return notBranded;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return { isBranded: true, baseType: primitiveBase };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Detects if all types in the array are branded with the same base type.
|
|
95
|
+
*
|
|
96
|
+
* This is useful for union types where branded boolean expands to:
|
|
97
|
+
* `(true & { __nominal: true }) | (false & { __nominal: true })`
|
|
98
|
+
*
|
|
99
|
+
* @param types - Array of TypeScript types to analyze
|
|
100
|
+
* @returns Common branded result if all types are branded with the same base, otherwise non-branded
|
|
101
|
+
*/
|
|
102
|
+
export function detectUniformBrandedType(
|
|
103
|
+
types: ReadonlyArray<ts.Type>,
|
|
104
|
+
): BrandedTypeResult {
|
|
105
|
+
if (types.length === 0) {
|
|
106
|
+
return { isBranded: false, baseType: null };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const first = detectBrandedType(types[0]!);
|
|
110
|
+
if (!first.isBranded) {
|
|
111
|
+
return { isBranded: false, baseType: null };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
for (let i = 1; i < types.length; i++) {
|
|
115
|
+
const result = detectBrandedType(types[i]!);
|
|
116
|
+
if (!result.isBranded || result.baseType !== first.baseType) {
|
|
117
|
+
return { isBranded: false, baseType: null };
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return first;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Gets the primitive type from a TypeScript type.
|
|
126
|
+
*
|
|
127
|
+
* @returns "string", "number", "boolean", or null if not a primitive
|
|
128
|
+
*/
|
|
129
|
+
function getPrimitiveType(
|
|
130
|
+
type: ts.Type,
|
|
131
|
+
): "string" | "number" | "boolean" | null {
|
|
132
|
+
if (type.flags & ts.TypeFlags.String) {
|
|
133
|
+
return "string";
|
|
134
|
+
}
|
|
135
|
+
if (type.flags & ts.TypeFlags.Number) {
|
|
136
|
+
return "number";
|
|
137
|
+
}
|
|
138
|
+
if (
|
|
139
|
+
type.flags & ts.TypeFlags.Boolean ||
|
|
140
|
+
type.flags & ts.TypeFlags.BooleanLiteral
|
|
141
|
+
) {
|
|
142
|
+
return "boolean";
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Checks if a type is a pure brand marker.
|
|
149
|
+
*
|
|
150
|
+
* A pure brand marker is an object type where all properties are
|
|
151
|
+
* brand-related (e.g., __brand, __nominal, __tag).
|
|
152
|
+
*
|
|
153
|
+
* @param type - The type to check
|
|
154
|
+
* @returns true if the type is a pure brand marker
|
|
155
|
+
*/
|
|
156
|
+
function isPureBrandMarker(type: ts.Type): boolean {
|
|
157
|
+
if (!(type.flags & ts.TypeFlags.Object)) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const properties = type.getProperties();
|
|
162
|
+
if (properties.length === 0) {
|
|
163
|
+
// Empty object is not a brand marker
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
for (const prop of properties) {
|
|
168
|
+
const propName = prop.getName();
|
|
169
|
+
|
|
170
|
+
// Excluded properties (like gqlkit metadata) disqualify as brand marker
|
|
171
|
+
if (EXCLUDED_BRAND_PROPERTIES.has(propName)) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// If any property is not a brand property, this is not a pure brand marker
|
|
176
|
+
if (!BRAND_PROPERTY_NAMES.has(propName)) {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts an enum name from any naming convention to UPPER_SNAKE_CASE.
|
|
3
|
+
*
|
|
4
|
+
* Supports PascalCase, camelCase, UPPER_SNAKE_CASE, and single word inputs.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* toUpperSnakeCase("UserStatus") // => "USER_STATUS"
|
|
8
|
+
* toUpperSnakeCase("userStatus") // => "USER_STATUS"
|
|
9
|
+
* toUpperSnakeCase("USER_STATUS") // => "USER_STATUS"
|
|
10
|
+
* toUpperSnakeCase("Status") // => "STATUS"
|
|
11
|
+
*/
|
|
12
|
+
export function toUpperSnakeCase(name: string): string {
|
|
13
|
+
return name
|
|
14
|
+
.replace(/([a-z])([A-Z])/g, "$1_$2")
|
|
15
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2")
|
|
16
|
+
.toUpperCase();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Builds the prefix candidate string for enum prefix stripping.
|
|
21
|
+
*
|
|
22
|
+
* Converts the enum name to UPPER_SNAKE_CASE and appends "_" to create
|
|
23
|
+
* the prefix that will be checked against all enum values.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* buildEnumPrefixCandidate("UserStatus") // => "USER_STATUS_"
|
|
27
|
+
* buildEnumPrefixCandidate("userStatus") // => "USER_STATUS_"
|
|
28
|
+
* buildEnumPrefixCandidate("USER_STATUS") // => "USER_STATUS_"
|
|
29
|
+
* buildEnumPrefixCandidate("Status") // => "STATUS_"
|
|
30
|
+
*/
|
|
31
|
+
export function buildEnumPrefixCandidate(enumName: string): string {
|
|
32
|
+
return `${toUpperSnakeCase(enumName)}_`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface DetectEnumPrefixParams {
|
|
36
|
+
readonly enumName: string;
|
|
37
|
+
readonly memberValues: ReadonlyArray<string>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface DetectEnumPrefixResult {
|
|
41
|
+
readonly shouldStrip: boolean;
|
|
42
|
+
readonly prefix: string | null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Detects whether an enum is a candidate for prefix stripping.
|
|
47
|
+
*
|
|
48
|
+
* Conditions for stripping:
|
|
49
|
+
* 1. All memberValues must start with `${toUpperSnakeCase(enumName)}_`
|
|
50
|
+
* 2. After removing the prefix, the remaining string must be non-empty
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* detectEnumPrefix({
|
|
54
|
+
* enumName: "UserStatus",
|
|
55
|
+
* memberValues: ["USER_STATUS_ACTIVE", "USER_STATUS_INACTIVE"]
|
|
56
|
+
* })
|
|
57
|
+
* // => { shouldStrip: true, prefix: "USER_STATUS_" }
|
|
58
|
+
*
|
|
59
|
+
* detectEnumPrefix({
|
|
60
|
+
* enumName: "UserStatus",
|
|
61
|
+
* memberValues: ["ACTIVE", "INACTIVE"]
|
|
62
|
+
* })
|
|
63
|
+
* // => { shouldStrip: false, prefix: null }
|
|
64
|
+
*/
|
|
65
|
+
export function detectEnumPrefix(
|
|
66
|
+
params: DetectEnumPrefixParams,
|
|
67
|
+
): DetectEnumPrefixResult {
|
|
68
|
+
const { enumName, memberValues } = params;
|
|
69
|
+
|
|
70
|
+
if (memberValues.length === 0) {
|
|
71
|
+
return { shouldStrip: false, prefix: null };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const prefixCandidate = buildEnumPrefixCandidate(enumName);
|
|
75
|
+
|
|
76
|
+
for (const value of memberValues) {
|
|
77
|
+
if (!value.startsWith(prefixCandidate)) {
|
|
78
|
+
return { shouldStrip: false, prefix: null };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const stripped = value.slice(prefixCandidate.length);
|
|
82
|
+
if (stripped === "") {
|
|
83
|
+
return { shouldStrip: false, prefix: null };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return { shouldStrip: true, prefix: prefixCandidate };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Removes the detected prefix from an enum value.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* stripEnumPrefix("USER_STATUS_ACTIVE", "USER_STATUS_")
|
|
95
|
+
* // => "ACTIVE"
|
|
96
|
+
*/
|
|
97
|
+
export function stripEnumPrefix(value: string, prefix: string): string {
|
|
98
|
+
return value.slice(prefix.length);
|
|
99
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IgnoreFields metadata detector.
|
|
3
|
+
*
|
|
4
|
+
* This module provides functions to detect ignoreFields metadata embedded
|
|
5
|
+
* in TypeScript intersection types using the $gqlkitTypeMeta property.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import ts from "typescript";
|
|
9
|
+
import { METADATA_PROPERTIES } from "./constants.js";
|
|
10
|
+
import { getActualMetadataType } from "./metadata-detector.js";
|
|
11
|
+
|
|
12
|
+
const TYPE_META_PROPERTY = METADATA_PROPERTIES.TYPE_META;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Parameters for detectIgnoreFieldsMetadata function.
|
|
16
|
+
*/
|
|
17
|
+
export interface DetectIgnoreFieldsParams {
|
|
18
|
+
readonly type: ts.Type;
|
|
19
|
+
readonly checker: ts.TypeChecker;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Extracts ignoreFields from a type's metadata.
|
|
24
|
+
* Returns null if the type doesn't have $gqlkitTypeMeta or ignoreFields is not specified.
|
|
25
|
+
*/
|
|
26
|
+
function extractIgnoreFieldsFromType(
|
|
27
|
+
type: ts.Type,
|
|
28
|
+
checker: ts.TypeChecker,
|
|
29
|
+
): ReadonlySet<string> | null {
|
|
30
|
+
const metaProp = type.getProperty(TYPE_META_PROPERTY);
|
|
31
|
+
if (!metaProp) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const rawMetadataType = checker.getTypeOfSymbol(metaProp);
|
|
36
|
+
const metadataType = getActualMetadataType(rawMetadataType);
|
|
37
|
+
if (!metadataType) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const ignoreFieldsProp = metadataType.getProperty("ignoreFields");
|
|
42
|
+
if (!ignoreFieldsProp) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const rawIgnoreFieldsType = checker.getTypeOfSymbol(ignoreFieldsProp);
|
|
47
|
+
const ignoreFieldsType = getActualMetadataType(rawIgnoreFieldsType);
|
|
48
|
+
if (!ignoreFieldsType) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return extractStringLiteralUnion(ignoreFieldsType);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Extracts string literals from a type (single literal or union of literals).
|
|
57
|
+
*/
|
|
58
|
+
function extractStringLiteralUnion(type: ts.Type): ReadonlySet<string> | null {
|
|
59
|
+
if (type.flags & ts.TypeFlags.StringLiteral) {
|
|
60
|
+
const value = (type as ts.StringLiteralType).value;
|
|
61
|
+
return new Set([value]);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (type.isUnion()) {
|
|
65
|
+
const values = new Set<string>();
|
|
66
|
+
for (const member of type.types) {
|
|
67
|
+
if (member.flags & ts.TypeFlags.StringLiteral) {
|
|
68
|
+
values.add((member as ts.StringLiteralType).value);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (values.size > 0) {
|
|
72
|
+
return values;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Detects ignoreFields metadata from a TypeScript type.
|
|
81
|
+
*
|
|
82
|
+
* This function analyzes TypeScript types to detect ignoreFields metadata
|
|
83
|
+
* from the $gqlkitTypeMeta property. It extracts string literal or string
|
|
84
|
+
* literal union types and returns them as a Set.
|
|
85
|
+
*
|
|
86
|
+
* @param params - The detection parameters containing type and checker
|
|
87
|
+
* @returns The ignoreFields set or null if not specified
|
|
88
|
+
*/
|
|
89
|
+
export function detectIgnoreFieldsMetadata(
|
|
90
|
+
params: DetectIgnoreFieldsParams,
|
|
91
|
+
): ReadonlySet<string> | null {
|
|
92
|
+
const { type, checker } = params;
|
|
93
|
+
|
|
94
|
+
const result = extractIgnoreFieldsFromType(type, checker);
|
|
95
|
+
if (result) {
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (type.isIntersection()) {
|
|
100
|
+
for (const member of type.types) {
|
|
101
|
+
const memberResult = extractIgnoreFieldsFromType(member, checker);
|
|
102
|
+
if (memberResult) {
|
|
103
|
+
return memberResult;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return null;
|
|
109
|
+
}
|