@gqlkit-ts/cli 0.1.0 → 0.3.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/dist/auto-type-generator/auto-type-generator.d.ts +26 -4
- package/dist/auto-type-generator/auto-type-generator.d.ts.map +1 -1
- package/dist/auto-type-generator/auto-type-generator.js +846 -152
- package/dist/auto-type-generator/auto-type-generator.js.map +1 -1
- package/dist/auto-type-generator/index.d.ts +9 -2
- 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 +39 -0
- package/dist/auto-type-generator/inline-enum-collector.d.ts.map +1 -0
- package/dist/auto-type-generator/inline-enum-collector.js +193 -0
- package/dist/auto-type-generator/inline-enum-collector.js.map +1 -0
- 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 +22 -1
- package/dist/auto-type-generator/naming-convention.d.ts.map +1 -1
- package/dist/auto-type-generator/naming-convention.js +24 -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/gen-orchestrator/orchestrator.d.ts.map +1 -1
- package/dist/gen-orchestrator/orchestrator.js +119 -14
- package/dist/gen-orchestrator/orchestrator.js.map +1 -1
- package/dist/resolver-extractor/extract-resolvers.d.ts +28 -1
- package/dist/resolver-extractor/extract-resolvers.d.ts.map +1 -1
- package/dist/resolver-extractor/extractor/define-api-extractor.d.ts +16 -1
- package/dist/resolver-extractor/extractor/define-api-extractor.d.ts.map +1 -1
- package/dist/resolver-extractor/extractor/define-api-extractor.js +86 -309
- 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/emitter/code-emitter.d.ts +10 -2
- package/dist/schema-generator/emitter/code-emitter.d.ts.map +1 -1
- package/dist/schema-generator/emitter/code-emitter.js +39 -4
- package/dist/schema-generator/emitter/code-emitter.js.map +1 -1
- package/dist/schema-generator/generate-schema.d.ts +1 -0
- package/dist/schema-generator/generate-schema.d.ts.map +1 -1
- package/dist/schema-generator/generate-schema.js +90 -4
- package/dist/schema-generator/generate-schema.js.map +1 -1
- package/dist/schema-generator/integrator/result-integrator.d.ts +34 -2
- package/dist/schema-generator/integrator/result-integrator.d.ts.map +1 -1
- package/dist/schema-generator/integrator/result-integrator.js +96 -1
- 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/constants.d.ts +0 -16
- package/dist/shared/constants.d.ts.map +1 -1
- package/dist/shared/constants.js +0 -19
- package/dist/shared/constants.js.map +1 -1
- package/dist/shared/directive-detector.d.ts.map +1 -1
- package/dist/shared/directive-detector.js +8 -15
- package/dist/shared/directive-detector.js.map +1 -1
- 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/file-scanner.d.ts.map +1 -1
- package/dist/shared/file-scanner.js +5 -3
- package/dist/shared/file-scanner.js.map +1 -1
- 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 +3 -1
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/index.js +1 -3
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/interface-detector.d.ts +3 -2
- package/dist/shared/interface-detector.d.ts.map +1 -1
- package/dist/shared/interface-detector.js +54 -11
- package/dist/shared/interface-detector.js.map +1 -1
- package/dist/shared/path-utils.d.ts +2 -0
- package/dist/shared/path-utils.d.ts.map +1 -0
- package/dist/shared/path-utils.js +4 -0
- package/dist/shared/path-utils.js.map +1 -0
- 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/type-converter.d.ts.map +1 -1
- package/dist/shared/type-converter.js +11 -0
- package/dist/shared/type-converter.js.map +1 -1
- package/dist/shared/typescript-utils.d.ts +34 -7
- package/dist/shared/typescript-utils.d.ts.map +1 -1
- package/dist/shared/typescript-utils.js +72 -24
- package/dist/shared/typescript-utils.js.map +1 -1
- package/dist/type-extractor/collector/scalar-collector.d.ts.map +1 -1
- package/dist/type-extractor/collector/scalar-collector.js +4 -14
- package/dist/type-extractor/collector/scalar-collector.js.map +1 -1
- package/dist/type-extractor/converter/graphql-converter.d.ts.map +1 -1
- package/dist/type-extractor/converter/graphql-converter.js +57 -4
- package/dist/type-extractor/converter/graphql-converter.js.map +1 -1
- package/dist/type-extractor/extractor/field-type-resolver.d.ts +28 -0
- package/dist/type-extractor/extractor/field-type-resolver.d.ts.map +1 -0
- package/dist/type-extractor/extractor/field-type-resolver.js +433 -0
- package/dist/type-extractor/extractor/field-type-resolver.js.map +1 -0
- package/dist/type-extractor/extractor/type-extractor.d.ts +12 -3
- package/dist/type-extractor/extractor/type-extractor.d.ts.map +1 -1
- package/dist/type-extractor/extractor/type-extractor.js +260 -229
- package/dist/type-extractor/extractor/type-extractor.js.map +1 -1
- package/dist/type-extractor/extractor/type-name-collector.d.ts +24 -0
- package/dist/type-extractor/extractor/type-name-collector.d.ts.map +1 -0
- package/dist/type-extractor/extractor/type-name-collector.js +102 -0
- package/dist/type-extractor/extractor/type-name-collector.js.map +1 -0
- package/dist/type-extractor/mapper/scalar-base-type-mapper.d.ts +89 -0
- package/dist/type-extractor/mapper/scalar-base-type-mapper.d.ts.map +1 -0
- package/dist/type-extractor/mapper/scalar-base-type-mapper.js +158 -0
- package/dist/type-extractor/mapper/scalar-base-type-mapper.js.map +1 -0
- 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/graphql.d.ts +2 -0
- package/dist/type-extractor/types/graphql.d.ts.map +1 -1
- package/dist/type-extractor/types/index.d.ts +2 -1
- package/dist/type-extractor/types/index.d.ts.map +1 -1
- package/dist/type-extractor/types/index.js +1 -1
- package/dist/type-extractor/types/index.js.map +1 -1
- package/dist/type-extractor/types/ts-type-reference-factory.d.ts +47 -0
- package/dist/type-extractor/types/ts-type-reference-factory.d.ts.map +1 -0
- package/dist/type-extractor/types/ts-type-reference-factory.js +75 -0
- package/dist/type-extractor/types/ts-type-reference-factory.js.map +1 -0
- package/dist/type-extractor/types/typescript.d.ts +25 -1
- package/dist/type-extractor/types/typescript.d.ts.map +1 -1
- package/dist/type-extractor/validator/type-validator.js +1 -1
- package/dist/type-extractor/validator/type-validator.js.map +1 -1
- package/docs/coding-agents.md +64 -0
- package/docs/configuration.md +6 -20
- package/docs/getting-started.md +15 -12
- package/docs/index.md +36 -21
- package/docs/integration/apollo.md +8 -40
- package/docs/integration/drizzle.md +187 -0
- 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 +307 -0
- package/docs/schema/fields.md +66 -0
- package/docs/schema/index.md +21 -0
- package/docs/schema/inputs.md +117 -15
- package/docs/schema/interfaces.md +31 -1
- package/docs/schema/objects.md +42 -0
- package/docs/schema/queries-mutations.md +138 -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 +14 -5
- package/src/auto-type-generator/auto-type-generator.ts +1670 -0
- package/src/auto-type-generator/index.ts +63 -0
- package/src/auto-type-generator/inline-enum-collector.ts +338 -0
- 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/name-collision-validator.ts +119 -0
- package/src/auto-type-generator/naming-convention.ts +163 -0
- 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 +13 -0
- package/src/commands/docs.ts +211 -0
- package/src/commands/gen.ts +141 -0
- package/src/commands/main.ts +5 -0
- package/src/config/define-config.ts +28 -0
- package/src/config/index.ts +7 -0
- package/src/config/types.ts +144 -0
- package/src/config-loader/index.ts +14 -0
- package/src/config-loader/loader.ts +143 -0
- package/src/config-loader/validator.ts +672 -0
- package/src/gen-orchestrator/hook-executor/hook-executor.ts +117 -0
- package/src/gen-orchestrator/orchestrator.ts +798 -0
- package/src/gen-orchestrator/reporter/diagnostic-reporter.ts +44 -0
- package/src/gen-orchestrator/reporter/progress-reporter.ts +61 -0
- package/src/gen-orchestrator/writer/file-writer.ts +38 -0
- package/src/index.ts +2 -0
- package/src/resolver-extractor/extract-resolvers.ts +82 -0
- package/src/resolver-extractor/extractor/define-api-extractor.ts +740 -0
- package/src/resolver-extractor/index.ts +13 -0
- package/src/resolver-extractor/validator/abstract-resolver-validator.ts +259 -0
- package/src/schema-generator/builder/ast-builder.ts +706 -0
- package/src/schema-generator/emitter/code-emitter.ts +385 -0
- package/src/schema-generator/emitter/sdl-emitter.ts +13 -0
- package/src/schema-generator/generate-schema.ts +267 -0
- package/src/schema-generator/index.ts +19 -0
- package/src/schema-generator/integrator/result-integrator.ts +759 -0
- package/src/schema-generator/pruner/schema-pruner.ts +112 -0
- package/src/schema-generator/resolver-collector/resolver-collector.ts +157 -0
- package/src/shared/constants.ts +122 -0
- package/src/shared/default-value-detector.ts +172 -0
- package/src/shared/diagnostics.ts +35 -0
- package/src/shared/directive-definition-extractor.ts +564 -0
- package/src/shared/directive-detector.ts +556 -0
- package/src/shared/enum-prefix-detector.ts +99 -0
- package/src/shared/file-scanner.ts +170 -0
- package/src/shared/ignore-fields-detector.ts +109 -0
- package/src/shared/ignore-fields-validator.ts +66 -0
- package/src/shared/index.ts +34 -0
- package/src/shared/inline-object-extractor.ts +102 -0
- package/src/shared/inline-object-utils.ts +23 -0
- package/src/shared/interface-detector.ts +176 -0
- package/src/shared/interface-validator.ts +211 -0
- package/src/shared/metadata-detector.ts +443 -0
- package/src/shared/path-utils.ts +3 -0
- package/src/shared/program-factory.ts +51 -0
- package/src/shared/source-location.ts +38 -0
- package/src/shared/tsconfig-loader.ts +126 -0
- package/src/shared/tsdoc-parser.ts +155 -0
- package/src/shared/type-converter.ts +99 -0
- package/src/shared/typescript-utils.ts +246 -0
- package/src/type-extractor/collector/result-collector.ts +57 -0
- package/src/type-extractor/collector/scalar-collector.ts +254 -0
- package/src/type-extractor/converter/field-eligibility.ts +112 -0
- package/src/type-extractor/converter/graphql-converter.ts +483 -0
- package/src/type-extractor/extract-types.ts +1 -0
- package/src/type-extractor/extractor/field-type-resolver.ts +614 -0
- package/src/type-extractor/extractor/type-extractor.ts +1644 -0
- package/src/type-extractor/extractor/type-name-collector.ts +130 -0
- package/src/type-extractor/index.ts +20 -0
- package/src/type-extractor/mapper/scalar-base-type-mapper.ts +265 -0
- package/src/type-extractor/types/diagnostics.ts +109 -0
- package/src/type-extractor/types/graphql.ts +55 -0
- package/src/type-extractor/types/index.ts +37 -0
- package/src/type-extractor/types/ts-type-reference-factory.ts +150 -0
- package/src/type-extractor/types/typescript.ts +137 -0
- package/src/type-extractor/validator/type-validator.ts +77 -0
- package/dist/auto-type-generator/auto-type-generator.test.d.ts +0 -2
- package/dist/auto-type-generator/auto-type-generator.test.d.ts.map +0 -1
- package/dist/auto-type-generator/auto-type-generator.test.js +0 -613
- package/dist/auto-type-generator/auto-type-generator.test.js.map +0 -1
- package/dist/auto-type-generator/name-collision-validator.test.d.ts +0 -2
- package/dist/auto-type-generator/name-collision-validator.test.d.ts.map +0 -1
- package/dist/auto-type-generator/name-collision-validator.test.js +0 -358
- package/dist/auto-type-generator/name-collision-validator.test.js.map +0 -1
- package/dist/auto-type-generator/naming-convention.test.d.ts +0 -2
- package/dist/auto-type-generator/naming-convention.test.d.ts.map +0 -1
- package/dist/auto-type-generator/naming-convention.test.js +0 -132
- package/dist/auto-type-generator/naming-convention.test.js.map +0 -1
- package/dist/commands/gen.test.d.ts +0 -2
- package/dist/commands/gen.test.d.ts.map +0 -1
- package/dist/commands/gen.test.js +0 -226
- package/dist/commands/gen.test.js.map +0 -1
- package/dist/config-loader/loader.test.d.ts +0 -2
- package/dist/config-loader/loader.test.d.ts.map +0 -1
- package/dist/config-loader/loader.test.js +0 -123
- package/dist/config-loader/loader.test.js.map +0 -1
- package/dist/config-loader/validator.test.d.ts +0 -2
- package/dist/config-loader/validator.test.d.ts.map +0 -1
- package/dist/config-loader/validator.test.js +0 -846
- package/dist/config-loader/validator.test.js.map +0 -1
- package/dist/gen-orchestrator/golden.test.d.ts +0 -2
- package/dist/gen-orchestrator/golden.test.d.ts.map +0 -1
- package/dist/gen-orchestrator/golden.test.js +0 -102
- package/dist/gen-orchestrator/golden.test.js.map +0 -1
- package/dist/gen-orchestrator/hook-executor/hook-executor.test.d.ts +0 -2
- package/dist/gen-orchestrator/hook-executor/hook-executor.test.d.ts.map +0 -1
- package/dist/gen-orchestrator/hook-executor/hook-executor.test.js +0 -167
- package/dist/gen-orchestrator/hook-executor/hook-executor.test.js.map +0 -1
- package/dist/gen-orchestrator/reporter/progress-reporter.test.d.ts +0 -2
- package/dist/gen-orchestrator/reporter/progress-reporter.test.d.ts.map +0 -1
- package/dist/gen-orchestrator/reporter/progress-reporter.test.js +0 -74
- package/dist/gen-orchestrator/reporter/progress-reporter.test.js.map +0 -1
- 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/dist/resolver-extractor/validator/only-validator.test.d.ts +0 -8
- package/dist/resolver-extractor/validator/only-validator.test.d.ts.map +0 -1
- package/dist/resolver-extractor/validator/only-validator.test.js +0 -352
- package/dist/resolver-extractor/validator/only-validator.test.js.map +0 -1
- package/dist/schema-generator/builder/ast-builder.test.d.ts +0 -2
- package/dist/schema-generator/builder/ast-builder.test.d.ts.map +0 -1
- package/dist/schema-generator/builder/ast-builder.test.js +0 -469
- package/dist/schema-generator/builder/ast-builder.test.js.map +0 -1
- package/dist/shared/file-scanner.test.d.ts +0 -2
- package/dist/shared/file-scanner.test.d.ts.map +0 -1
- package/dist/shared/file-scanner.test.js +0 -138
- package/dist/shared/file-scanner.test.js.map +0 -1
- package/dist/shared/interface-validator.test.d.ts +0 -2
- package/dist/shared/interface-validator.test.d.ts.map +0 -1
- package/dist/shared/interface-validator.test.js +0 -145
- package/dist/shared/interface-validator.test.js.map +0 -1
- package/dist/type-extractor/types/typescript.test.d.ts +0 -2
- package/dist/type-extractor/types/typescript.test.d.ts.map +0 -1
- package/dist/type-extractor/types/typescript.test.js +0 -287
- package/dist/type-extractor/types/typescript.test.js.map +0 -1
|
@@ -0,0 +1,1670 @@
|
|
|
1
|
+
import type ts from "typescript";
|
|
2
|
+
import type {
|
|
3
|
+
ExtractResolversResult,
|
|
4
|
+
GraphQLFieldDefinition,
|
|
5
|
+
} from "../resolver-extractor/index.js";
|
|
6
|
+
import type {
|
|
7
|
+
DirectiveArgumentValue,
|
|
8
|
+
DirectiveInfo,
|
|
9
|
+
} from "../shared/directive-detector.js";
|
|
10
|
+
import {
|
|
11
|
+
detectEnumPrefix,
|
|
12
|
+
stripEnumPrefix,
|
|
13
|
+
} from "../shared/enum-prefix-detector.js";
|
|
14
|
+
import { getSourceLocationOrDefault } from "../shared/source-location.js";
|
|
15
|
+
import type { DeprecationInfo } from "../shared/tsdoc-parser.js";
|
|
16
|
+
import { convertTsTypeToGraphQLType } from "../shared/type-converter.js";
|
|
17
|
+
import {
|
|
18
|
+
isEligibleAsInputObjectField,
|
|
19
|
+
isEligibleAsObjectField,
|
|
20
|
+
} from "../type-extractor/converter/field-eligibility.js";
|
|
21
|
+
import {
|
|
22
|
+
createReferenceType,
|
|
23
|
+
type Diagnostic,
|
|
24
|
+
type ExtractedTypeInfo,
|
|
25
|
+
type FieldDefinition,
|
|
26
|
+
type GraphQLFieldType,
|
|
27
|
+
type InlineEnumMemberInfo,
|
|
28
|
+
type InlineObjectPropertyDef,
|
|
29
|
+
type SourceLocation,
|
|
30
|
+
} from "../type-extractor/types/index.js";
|
|
31
|
+
import {
|
|
32
|
+
collectInlineEnumsFromPayloads,
|
|
33
|
+
collectInlineEnumsFromResolvers,
|
|
34
|
+
collectInlineEnumsFromTypes,
|
|
35
|
+
type InlineEnumWithContext,
|
|
36
|
+
} from "./inline-enum-collector.js";
|
|
37
|
+
import {
|
|
38
|
+
collectInlineUnionsFromPayloads,
|
|
39
|
+
collectInlineUnionsFromResolvers,
|
|
40
|
+
collectInlineUnionsFromTypes,
|
|
41
|
+
type InlineUnionWithContext,
|
|
42
|
+
} from "./inline-union-collector.js";
|
|
43
|
+
import type { InlineUnionMemberInfo } from "./inline-union-types.js";
|
|
44
|
+
import {
|
|
45
|
+
type ValidatedTypenameInfo,
|
|
46
|
+
validateOneOfMembers,
|
|
47
|
+
validateUnionMembers,
|
|
48
|
+
validateUnionMemberTypenames,
|
|
49
|
+
} from "./inline-union-validator.js";
|
|
50
|
+
import {
|
|
51
|
+
type AutoTypeNameContext,
|
|
52
|
+
buildFieldContext,
|
|
53
|
+
generateAutoTypeName,
|
|
54
|
+
isInputTypeName,
|
|
55
|
+
} from "./naming-convention.js";
|
|
56
|
+
import type { ResolveTypeFieldPattern } from "./resolve-type-generator.js";
|
|
57
|
+
import { forEachResolverField } from "./resolver-field-iterator.js";
|
|
58
|
+
import {
|
|
59
|
+
createFieldNameSet,
|
|
60
|
+
findTypenameProperty,
|
|
61
|
+
type TypenameFieldInfo,
|
|
62
|
+
type TypenameFieldName,
|
|
63
|
+
} from "./typename-types.js";
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Information about where an auto-generated type was generated from.
|
|
67
|
+
*/
|
|
68
|
+
export interface GeneratedFromInfo {
|
|
69
|
+
readonly parentTypeName: string | null;
|
|
70
|
+
readonly fieldPath: ReadonlyArray<string>;
|
|
71
|
+
readonly context:
|
|
72
|
+
| "typeField"
|
|
73
|
+
| "inputField"
|
|
74
|
+
| "resolverArg"
|
|
75
|
+
| "resolverPayload";
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Field information for auto-generated types.
|
|
80
|
+
*/
|
|
81
|
+
export interface AutoGeneratedField {
|
|
82
|
+
readonly name: string;
|
|
83
|
+
readonly type: GraphQLFieldType;
|
|
84
|
+
readonly description: string | null;
|
|
85
|
+
readonly deprecated: DeprecationInfo | null;
|
|
86
|
+
readonly directives: ReadonlyArray<DirectiveInfo> | null;
|
|
87
|
+
readonly defaultValue: DirectiveArgumentValue | null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Enum value information for auto-generated enum types.
|
|
92
|
+
*/
|
|
93
|
+
export interface AutoGeneratedEnumValue {
|
|
94
|
+
/** GraphQL enum value name (SCREAMING_SNAKE_CASE) */
|
|
95
|
+
readonly name: string;
|
|
96
|
+
/** Original TypeScript value */
|
|
97
|
+
readonly originalValue: string;
|
|
98
|
+
readonly description: string | null;
|
|
99
|
+
readonly deprecated: DeprecationInfo | null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Auto-generated type information.
|
|
104
|
+
*/
|
|
105
|
+
export interface AutoGeneratedType {
|
|
106
|
+
readonly name: string;
|
|
107
|
+
readonly kind:
|
|
108
|
+
| "Object"
|
|
109
|
+
| "InputObject"
|
|
110
|
+
| "Enum"
|
|
111
|
+
| "Union"
|
|
112
|
+
| "OneOfInputObject";
|
|
113
|
+
/** Fields for Object/InputObject/OneOfInputObject kinds (null for Enum/Union) */
|
|
114
|
+
readonly fields: ReadonlyArray<AutoGeneratedField> | null;
|
|
115
|
+
/** Enum values for Enum kind (null for Object/InputObject/Union/OneOfInputObject) */
|
|
116
|
+
readonly enumValues: ReadonlyArray<AutoGeneratedEnumValue> | null;
|
|
117
|
+
/** Union members for Union kind (null for Object/InputObject/Enum/OneOfInputObject) */
|
|
118
|
+
readonly unionMembers: ReadonlyArray<string> | null;
|
|
119
|
+
/** True if enum needs value mapping (at least one value converted) */
|
|
120
|
+
readonly needsStringEnumMapping: boolean;
|
|
121
|
+
readonly sourceLocation: SourceLocation;
|
|
122
|
+
readonly generatedFrom: GeneratedFromInfo;
|
|
123
|
+
readonly description: string | null;
|
|
124
|
+
/** For Union types from resolverPayload context: the field pattern for resolveType */
|
|
125
|
+
readonly resolveTypeFieldPattern: ResolveTypeFieldPattern | null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export interface AutoTypeGeneratorInput {
|
|
129
|
+
readonly extractedTypes: ReadonlyArray<ExtractedTypeInfo>;
|
|
130
|
+
readonly resolversResult: ExtractResolversResult;
|
|
131
|
+
readonly knownTypeNames: ReadonlySet<string>;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export interface AutoTypeGeneratorResult {
|
|
135
|
+
readonly autoGeneratedTypes: ReadonlyArray<AutoGeneratedType>;
|
|
136
|
+
readonly updatedExtractedTypes: ReadonlyArray<ExtractedTypeInfo>;
|
|
137
|
+
readonly updatedResolversResult: ExtractResolversResult;
|
|
138
|
+
readonly diagnostics: ReadonlyArray<Diagnostic>;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
interface InlineObjectWithContext {
|
|
142
|
+
readonly properties: ReadonlyArray<InlineObjectPropertyDef>;
|
|
143
|
+
readonly context: AutoTypeNameContext;
|
|
144
|
+
readonly sourceLocation: SourceLocation;
|
|
145
|
+
readonly nullable: boolean;
|
|
146
|
+
/** TSDoc description from the inline object type alias (Requirement 7.2) */
|
|
147
|
+
readonly description: string | null;
|
|
148
|
+
/** @deprecated tag from the inline object type alias (Requirement 7.3) */
|
|
149
|
+
readonly deprecated: DeprecationInfo | null;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
type ContextBuilderFn = (
|
|
153
|
+
nestedPath: ReadonlyArray<string>,
|
|
154
|
+
) => AutoTypeNameContext;
|
|
155
|
+
|
|
156
|
+
interface ExtractNestedInlineObjectsParams {
|
|
157
|
+
readonly properties: ReadonlyArray<InlineObjectPropertyDef>;
|
|
158
|
+
readonly currentPath: ReadonlyArray<string>;
|
|
159
|
+
readonly sourceLocation: SourceLocation;
|
|
160
|
+
readonly buildContext: ContextBuilderFn;
|
|
161
|
+
readonly preserveDocumentation: boolean;
|
|
162
|
+
readonly results: InlineObjectWithContext[];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function extractNestedInlineObjectsRecursively(
|
|
166
|
+
params: ExtractNestedInlineObjectsParams,
|
|
167
|
+
): void {
|
|
168
|
+
const {
|
|
169
|
+
properties,
|
|
170
|
+
currentPath,
|
|
171
|
+
sourceLocation,
|
|
172
|
+
buildContext,
|
|
173
|
+
preserveDocumentation,
|
|
174
|
+
results,
|
|
175
|
+
} = params;
|
|
176
|
+
|
|
177
|
+
for (const prop of properties) {
|
|
178
|
+
if (
|
|
179
|
+
prop.tsType.kind === "inlineObject" &&
|
|
180
|
+
prop.tsType.inlineObjectProperties
|
|
181
|
+
) {
|
|
182
|
+
const nestedPath = [...currentPath, prop.name];
|
|
183
|
+
const nestedContext = buildContext(nestedPath);
|
|
184
|
+
// Use property's source location if available for more accurate diagnostics
|
|
185
|
+
const nestedSourceLocation = prop.sourceLocation ?? sourceLocation;
|
|
186
|
+
|
|
187
|
+
results.push({
|
|
188
|
+
properties: prop.tsType.inlineObjectProperties,
|
|
189
|
+
context: nestedContext,
|
|
190
|
+
sourceLocation: nestedSourceLocation,
|
|
191
|
+
nullable: prop.tsType.nullable,
|
|
192
|
+
description: preserveDocumentation
|
|
193
|
+
? prop.tsType.inlineObjectDescription
|
|
194
|
+
: null,
|
|
195
|
+
deprecated: preserveDocumentation
|
|
196
|
+
? prop.tsType.inlineObjectDeprecated
|
|
197
|
+
: null,
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
extractNestedInlineObjectsRecursively({
|
|
201
|
+
properties: prop.tsType.inlineObjectProperties,
|
|
202
|
+
currentPath: nestedPath,
|
|
203
|
+
sourceLocation: nestedSourceLocation,
|
|
204
|
+
buildContext,
|
|
205
|
+
preserveDocumentation,
|
|
206
|
+
results,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function getContextKey(context: AutoTypeNameContext): string {
|
|
213
|
+
switch (context.kind) {
|
|
214
|
+
case "objectField":
|
|
215
|
+
return `objectField:${context.parentTypeName}:${context.fieldPath.join(".")}`;
|
|
216
|
+
case "inputField":
|
|
217
|
+
return `inputField:${context.parentTypeName}:${context.fieldPath.join(".")}`;
|
|
218
|
+
case "resolverArg":
|
|
219
|
+
return `resolverArg:${context.resolverType}:${context.parentTypeName ?? ""}:${context.fieldName}:${context.argName}:${context.fieldPath.join(".")}`;
|
|
220
|
+
case "resolverPayload":
|
|
221
|
+
return `resolverPayload:${context.resolverType}:${context.parentTypeName ?? ""}:${context.fieldName}:${context.fieldPath.join(".")}`;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function mapContextKindToGeneratedFromContext(
|
|
226
|
+
kind: AutoTypeNameContext["kind"],
|
|
227
|
+
): GeneratedFromInfo["context"] {
|
|
228
|
+
switch (kind) {
|
|
229
|
+
case "objectField":
|
|
230
|
+
return "typeField";
|
|
231
|
+
case "inputField":
|
|
232
|
+
return "inputField";
|
|
233
|
+
case "resolverArg":
|
|
234
|
+
return "resolverArg";
|
|
235
|
+
case "resolverPayload":
|
|
236
|
+
return "resolverPayload";
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function buildGeneratedFromInfo(
|
|
241
|
+
context: AutoTypeNameContext,
|
|
242
|
+
): GeneratedFromInfo {
|
|
243
|
+
const fieldPath =
|
|
244
|
+
context.kind === "resolverArg" && context.fieldPath.length === 0
|
|
245
|
+
? [context.argName]
|
|
246
|
+
: context.fieldPath;
|
|
247
|
+
|
|
248
|
+
return {
|
|
249
|
+
parentTypeName: context.parentTypeName,
|
|
250
|
+
fieldPath,
|
|
251
|
+
context: mapContextKindToGeneratedFromContext(context.kind),
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function collectInlineObjectsFromType(
|
|
256
|
+
typeInfo: ExtractedTypeInfo,
|
|
257
|
+
): InlineObjectWithContext[] {
|
|
258
|
+
const results: InlineObjectWithContext[] = [];
|
|
259
|
+
const isInput = isInputTypeName(typeInfo.metadata.name);
|
|
260
|
+
|
|
261
|
+
for (const field of typeInfo.fields) {
|
|
262
|
+
collectInlineObjectsFromField(
|
|
263
|
+
field,
|
|
264
|
+
typeInfo.metadata.name,
|
|
265
|
+
[],
|
|
266
|
+
isInput,
|
|
267
|
+
typeInfo.metadata.sourceFile,
|
|
268
|
+
results,
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return results;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function collectInlineObjectsFromField(
|
|
276
|
+
field: FieldDefinition,
|
|
277
|
+
parentTypeName: string,
|
|
278
|
+
parentPath: ReadonlyArray<string>,
|
|
279
|
+
isInput: boolean,
|
|
280
|
+
sourceFile: string,
|
|
281
|
+
results: InlineObjectWithContext[],
|
|
282
|
+
): void {
|
|
283
|
+
const tsType = field.tsType;
|
|
284
|
+
|
|
285
|
+
if (tsType.kind !== "inlineObject" || !tsType.inlineObjectProperties) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const fieldPath = [...parentPath, field.name];
|
|
290
|
+
|
|
291
|
+
const context: AutoTypeNameContext = isInput
|
|
292
|
+
? {
|
|
293
|
+
kind: "inputField",
|
|
294
|
+
parentTypeName,
|
|
295
|
+
fieldPath,
|
|
296
|
+
}
|
|
297
|
+
: {
|
|
298
|
+
kind: "objectField",
|
|
299
|
+
parentTypeName,
|
|
300
|
+
fieldPath,
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
const sourceLocation = getSourceLocationOrDefault(
|
|
304
|
+
field.sourceLocation,
|
|
305
|
+
sourceFile,
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
results.push({
|
|
309
|
+
properties: tsType.inlineObjectProperties,
|
|
310
|
+
context,
|
|
311
|
+
sourceLocation,
|
|
312
|
+
nullable: tsType.nullable,
|
|
313
|
+
description: tsType.inlineObjectDescription,
|
|
314
|
+
deprecated: tsType.inlineObjectDeprecated,
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
extractNestedInlineObjectsRecursively({
|
|
318
|
+
properties: tsType.inlineObjectProperties,
|
|
319
|
+
currentPath: fieldPath,
|
|
320
|
+
sourceLocation,
|
|
321
|
+
buildContext: (nestedPath) =>
|
|
322
|
+
isInput
|
|
323
|
+
? { kind: "inputField", parentTypeName, fieldPath: nestedPath }
|
|
324
|
+
: { kind: "objectField", parentTypeName, fieldPath: nestedPath },
|
|
325
|
+
preserveDocumentation: true,
|
|
326
|
+
results,
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function collectInlineObjectsFromResolvers(
|
|
331
|
+
resolversResult: ExtractResolversResult,
|
|
332
|
+
): InlineObjectWithContext[] {
|
|
333
|
+
const results: InlineObjectWithContext[] = [];
|
|
334
|
+
|
|
335
|
+
forEachResolverField(
|
|
336
|
+
resolversResult,
|
|
337
|
+
({ field, resolverType, parentTypeName }) => {
|
|
338
|
+
collectInlineObjectsFromResolverArgs(
|
|
339
|
+
field,
|
|
340
|
+
resolverType,
|
|
341
|
+
parentTypeName,
|
|
342
|
+
results,
|
|
343
|
+
);
|
|
344
|
+
},
|
|
345
|
+
);
|
|
346
|
+
|
|
347
|
+
return results;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function collectInlineObjectsFromResolverArgs(
|
|
351
|
+
field: GraphQLFieldDefinition,
|
|
352
|
+
resolverType: "query" | "mutation" | "field",
|
|
353
|
+
parentTypeName: string | null,
|
|
354
|
+
results: InlineObjectWithContext[],
|
|
355
|
+
): void {
|
|
356
|
+
if (!field.args) return;
|
|
357
|
+
|
|
358
|
+
for (const arg of field.args) {
|
|
359
|
+
if (!arg.inlineObjectProperties) continue;
|
|
360
|
+
|
|
361
|
+
const context: AutoTypeNameContext = {
|
|
362
|
+
kind: "resolverArg",
|
|
363
|
+
resolverType,
|
|
364
|
+
fieldName: field.name,
|
|
365
|
+
argName: arg.name,
|
|
366
|
+
parentTypeName,
|
|
367
|
+
fieldPath: [],
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
results.push({
|
|
371
|
+
properties: arg.inlineObjectProperties,
|
|
372
|
+
context,
|
|
373
|
+
sourceLocation: field.sourceLocation,
|
|
374
|
+
nullable: arg.type.nullable,
|
|
375
|
+
description: null,
|
|
376
|
+
deprecated: null,
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
extractNestedInlineObjectsRecursively({
|
|
380
|
+
properties: arg.inlineObjectProperties,
|
|
381
|
+
currentPath: [],
|
|
382
|
+
sourceLocation: field.sourceLocation,
|
|
383
|
+
buildContext: (nestedPath) => ({
|
|
384
|
+
kind: "resolverArg",
|
|
385
|
+
resolverType,
|
|
386
|
+
fieldName: field.name,
|
|
387
|
+
argName: arg.name,
|
|
388
|
+
parentTypeName,
|
|
389
|
+
fieldPath: nestedPath,
|
|
390
|
+
}),
|
|
391
|
+
preserveDocumentation: false,
|
|
392
|
+
results,
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
function collectInlinePayloadsFromResolvers(
|
|
398
|
+
resolversResult: ExtractResolversResult,
|
|
399
|
+
): InlineObjectWithContext[] {
|
|
400
|
+
const results: InlineObjectWithContext[] = [];
|
|
401
|
+
|
|
402
|
+
forEachResolverField(
|
|
403
|
+
resolversResult,
|
|
404
|
+
({ field, resolverType, parentTypeName }) => {
|
|
405
|
+
collectInlinePayloadFromReturnType(
|
|
406
|
+
field,
|
|
407
|
+
resolverType,
|
|
408
|
+
parentTypeName,
|
|
409
|
+
results,
|
|
410
|
+
);
|
|
411
|
+
},
|
|
412
|
+
);
|
|
413
|
+
|
|
414
|
+
return results;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function collectInlinePayloadFromReturnType(
|
|
418
|
+
field: GraphQLFieldDefinition,
|
|
419
|
+
resolverType: "query" | "mutation" | "field",
|
|
420
|
+
parentTypeName: string | null,
|
|
421
|
+
results: InlineObjectWithContext[],
|
|
422
|
+
): void {
|
|
423
|
+
if (!field.returnTypeInlineObjectProperties) return;
|
|
424
|
+
|
|
425
|
+
const context: AutoTypeNameContext = {
|
|
426
|
+
kind: "resolverPayload",
|
|
427
|
+
resolverType,
|
|
428
|
+
fieldName: field.name,
|
|
429
|
+
parentTypeName,
|
|
430
|
+
fieldPath: [],
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
results.push({
|
|
434
|
+
properties: field.returnTypeInlineObjectProperties,
|
|
435
|
+
context,
|
|
436
|
+
sourceLocation: field.sourceLocation,
|
|
437
|
+
nullable: field.type.nullable,
|
|
438
|
+
description: field.returnTypeInlineObjectDescription,
|
|
439
|
+
deprecated: field.returnTypeInlineObjectDeprecated,
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
extractNestedInlineObjectsRecursively({
|
|
443
|
+
properties: field.returnTypeInlineObjectProperties,
|
|
444
|
+
currentPath: [],
|
|
445
|
+
sourceLocation: field.sourceLocation,
|
|
446
|
+
buildContext: (nestedPath) => ({
|
|
447
|
+
kind: "resolverPayload",
|
|
448
|
+
resolverType,
|
|
449
|
+
fieldName: field.name,
|
|
450
|
+
parentTypeName,
|
|
451
|
+
fieldPath: nestedPath,
|
|
452
|
+
}),
|
|
453
|
+
preserveDocumentation: true,
|
|
454
|
+
results,
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
interface GenerateAutoTypeResult {
|
|
459
|
+
readonly type: AutoGeneratedType;
|
|
460
|
+
readonly diagnostics: ReadonlyArray<Diagnostic>;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
interface GenerateAutoTypeParams {
|
|
464
|
+
readonly inlineObj: InlineObjectWithContext;
|
|
465
|
+
readonly generatedTypeNames: Map<string, string>;
|
|
466
|
+
readonly enumTypeNames: Map<string, string>;
|
|
467
|
+
readonly unionTypeNames: Map<string, string>;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function generateAutoType(
|
|
471
|
+
params: GenerateAutoTypeParams,
|
|
472
|
+
): GenerateAutoTypeResult {
|
|
473
|
+
const { inlineObj, generatedTypeNames, enumTypeNames, unionTypeNames } =
|
|
474
|
+
params;
|
|
475
|
+
const name = generateAutoTypeName(inlineObj.context);
|
|
476
|
+
const isInput =
|
|
477
|
+
inlineObj.context.kind === "inputField" ||
|
|
478
|
+
inlineObj.context.kind === "resolverArg";
|
|
479
|
+
|
|
480
|
+
const fields: AutoGeneratedField[] = [];
|
|
481
|
+
const diagnostics: Diagnostic[] = [];
|
|
482
|
+
|
|
483
|
+
for (const prop of inlineObj.properties) {
|
|
484
|
+
const eligibility = isInput
|
|
485
|
+
? isEligibleAsInputObjectField(prop.name)
|
|
486
|
+
: isEligibleAsObjectField(prop.name);
|
|
487
|
+
|
|
488
|
+
if (!eligibility.eligible) {
|
|
489
|
+
diagnostics.push({
|
|
490
|
+
code: "SKIPPED_FIELD",
|
|
491
|
+
message: eligibility.skipReason.message,
|
|
492
|
+
severity: "warning",
|
|
493
|
+
location: prop.sourceLocation ?? inlineObj.sourceLocation,
|
|
494
|
+
});
|
|
495
|
+
continue;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
const fieldType = resolveFieldType({
|
|
499
|
+
prop,
|
|
500
|
+
generatedTypeNames,
|
|
501
|
+
enumTypeNames,
|
|
502
|
+
unionTypeNames,
|
|
503
|
+
parentContext: inlineObj.context,
|
|
504
|
+
});
|
|
505
|
+
fields.push({
|
|
506
|
+
name: prop.name,
|
|
507
|
+
type: fieldType,
|
|
508
|
+
description: prop.description,
|
|
509
|
+
deprecated: prop.deprecated,
|
|
510
|
+
directives: prop.directives,
|
|
511
|
+
defaultValue: prop.defaultValue,
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
return {
|
|
516
|
+
type: {
|
|
517
|
+
name,
|
|
518
|
+
kind: isInput ? "InputObject" : "Object",
|
|
519
|
+
fields,
|
|
520
|
+
enumValues: null,
|
|
521
|
+
unionMembers: null,
|
|
522
|
+
needsStringEnumMapping: false,
|
|
523
|
+
sourceLocation: inlineObj.sourceLocation,
|
|
524
|
+
generatedFrom: buildGeneratedFromInfo(inlineObj.context),
|
|
525
|
+
description: inlineObj.description,
|
|
526
|
+
resolveTypeFieldPattern: null,
|
|
527
|
+
},
|
|
528
|
+
diagnostics,
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
interface ResolveFieldTypeParams {
|
|
533
|
+
readonly prop: InlineObjectPropertyDef;
|
|
534
|
+
readonly generatedTypeNames: Map<string, string>;
|
|
535
|
+
readonly enumTypeNames: Map<string, string>;
|
|
536
|
+
readonly unionTypeNames: Map<string, string>;
|
|
537
|
+
readonly parentContext: AutoTypeNameContext;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
function tryResolveNestedType(
|
|
541
|
+
prop: InlineObjectPropertyDef,
|
|
542
|
+
parentContext: AutoTypeNameContext,
|
|
543
|
+
typeNamesMap: ReadonlyMap<string, string>,
|
|
544
|
+
): GraphQLFieldType | null {
|
|
545
|
+
const nestedPath = [...parentContext.fieldPath, prop.name];
|
|
546
|
+
const nestedContext: AutoTypeNameContext = {
|
|
547
|
+
...parentContext,
|
|
548
|
+
fieldPath: nestedPath,
|
|
549
|
+
};
|
|
550
|
+
const contextKey = getContextKey(nestedContext);
|
|
551
|
+
const resolvedTypeName = typeNamesMap.get(contextKey);
|
|
552
|
+
|
|
553
|
+
if (resolvedTypeName) {
|
|
554
|
+
return {
|
|
555
|
+
typeName: resolvedTypeName,
|
|
556
|
+
nullable: prop.tsType.nullable || prop.optional,
|
|
557
|
+
list: false,
|
|
558
|
+
listItemNullable: null,
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
return null;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
function resolveFieldType(params: ResolveFieldTypeParams): GraphQLFieldType {
|
|
565
|
+
const {
|
|
566
|
+
prop,
|
|
567
|
+
generatedTypeNames,
|
|
568
|
+
enumTypeNames,
|
|
569
|
+
unionTypeNames,
|
|
570
|
+
parentContext,
|
|
571
|
+
} = params;
|
|
572
|
+
|
|
573
|
+
if (
|
|
574
|
+
prop.tsType.kind === "inlineObject" &&
|
|
575
|
+
prop.tsType.inlineObjectProperties
|
|
576
|
+
) {
|
|
577
|
+
const result = tryResolveNestedType(
|
|
578
|
+
prop,
|
|
579
|
+
parentContext,
|
|
580
|
+
generatedTypeNames,
|
|
581
|
+
);
|
|
582
|
+
if (result) return result;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
if (prop.tsType.kind === "inlineEnum" && prop.tsType.inlineEnumMembers) {
|
|
586
|
+
const result = tryResolveNestedType(prop, parentContext, enumTypeNames);
|
|
587
|
+
if (result) return result;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
if (prop.tsType.kind === "union" && prop.tsType.members) {
|
|
591
|
+
const result = tryResolveNestedType(prop, parentContext, unionTypeNames);
|
|
592
|
+
if (result) return result;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
return convertTsTypeToGraphQLType(prop.tsType, prop.optional);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
interface UpdateTypeNamesParams {
|
|
599
|
+
readonly generatedTypeNames: Map<string, string>;
|
|
600
|
+
readonly enumTypeNames: Map<string, string>;
|
|
601
|
+
readonly unionTypeNames: Map<string, string>;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
function updateExtractedTypes(
|
|
605
|
+
extractedTypes: ReadonlyArray<ExtractedTypeInfo>,
|
|
606
|
+
params: UpdateTypeNamesParams,
|
|
607
|
+
): ExtractedTypeInfo[] {
|
|
608
|
+
return extractedTypes.map((typeInfo) => {
|
|
609
|
+
const isInput = isInputTypeName(typeInfo.metadata.name);
|
|
610
|
+
return {
|
|
611
|
+
...typeInfo,
|
|
612
|
+
fields: typeInfo.fields.map((field) =>
|
|
613
|
+
updateField(field, params, typeInfo.metadata.name, isInput),
|
|
614
|
+
),
|
|
615
|
+
};
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
function updateField(
|
|
620
|
+
field: FieldDefinition,
|
|
621
|
+
params: UpdateTypeNamesParams,
|
|
622
|
+
parentTypeName: string,
|
|
623
|
+
isInput: boolean,
|
|
624
|
+
): FieldDefinition {
|
|
625
|
+
const { generatedTypeNames, enumTypeNames, unionTypeNames } = params;
|
|
626
|
+
const context = buildFieldContext(parentTypeName, [field.name], isInput);
|
|
627
|
+
const contextKey = getContextKey(context);
|
|
628
|
+
|
|
629
|
+
// Handle inline objects
|
|
630
|
+
if (
|
|
631
|
+
field.tsType.kind === "inlineObject" &&
|
|
632
|
+
field.tsType.inlineObjectProperties
|
|
633
|
+
) {
|
|
634
|
+
const resolvedTypeName = generatedTypeNames.get(contextKey);
|
|
635
|
+
if (resolvedTypeName) {
|
|
636
|
+
return {
|
|
637
|
+
...field,
|
|
638
|
+
tsType: createReferenceType({
|
|
639
|
+
name: resolvedTypeName,
|
|
640
|
+
nullable: field.tsType.nullable,
|
|
641
|
+
}),
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// Handle inline enums
|
|
647
|
+
if (field.tsType.kind === "inlineEnum" && field.tsType.inlineEnumMembers) {
|
|
648
|
+
const resolvedTypeName = enumTypeNames.get(contextKey);
|
|
649
|
+
if (resolvedTypeName) {
|
|
650
|
+
return {
|
|
651
|
+
...field,
|
|
652
|
+
tsType: createReferenceType({
|
|
653
|
+
name: resolvedTypeName,
|
|
654
|
+
nullable: field.tsType.nullable,
|
|
655
|
+
}),
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// Handle array of inline enums
|
|
661
|
+
if (
|
|
662
|
+
field.tsType.kind === "array" &&
|
|
663
|
+
field.tsType.elementType?.kind === "inlineEnum" &&
|
|
664
|
+
field.tsType.elementType.inlineEnumMembers
|
|
665
|
+
) {
|
|
666
|
+
const resolvedTypeName = enumTypeNames.get(contextKey);
|
|
667
|
+
if (resolvedTypeName) {
|
|
668
|
+
return {
|
|
669
|
+
...field,
|
|
670
|
+
tsType: {
|
|
671
|
+
...field.tsType,
|
|
672
|
+
elementType: createReferenceType({
|
|
673
|
+
name: resolvedTypeName,
|
|
674
|
+
nullable: field.tsType.elementType.nullable,
|
|
675
|
+
}),
|
|
676
|
+
},
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// Handle inline union types
|
|
682
|
+
if (field.tsType.kind === "union" && field.tsType.members) {
|
|
683
|
+
const resolvedTypeName = unionTypeNames.get(contextKey);
|
|
684
|
+
if (resolvedTypeName) {
|
|
685
|
+
return {
|
|
686
|
+
...field,
|
|
687
|
+
tsType: createReferenceType({
|
|
688
|
+
name: resolvedTypeName,
|
|
689
|
+
nullable: field.tsType.nullable,
|
|
690
|
+
}),
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
return field;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
function updateResolversResult(
|
|
699
|
+
resolversResult: ExtractResolversResult,
|
|
700
|
+
params: UpdateTypeNamesParams,
|
|
701
|
+
): ExtractResolversResult {
|
|
702
|
+
return {
|
|
703
|
+
...resolversResult,
|
|
704
|
+
queryFields: {
|
|
705
|
+
fields: resolversResult.queryFields.fields.map((field) =>
|
|
706
|
+
updateResolverField(field, params, "query", null),
|
|
707
|
+
),
|
|
708
|
+
},
|
|
709
|
+
mutationFields: {
|
|
710
|
+
fields: resolversResult.mutationFields.fields.map((field) =>
|
|
711
|
+
updateResolverField(field, params, "mutation", null),
|
|
712
|
+
),
|
|
713
|
+
},
|
|
714
|
+
typeExtensions: resolversResult.typeExtensions.map((ext) => ({
|
|
715
|
+
...ext,
|
|
716
|
+
fields: ext.fields.map((field) =>
|
|
717
|
+
updateResolverField(field, params, "field", ext.targetTypeName),
|
|
718
|
+
),
|
|
719
|
+
})),
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
function updateResolverField(
|
|
724
|
+
field: GraphQLFieldDefinition,
|
|
725
|
+
params: UpdateTypeNamesParams,
|
|
726
|
+
resolverType: "query" | "mutation" | "field",
|
|
727
|
+
parentTypeName: string | null,
|
|
728
|
+
): GraphQLFieldDefinition {
|
|
729
|
+
const { generatedTypeNames, enumTypeNames, unionTypeNames } = params;
|
|
730
|
+
|
|
731
|
+
let updatedType = field.type;
|
|
732
|
+
|
|
733
|
+
// Create payload context once for all inline return type checks
|
|
734
|
+
const hasInlinePayload =
|
|
735
|
+
field.returnTypeInlineObjectProperties ||
|
|
736
|
+
field.returnTypeInlineEnumMembers ||
|
|
737
|
+
field.returnTypeInlineUnionMembers;
|
|
738
|
+
|
|
739
|
+
if (hasInlinePayload) {
|
|
740
|
+
const payloadContext: AutoTypeNameContext = {
|
|
741
|
+
kind: "resolverPayload",
|
|
742
|
+
resolverType,
|
|
743
|
+
fieldName: field.name,
|
|
744
|
+
parentTypeName,
|
|
745
|
+
fieldPath: [],
|
|
746
|
+
};
|
|
747
|
+
const payloadContextKey = getContextKey(payloadContext);
|
|
748
|
+
|
|
749
|
+
// These are mutually exclusive - a return type can only be one of:
|
|
750
|
+
// inline object, inline enum, or inline union
|
|
751
|
+
if (field.returnTypeInlineObjectProperties) {
|
|
752
|
+
// Handle inline payload objects in return type
|
|
753
|
+
const resolvedTypeName = generatedTypeNames.get(payloadContextKey);
|
|
754
|
+
if (resolvedTypeName) {
|
|
755
|
+
updatedType = { ...field.type, typeName: resolvedTypeName };
|
|
756
|
+
}
|
|
757
|
+
} else if (field.returnTypeInlineEnumMembers) {
|
|
758
|
+
// Handle inline enum in return type
|
|
759
|
+
const resolvedTypeName = enumTypeNames.get(payloadContextKey);
|
|
760
|
+
if (resolvedTypeName) {
|
|
761
|
+
updatedType = { ...field.type, typeName: resolvedTypeName };
|
|
762
|
+
}
|
|
763
|
+
} else if (field.returnTypeInlineUnionMembers) {
|
|
764
|
+
// Handle inline union in return type
|
|
765
|
+
const resolvedTypeName = unionTypeNames.get(payloadContextKey);
|
|
766
|
+
if (resolvedTypeName) {
|
|
767
|
+
updatedType = { ...field.type, typeName: resolvedTypeName };
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
if (!field.args) {
|
|
773
|
+
return {
|
|
774
|
+
...field,
|
|
775
|
+
type: updatedType,
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
const updatedArgs = field.args.map((arg) => {
|
|
780
|
+
const context: AutoTypeNameContext = {
|
|
781
|
+
kind: "resolverArg",
|
|
782
|
+
resolverType,
|
|
783
|
+
fieldName: field.name,
|
|
784
|
+
argName: arg.name,
|
|
785
|
+
parentTypeName,
|
|
786
|
+
fieldPath: [],
|
|
787
|
+
};
|
|
788
|
+
const contextKey = getContextKey(context);
|
|
789
|
+
|
|
790
|
+
// Handle inline objects
|
|
791
|
+
if (arg.inlineObjectProperties) {
|
|
792
|
+
const resolvedTypeName = generatedTypeNames.get(contextKey);
|
|
793
|
+
if (resolvedTypeName) {
|
|
794
|
+
return {
|
|
795
|
+
...arg,
|
|
796
|
+
type: {
|
|
797
|
+
...arg.type,
|
|
798
|
+
typeName: resolvedTypeName,
|
|
799
|
+
},
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
// Handle inline enums
|
|
805
|
+
if (arg.inlineEnumMembers) {
|
|
806
|
+
const resolvedTypeName = enumTypeNames.get(contextKey);
|
|
807
|
+
if (resolvedTypeName) {
|
|
808
|
+
return {
|
|
809
|
+
...arg,
|
|
810
|
+
type: {
|
|
811
|
+
...arg.type,
|
|
812
|
+
typeName: resolvedTypeName,
|
|
813
|
+
},
|
|
814
|
+
};
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
// Handle inline unions (OneOf input objects)
|
|
819
|
+
if (arg.inlineUnionMembers) {
|
|
820
|
+
const resolvedTypeName = unionTypeNames.get(contextKey);
|
|
821
|
+
if (resolvedTypeName) {
|
|
822
|
+
return {
|
|
823
|
+
...arg,
|
|
824
|
+
type: {
|
|
825
|
+
...arg.type,
|
|
826
|
+
typeName: resolvedTypeName,
|
|
827
|
+
},
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
return arg;
|
|
833
|
+
});
|
|
834
|
+
|
|
835
|
+
return {
|
|
836
|
+
...field,
|
|
837
|
+
type: updatedType,
|
|
838
|
+
args: updatedArgs,
|
|
839
|
+
};
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
function buildGeneratedTypeNamesMap(
|
|
843
|
+
inlineObjects: InlineObjectWithContext[],
|
|
844
|
+
): Map<string, string> {
|
|
845
|
+
const map = new Map<string, string>();
|
|
846
|
+
|
|
847
|
+
for (const inlineObj of inlineObjects) {
|
|
848
|
+
const typeName = generateAutoTypeName(inlineObj.context);
|
|
849
|
+
const contextKey = getContextKey(inlineObj.context);
|
|
850
|
+
map.set(contextKey, typeName);
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
return map;
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
function toScreamingSnakeCase(value: string): string {
|
|
857
|
+
return value
|
|
858
|
+
.replace(/[-\s]+/g, "_")
|
|
859
|
+
.replace(/([a-z])([A-Z])/g, "$1_$2")
|
|
860
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2")
|
|
861
|
+
.toUpperCase();
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
interface ConvertInlineEnumMembersParams {
|
|
865
|
+
readonly members: ReadonlyArray<InlineEnumMemberInfo>;
|
|
866
|
+
readonly enumName: string;
|
|
867
|
+
readonly sourceLocation: SourceLocation;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
interface ConvertEnumMembersWithDiagnosticsResult {
|
|
871
|
+
readonly enumValues: ReadonlyArray<AutoGeneratedEnumValue>;
|
|
872
|
+
readonly needsStringEnumMapping: boolean;
|
|
873
|
+
readonly diagnostics: ReadonlyArray<Diagnostic>;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
interface ConvertedMemberInfo {
|
|
877
|
+
readonly convertedName: string;
|
|
878
|
+
readonly member: InlineEnumMemberInfo;
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
function convertInlineEnumMembers(
|
|
882
|
+
params: ConvertInlineEnumMembersParams,
|
|
883
|
+
): ConvertEnumMembersWithDiagnosticsResult {
|
|
884
|
+
const { members, enumName, sourceLocation } = params;
|
|
885
|
+
let needsStringEnumMapping = false;
|
|
886
|
+
const enumValues: AutoGeneratedEnumValue[] = [];
|
|
887
|
+
const diagnostics: Diagnostic[] = [];
|
|
888
|
+
|
|
889
|
+
const convertedMembers: ConvertedMemberInfo[] = [];
|
|
890
|
+
|
|
891
|
+
for (const member of members) {
|
|
892
|
+
const convertedName = toScreamingSnakeCase(member.value);
|
|
893
|
+
convertedMembers.push({ convertedName, member });
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
const prefixDetectionResult = detectEnumPrefix({
|
|
897
|
+
enumName,
|
|
898
|
+
memberValues: convertedMembers.map((m) => m.convertedName),
|
|
899
|
+
});
|
|
900
|
+
|
|
901
|
+
const finalNameToOriginals = new Map<string, string[]>();
|
|
902
|
+
|
|
903
|
+
for (const { convertedName, member } of convertedMembers) {
|
|
904
|
+
let finalName = convertedName;
|
|
905
|
+
if (prefixDetectionResult.shouldStrip && prefixDetectionResult.prefix) {
|
|
906
|
+
finalName = stripEnumPrefix(convertedName, prefixDetectionResult.prefix);
|
|
907
|
+
needsStringEnumMapping = true;
|
|
908
|
+
} else if (convertedName !== member.value) {
|
|
909
|
+
needsStringEnumMapping = true;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
const originals = finalNameToOriginals.get(finalName) ?? [];
|
|
913
|
+
originals.push(member.value);
|
|
914
|
+
finalNameToOriginals.set(finalName, originals);
|
|
915
|
+
|
|
916
|
+
enumValues.push({
|
|
917
|
+
name: finalName,
|
|
918
|
+
originalValue: member.value,
|
|
919
|
+
description: member.description,
|
|
920
|
+
deprecated: member.deprecated,
|
|
921
|
+
});
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
for (const [finalName, originals] of finalNameToOriginals) {
|
|
925
|
+
if (originals.length > 1) {
|
|
926
|
+
diagnostics.push({
|
|
927
|
+
code: "DUPLICATE_ENUM_VALUE_AFTER_CONVERSION",
|
|
928
|
+
message: `Enum '${enumName}' has duplicate value '${finalName}' after conversion (from '${originals.join("' and '")}')`,
|
|
929
|
+
severity: "error",
|
|
930
|
+
location: sourceLocation,
|
|
931
|
+
});
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
return { enumValues, needsStringEnumMapping, diagnostics };
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
interface GenerateAutoEnumTypeResult {
|
|
939
|
+
readonly type: AutoGeneratedType;
|
|
940
|
+
readonly diagnostics: ReadonlyArray<Diagnostic>;
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
function generateAutoEnumType(
|
|
944
|
+
inlineEnum: InlineEnumWithContext,
|
|
945
|
+
typeName: string,
|
|
946
|
+
): GenerateAutoEnumTypeResult {
|
|
947
|
+
const { enumValues, needsStringEnumMapping, diagnostics } =
|
|
948
|
+
convertInlineEnumMembers({
|
|
949
|
+
members: inlineEnum.members,
|
|
950
|
+
enumName: typeName,
|
|
951
|
+
sourceLocation: inlineEnum.sourceLocation,
|
|
952
|
+
});
|
|
953
|
+
|
|
954
|
+
return {
|
|
955
|
+
type: {
|
|
956
|
+
name: typeName,
|
|
957
|
+
kind: "Enum",
|
|
958
|
+
fields: null,
|
|
959
|
+
enumValues,
|
|
960
|
+
unionMembers: null,
|
|
961
|
+
needsStringEnumMapping,
|
|
962
|
+
sourceLocation: inlineEnum.sourceLocation,
|
|
963
|
+
generatedFrom: buildGeneratedFromInfo(inlineEnum.context),
|
|
964
|
+
description: inlineEnum.externalEnumDescription,
|
|
965
|
+
resolveTypeFieldPattern: null,
|
|
966
|
+
},
|
|
967
|
+
diagnostics,
|
|
968
|
+
};
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
interface ExternalEnumRegistry {
|
|
972
|
+
readonly symbolToTypeName: Map<ts.Symbol, string>;
|
|
973
|
+
readonly symbolToContextKey: Map<ts.Symbol, string>;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
interface BuildEnumTypeNamesMapResult {
|
|
977
|
+
readonly enumTypeNames: Map<string, string>;
|
|
978
|
+
readonly externalEnumRegistry: ExternalEnumRegistry;
|
|
979
|
+
readonly uniqueInlineEnums: InlineEnumWithContext[];
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
function buildEnumTypeNamesMap(
|
|
983
|
+
inlineEnums: InlineEnumWithContext[],
|
|
984
|
+
): BuildEnumTypeNamesMapResult {
|
|
985
|
+
const enumTypeNames = new Map<string, string>();
|
|
986
|
+
const symbolToTypeName = new Map<ts.Symbol, string>();
|
|
987
|
+
const symbolToContextKey = new Map<ts.Symbol, string>();
|
|
988
|
+
const uniqueInlineEnums: InlineEnumWithContext[] = [];
|
|
989
|
+
|
|
990
|
+
for (const inlineEnum of inlineEnums) {
|
|
991
|
+
const contextKey = getContextKey(inlineEnum.context);
|
|
992
|
+
|
|
993
|
+
if (inlineEnum.externalEnumSymbol !== null) {
|
|
994
|
+
const existingTypeName = symbolToTypeName.get(
|
|
995
|
+
inlineEnum.externalEnumSymbol,
|
|
996
|
+
);
|
|
997
|
+
if (existingTypeName) {
|
|
998
|
+
enumTypeNames.set(contextKey, existingTypeName);
|
|
999
|
+
continue;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
const typeName = generateAutoTypeName(inlineEnum.context);
|
|
1003
|
+
symbolToTypeName.set(inlineEnum.externalEnumSymbol, typeName);
|
|
1004
|
+
symbolToContextKey.set(inlineEnum.externalEnumSymbol, contextKey);
|
|
1005
|
+
enumTypeNames.set(contextKey, typeName);
|
|
1006
|
+
uniqueInlineEnums.push(inlineEnum);
|
|
1007
|
+
} else {
|
|
1008
|
+
const typeName = generateAutoTypeName(inlineEnum.context);
|
|
1009
|
+
enumTypeNames.set(contextKey, typeName);
|
|
1010
|
+
uniqueInlineEnums.push(inlineEnum);
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
return {
|
|
1015
|
+
enumTypeNames,
|
|
1016
|
+
externalEnumRegistry: { symbolToTypeName, symbolToContextKey },
|
|
1017
|
+
uniqueInlineEnums,
|
|
1018
|
+
};
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
function buildUnionTypeNamesMap(
|
|
1022
|
+
inlineUnions: InlineUnionWithContext[],
|
|
1023
|
+
): Map<string, string> {
|
|
1024
|
+
const unionTypeNames = new Map<string, string>();
|
|
1025
|
+
|
|
1026
|
+
for (const inlineUnion of inlineUnions) {
|
|
1027
|
+
const contextKey = getContextKey(inlineUnion.context);
|
|
1028
|
+
const typeName = generateAutoTypeName(inlineUnion.context);
|
|
1029
|
+
unionTypeNames.set(contextKey, typeName);
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
return unionTypeNames;
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
interface ProcessInlineUnionsParams {
|
|
1036
|
+
readonly inlineUnions: ReadonlyArray<InlineUnionWithContext>;
|
|
1037
|
+
readonly knownTypeNames: ReadonlySet<string>;
|
|
1038
|
+
readonly generatedTypeNames: Map<string, string>;
|
|
1039
|
+
readonly enumTypeNames: Map<string, string>;
|
|
1040
|
+
readonly unionTypeNames: Map<string, string>;
|
|
1041
|
+
readonly extractedTypes: ReadonlyArray<ExtractedTypeInfo>;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
interface ProcessInlineUnionsResult {
|
|
1045
|
+
readonly types: AutoGeneratedType[];
|
|
1046
|
+
readonly diagnostics: Diagnostic[];
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
interface ProcessOneOfInputObjectsParams {
|
|
1050
|
+
readonly inlineUnions: ReadonlyArray<InlineUnionWithContext>;
|
|
1051
|
+
readonly knownTypeNames: ReadonlySet<string>;
|
|
1052
|
+
readonly typeMap: ReadonlyMap<string, ExtractedTypeInfo>;
|
|
1053
|
+
readonly unionTypeNames: Map<string, string>;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
function processOneOfInputObjects(
|
|
1057
|
+
params: ProcessOneOfInputObjectsParams,
|
|
1058
|
+
): ProcessInlineUnionsResult {
|
|
1059
|
+
const { inlineUnions, knownTypeNames, typeMap, unionTypeNames } = params;
|
|
1060
|
+
const types: AutoGeneratedType[] = [];
|
|
1061
|
+
const diagnostics: Diagnostic[] = [];
|
|
1062
|
+
|
|
1063
|
+
for (const inlineUnion of inlineUnions) {
|
|
1064
|
+
const contextKey = getContextKey(inlineUnion.context);
|
|
1065
|
+
const typeName = generateAutoTypeName(inlineUnion.context);
|
|
1066
|
+
|
|
1067
|
+
const validationResult = validateOneOfMembers({
|
|
1068
|
+
members: inlineUnion.members,
|
|
1069
|
+
typeName,
|
|
1070
|
+
sourceLocation: inlineUnion.sourceLocation,
|
|
1071
|
+
typeMap,
|
|
1072
|
+
});
|
|
1073
|
+
|
|
1074
|
+
diagnostics.push(...validationResult.diagnostics);
|
|
1075
|
+
|
|
1076
|
+
if (!validationResult.valid) {
|
|
1077
|
+
continue;
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
const fields = generateOneOfFields({
|
|
1081
|
+
members: inlineUnion.members,
|
|
1082
|
+
knownTypeNames,
|
|
1083
|
+
});
|
|
1084
|
+
|
|
1085
|
+
types.push({
|
|
1086
|
+
name: typeName,
|
|
1087
|
+
kind: "OneOfInputObject",
|
|
1088
|
+
fields,
|
|
1089
|
+
enumValues: null,
|
|
1090
|
+
unionMembers: null,
|
|
1091
|
+
needsStringEnumMapping: false,
|
|
1092
|
+
sourceLocation: inlineUnion.sourceLocation,
|
|
1093
|
+
generatedFrom: buildGeneratedFromInfo(inlineUnion.context),
|
|
1094
|
+
description: null,
|
|
1095
|
+
resolveTypeFieldPattern: null,
|
|
1096
|
+
});
|
|
1097
|
+
|
|
1098
|
+
unionTypeNames.set(contextKey, typeName);
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
return { types, diagnostics };
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
interface ProcessUnionTypesParams {
|
|
1105
|
+
readonly inlineUnions: ReadonlyArray<InlineUnionWithContext>;
|
|
1106
|
+
readonly knownTypeNames: ReadonlySet<string>;
|
|
1107
|
+
readonly generatedTypeNames: Map<string, string>;
|
|
1108
|
+
readonly enumTypeNames: Map<string, string>;
|
|
1109
|
+
readonly unionTypeNames: Map<string, string>;
|
|
1110
|
+
readonly typeMap: ReadonlyMap<string, ExtractedTypeInfo>;
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
function processUnionTypes(
|
|
1114
|
+
params: ProcessUnionTypesParams,
|
|
1115
|
+
): ProcessInlineUnionsResult {
|
|
1116
|
+
const {
|
|
1117
|
+
inlineUnions,
|
|
1118
|
+
knownTypeNames,
|
|
1119
|
+
generatedTypeNames,
|
|
1120
|
+
enumTypeNames,
|
|
1121
|
+
unionTypeNames,
|
|
1122
|
+
typeMap,
|
|
1123
|
+
} = params;
|
|
1124
|
+
const types: AutoGeneratedType[] = [];
|
|
1125
|
+
const diagnostics: Diagnostic[] = [];
|
|
1126
|
+
const generatedTypenameTypes = new Map<
|
|
1127
|
+
string,
|
|
1128
|
+
ReadonlyArray<AutoGeneratedField>
|
|
1129
|
+
>();
|
|
1130
|
+
|
|
1131
|
+
for (const inlineUnion of inlineUnions) {
|
|
1132
|
+
const contextKey = getContextKey(inlineUnion.context);
|
|
1133
|
+
const typeName = generateAutoTypeName(inlineUnion.context);
|
|
1134
|
+
|
|
1135
|
+
const validationResult = validateUnionMembers({
|
|
1136
|
+
members: inlineUnion.members,
|
|
1137
|
+
typeName,
|
|
1138
|
+
sourceLocation: inlineUnion.sourceLocation,
|
|
1139
|
+
typeMap,
|
|
1140
|
+
});
|
|
1141
|
+
|
|
1142
|
+
diagnostics.push(...validationResult.diagnostics);
|
|
1143
|
+
|
|
1144
|
+
if (!validationResult.valid) {
|
|
1145
|
+
continue;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
let resolveTypeFieldPattern: AutoGeneratedType["resolveTypeFieldPattern"] =
|
|
1149
|
+
null;
|
|
1150
|
+
|
|
1151
|
+
if (inlineUnion.context.kind === "resolverPayload") {
|
|
1152
|
+
const typenameValidationResult = validateUnionMemberTypenames({
|
|
1153
|
+
members: inlineUnion.members,
|
|
1154
|
+
unionTypeName: typeName,
|
|
1155
|
+
sourceLocation: inlineUnion.sourceLocation,
|
|
1156
|
+
typeMap,
|
|
1157
|
+
});
|
|
1158
|
+
|
|
1159
|
+
diagnostics.push(...typenameValidationResult.diagnostics);
|
|
1160
|
+
|
|
1161
|
+
if (!typenameValidationResult.valid) {
|
|
1162
|
+
continue;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
if (typenameValidationResult.allMembersHaveTypename) {
|
|
1166
|
+
resolveTypeFieldPattern = determineFieldPattern(
|
|
1167
|
+
typenameValidationResult.memberTypenames,
|
|
1168
|
+
);
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
const memberNames = resolveMemberNames({
|
|
1173
|
+
members: inlineUnion.members,
|
|
1174
|
+
knownTypeNames,
|
|
1175
|
+
generatedTypeNames,
|
|
1176
|
+
enumTypeNames,
|
|
1177
|
+
parentContext: inlineUnion.context,
|
|
1178
|
+
unionTypeNames,
|
|
1179
|
+
types,
|
|
1180
|
+
diagnostics,
|
|
1181
|
+
generatedTypenameTypes,
|
|
1182
|
+
sourceLocation: inlineUnion.sourceLocation,
|
|
1183
|
+
});
|
|
1184
|
+
|
|
1185
|
+
types.push({
|
|
1186
|
+
name: typeName,
|
|
1187
|
+
kind: "Union",
|
|
1188
|
+
fields: null,
|
|
1189
|
+
enumValues: null,
|
|
1190
|
+
unionMembers: memberNames,
|
|
1191
|
+
needsStringEnumMapping: false,
|
|
1192
|
+
sourceLocation: inlineUnion.sourceLocation,
|
|
1193
|
+
generatedFrom: buildGeneratedFromInfo(inlineUnion.context),
|
|
1194
|
+
description: null,
|
|
1195
|
+
resolveTypeFieldPattern,
|
|
1196
|
+
});
|
|
1197
|
+
|
|
1198
|
+
unionTypeNames.set(contextKey, typeName);
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
return { types, diagnostics };
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
/**
|
|
1205
|
+
* Determine the field pattern for resolveType based on the typename fields used by members.
|
|
1206
|
+
*/
|
|
1207
|
+
function determineFieldPattern(
|
|
1208
|
+
memberTypenames: ReadonlyMap<number, ValidatedTypenameInfo>,
|
|
1209
|
+
): ResolveTypeFieldPattern {
|
|
1210
|
+
const fieldNames = new Set<TypenameFieldName>();
|
|
1211
|
+
for (const info of memberTypenames.values()) {
|
|
1212
|
+
fieldNames.add(info.fieldName);
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
if (fieldNames.size === 0) {
|
|
1216
|
+
return { usedFieldNames: createFieldNameSet(["__typename"]) };
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
return { usedFieldNames: fieldNames };
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
function processInlineUnions(
|
|
1223
|
+
params: ProcessInlineUnionsParams,
|
|
1224
|
+
): ProcessInlineUnionsResult {
|
|
1225
|
+
const {
|
|
1226
|
+
inlineUnions,
|
|
1227
|
+
knownTypeNames,
|
|
1228
|
+
generatedTypeNames,
|
|
1229
|
+
enumTypeNames,
|
|
1230
|
+
unionTypeNames,
|
|
1231
|
+
extractedTypes,
|
|
1232
|
+
} = params;
|
|
1233
|
+
|
|
1234
|
+
const typeMap = new Map<string, ExtractedTypeInfo>();
|
|
1235
|
+
for (const typeInfo of extractedTypes) {
|
|
1236
|
+
typeMap.set(typeInfo.metadata.name, typeInfo);
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
const inputUnions = inlineUnions.filter((u) => u.isInputContext);
|
|
1240
|
+
const outputUnions = inlineUnions.filter((u) => !u.isInputContext);
|
|
1241
|
+
|
|
1242
|
+
const oneOfResult = processOneOfInputObjects({
|
|
1243
|
+
inlineUnions: inputUnions,
|
|
1244
|
+
knownTypeNames,
|
|
1245
|
+
typeMap,
|
|
1246
|
+
unionTypeNames,
|
|
1247
|
+
});
|
|
1248
|
+
|
|
1249
|
+
const unionResult = processUnionTypes({
|
|
1250
|
+
inlineUnions: outputUnions,
|
|
1251
|
+
knownTypeNames,
|
|
1252
|
+
generatedTypeNames,
|
|
1253
|
+
enumTypeNames,
|
|
1254
|
+
unionTypeNames,
|
|
1255
|
+
typeMap,
|
|
1256
|
+
});
|
|
1257
|
+
|
|
1258
|
+
return {
|
|
1259
|
+
types: [...oneOfResult.types, ...unionResult.types],
|
|
1260
|
+
diagnostics: [...oneOfResult.diagnostics, ...unionResult.diagnostics],
|
|
1261
|
+
};
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
interface GenerateOneOfFieldsParams {
|
|
1265
|
+
readonly members: ReadonlyArray<InlineUnionMemberInfo>;
|
|
1266
|
+
readonly knownTypeNames: ReadonlySet<string>;
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
function generateOneOfFields(
|
|
1270
|
+
params: GenerateOneOfFieldsParams,
|
|
1271
|
+
): AutoGeneratedField[] {
|
|
1272
|
+
const { members, knownTypeNames } = params;
|
|
1273
|
+
|
|
1274
|
+
const fields: AutoGeneratedField[] = [];
|
|
1275
|
+
|
|
1276
|
+
for (const member of members) {
|
|
1277
|
+
const memberType = member.memberType;
|
|
1278
|
+
|
|
1279
|
+
if (
|
|
1280
|
+
memberType.kind === "inlineObject" &&
|
|
1281
|
+
memberType.inlineObjectProperties
|
|
1282
|
+
) {
|
|
1283
|
+
for (const prop of memberType.inlineObjectProperties) {
|
|
1284
|
+
const fieldType = convertTsTypeToGraphQLType(
|
|
1285
|
+
prop.tsType,
|
|
1286
|
+
prop.optional,
|
|
1287
|
+
);
|
|
1288
|
+
fields.push({
|
|
1289
|
+
name: prop.name,
|
|
1290
|
+
type: {
|
|
1291
|
+
...fieldType,
|
|
1292
|
+
nullable: true,
|
|
1293
|
+
},
|
|
1294
|
+
description: prop.description,
|
|
1295
|
+
deprecated: prop.deprecated,
|
|
1296
|
+
directives: prop.directives,
|
|
1297
|
+
defaultValue: prop.defaultValue,
|
|
1298
|
+
});
|
|
1299
|
+
}
|
|
1300
|
+
} else if (memberType.kind === "reference" && memberType.name) {
|
|
1301
|
+
if (knownTypeNames.has(memberType.name)) {
|
|
1302
|
+
const camelCaseName =
|
|
1303
|
+
memberType.name.charAt(0).toLowerCase() + memberType.name.slice(1);
|
|
1304
|
+
fields.push({
|
|
1305
|
+
name: camelCaseName,
|
|
1306
|
+
type: {
|
|
1307
|
+
typeName: memberType.name,
|
|
1308
|
+
nullable: true,
|
|
1309
|
+
list: false,
|
|
1310
|
+
listItemNullable: null,
|
|
1311
|
+
},
|
|
1312
|
+
description: null,
|
|
1313
|
+
deprecated: null,
|
|
1314
|
+
directives: null,
|
|
1315
|
+
defaultValue: null,
|
|
1316
|
+
});
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
return fields;
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
interface ResolveMemberNamesParams {
|
|
1325
|
+
readonly members: ReadonlyArray<InlineUnionMemberInfo>;
|
|
1326
|
+
readonly knownTypeNames: ReadonlySet<string>;
|
|
1327
|
+
readonly generatedTypeNames: Map<string, string>;
|
|
1328
|
+
readonly enumTypeNames: Map<string, string>;
|
|
1329
|
+
readonly parentContext: AutoTypeNameContext;
|
|
1330
|
+
readonly unionTypeNames: Map<string, string>;
|
|
1331
|
+
readonly types: AutoGeneratedType[];
|
|
1332
|
+
readonly diagnostics: Diagnostic[];
|
|
1333
|
+
readonly generatedTypenameTypes: Map<
|
|
1334
|
+
string,
|
|
1335
|
+
ReadonlyArray<AutoGeneratedField>
|
|
1336
|
+
>;
|
|
1337
|
+
readonly sourceLocation: SourceLocation;
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
/**
|
|
1341
|
+
* Extract __typename or $typeName property value from inline object properties.
|
|
1342
|
+
* Returns null if neither is found or neither is a valid string literal.
|
|
1343
|
+
* __typename takes priority over $typeName if both are present.
|
|
1344
|
+
*/
|
|
1345
|
+
function extractTypenameFromInlineObject(
|
|
1346
|
+
properties: ReadonlyArray<InlineObjectPropertyDef>,
|
|
1347
|
+
): TypenameFieldInfo | null {
|
|
1348
|
+
const found = findTypenameProperty(properties, (p) => p.name);
|
|
1349
|
+
if (!found) {
|
|
1350
|
+
return null;
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
const { property, fieldName } = found;
|
|
1354
|
+
const { tsType } = property;
|
|
1355
|
+
|
|
1356
|
+
if (tsType.kind === "literal" && tsType.name !== null) {
|
|
1357
|
+
return { typeName: tsType.name, fieldName };
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
return null;
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
function resolveMemberNames(params: ResolveMemberNamesParams): string[] {
|
|
1364
|
+
const {
|
|
1365
|
+
members,
|
|
1366
|
+
generatedTypeNames,
|
|
1367
|
+
parentContext,
|
|
1368
|
+
types,
|
|
1369
|
+
generatedTypenameTypes,
|
|
1370
|
+
diagnostics,
|
|
1371
|
+
sourceLocation,
|
|
1372
|
+
} = params;
|
|
1373
|
+
|
|
1374
|
+
const memberNames: string[] = [];
|
|
1375
|
+
|
|
1376
|
+
for (let i = 0; i < members.length; i++) {
|
|
1377
|
+
const member = members[i]!;
|
|
1378
|
+
const memberType = member.memberType;
|
|
1379
|
+
|
|
1380
|
+
if (memberType.kind === "reference" && memberType.name) {
|
|
1381
|
+
memberNames.push(memberType.name);
|
|
1382
|
+
} else if (
|
|
1383
|
+
memberType.kind === "inlineObject" &&
|
|
1384
|
+
memberType.inlineObjectProperties
|
|
1385
|
+
) {
|
|
1386
|
+
// Only extract __typename or $typeName for resolverPayload context
|
|
1387
|
+
// For other contexts (resolverArg, objectField, inputField), these fields
|
|
1388
|
+
// should be treated as regular fields, not as type discriminators
|
|
1389
|
+
const extractedInfo =
|
|
1390
|
+
parentContext.kind === "resolverPayload"
|
|
1391
|
+
? extractTypenameFromInlineObject(memberType.inlineObjectProperties)
|
|
1392
|
+
: null;
|
|
1393
|
+
|
|
1394
|
+
let memberTypeName: string;
|
|
1395
|
+
let contextKey: string;
|
|
1396
|
+
|
|
1397
|
+
if (extractedInfo !== null) {
|
|
1398
|
+
memberTypeName = extractedInfo.typeName;
|
|
1399
|
+
const nestedContext: AutoTypeNameContext = {
|
|
1400
|
+
...parentContext,
|
|
1401
|
+
fieldPath: [...parentContext.fieldPath, extractedInfo.typeName],
|
|
1402
|
+
};
|
|
1403
|
+
contextKey = getContextKey(nestedContext);
|
|
1404
|
+
} else {
|
|
1405
|
+
const nestedContext: AutoTypeNameContext = {
|
|
1406
|
+
...parentContext,
|
|
1407
|
+
fieldPath: [...parentContext.fieldPath, `member${i}`],
|
|
1408
|
+
};
|
|
1409
|
+
memberTypeName = generateAutoTypeName(nestedContext);
|
|
1410
|
+
contextKey = getContextKey(nestedContext);
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
// Only filter out __typename or $typeName for resolverPayload context
|
|
1414
|
+
// For other contexts, these are regular fields that should be preserved
|
|
1415
|
+
const typenameFieldToFilter = extractedInfo?.fieldName ?? null;
|
|
1416
|
+
const fields: AutoGeneratedField[] = memberType.inlineObjectProperties
|
|
1417
|
+
.filter(
|
|
1418
|
+
(prop) =>
|
|
1419
|
+
parentContext.kind !== "resolverPayload" ||
|
|
1420
|
+
prop.name !== typenameFieldToFilter,
|
|
1421
|
+
)
|
|
1422
|
+
.map((prop) => {
|
|
1423
|
+
const fieldType = convertTsTypeToGraphQLType(
|
|
1424
|
+
prop.tsType,
|
|
1425
|
+
prop.optional,
|
|
1426
|
+
);
|
|
1427
|
+
return {
|
|
1428
|
+
name: prop.name,
|
|
1429
|
+
type: fieldType,
|
|
1430
|
+
description: prop.description,
|
|
1431
|
+
deprecated: prop.deprecated,
|
|
1432
|
+
directives: prop.directives,
|
|
1433
|
+
defaultValue: prop.defaultValue,
|
|
1434
|
+
};
|
|
1435
|
+
});
|
|
1436
|
+
|
|
1437
|
+
// Check if this typename was already seen with a different field structure
|
|
1438
|
+
if (extractedInfo !== null) {
|
|
1439
|
+
const existingFields = generatedTypenameTypes.get(
|
|
1440
|
+
extractedInfo.typeName,
|
|
1441
|
+
);
|
|
1442
|
+
if (existingFields !== undefined) {
|
|
1443
|
+
// Compare field structures
|
|
1444
|
+
if (!areFieldStructuresEqual(existingFields, fields)) {
|
|
1445
|
+
diagnostics.push({
|
|
1446
|
+
code: "TYPENAME_FIELD_STRUCTURE_MISMATCH",
|
|
1447
|
+
message: `Type with ${extractedInfo.fieldName} '${extractedInfo.typeName}' has inconsistent field structures across different union members. All types with the same ${extractedInfo.fieldName} must have identical field definitions.`,
|
|
1448
|
+
severity: "error",
|
|
1449
|
+
location: sourceLocation,
|
|
1450
|
+
});
|
|
1451
|
+
}
|
|
1452
|
+
// Skip generating duplicate type and avoid adding duplicate union member
|
|
1453
|
+
if (!memberNames.includes(memberTypeName)) {
|
|
1454
|
+
memberNames.push(memberTypeName);
|
|
1455
|
+
}
|
|
1456
|
+
continue;
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
const nestedContext: AutoTypeNameContext = {
|
|
1461
|
+
...parentContext,
|
|
1462
|
+
fieldPath: [
|
|
1463
|
+
...parentContext.fieldPath,
|
|
1464
|
+
extractedInfo?.typeName ?? `member${i}`,
|
|
1465
|
+
],
|
|
1466
|
+
};
|
|
1467
|
+
|
|
1468
|
+
types.push({
|
|
1469
|
+
name: memberTypeName,
|
|
1470
|
+
kind: "Object",
|
|
1471
|
+
fields,
|
|
1472
|
+
enumValues: null,
|
|
1473
|
+
unionMembers: null,
|
|
1474
|
+
needsStringEnumMapping: false,
|
|
1475
|
+
sourceLocation: {
|
|
1476
|
+
file: "",
|
|
1477
|
+
line: 1,
|
|
1478
|
+
column: 1,
|
|
1479
|
+
},
|
|
1480
|
+
generatedFrom: buildGeneratedFromInfo(nestedContext),
|
|
1481
|
+
description: memberType.inlineObjectDescription,
|
|
1482
|
+
resolveTypeFieldPattern: null,
|
|
1483
|
+
});
|
|
1484
|
+
|
|
1485
|
+
generatedTypeNames.set(contextKey, memberTypeName);
|
|
1486
|
+
if (extractedInfo !== null) {
|
|
1487
|
+
generatedTypenameTypes.set(extractedInfo.typeName, fields);
|
|
1488
|
+
}
|
|
1489
|
+
memberNames.push(memberTypeName);
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
return memberNames;
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
/**
|
|
1497
|
+
* Compare two field structures for equality.
|
|
1498
|
+
* Returns true if both have the same fields with the same types.
|
|
1499
|
+
*/
|
|
1500
|
+
function areFieldStructuresEqual(
|
|
1501
|
+
fields1: ReadonlyArray<AutoGeneratedField>,
|
|
1502
|
+
fields2: ReadonlyArray<AutoGeneratedField>,
|
|
1503
|
+
): boolean {
|
|
1504
|
+
if (fields1.length !== fields2.length) {
|
|
1505
|
+
return false;
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
const sorted1 = [...fields1].sort((a, b) => a.name.localeCompare(b.name));
|
|
1509
|
+
const sorted2 = [...fields2].sort((a, b) => a.name.localeCompare(b.name));
|
|
1510
|
+
|
|
1511
|
+
for (let i = 0; i < sorted1.length; i++) {
|
|
1512
|
+
const f1 = sorted1[i]!;
|
|
1513
|
+
const f2 = sorted2[i]!;
|
|
1514
|
+
|
|
1515
|
+
if (f1.name !== f2.name) {
|
|
1516
|
+
return false;
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
if (!areGraphQLTypesEqual(f1.type, f2.type)) {
|
|
1520
|
+
return false;
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
return true;
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
/**
|
|
1528
|
+
* Compare two GraphQL type references for equality.
|
|
1529
|
+
*/
|
|
1530
|
+
function areGraphQLTypesEqual(
|
|
1531
|
+
type1: GraphQLFieldType,
|
|
1532
|
+
type2: GraphQLFieldType,
|
|
1533
|
+
): boolean {
|
|
1534
|
+
if (type1.typeName !== type2.typeName) {
|
|
1535
|
+
return false;
|
|
1536
|
+
}
|
|
1537
|
+
if (type1.nullable !== type2.nullable) {
|
|
1538
|
+
return false;
|
|
1539
|
+
}
|
|
1540
|
+
if (type1.list !== type2.list) {
|
|
1541
|
+
return false;
|
|
1542
|
+
}
|
|
1543
|
+
if (type1.listItemNullable !== type2.listItemNullable) {
|
|
1544
|
+
return false;
|
|
1545
|
+
}
|
|
1546
|
+
return true;
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
export function generateAutoTypes(
|
|
1550
|
+
input: AutoTypeGeneratorInput,
|
|
1551
|
+
): AutoTypeGeneratorResult {
|
|
1552
|
+
const inlineObjectsFromTypes: InlineObjectWithContext[] = [];
|
|
1553
|
+
for (const typeInfo of input.extractedTypes) {
|
|
1554
|
+
inlineObjectsFromTypes.push(...collectInlineObjectsFromType(typeInfo));
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
const inlineObjectsFromResolvers = collectInlineObjectsFromResolvers(
|
|
1558
|
+
input.resolversResult,
|
|
1559
|
+
);
|
|
1560
|
+
|
|
1561
|
+
const inlinePayloadsFromResolvers = collectInlinePayloadsFromResolvers(
|
|
1562
|
+
input.resolversResult,
|
|
1563
|
+
);
|
|
1564
|
+
|
|
1565
|
+
const allInlineObjects = [
|
|
1566
|
+
...inlineObjectsFromTypes,
|
|
1567
|
+
...inlineObjectsFromResolvers,
|
|
1568
|
+
...inlinePayloadsFromResolvers,
|
|
1569
|
+
];
|
|
1570
|
+
|
|
1571
|
+
const generatedTypeNames = buildGeneratedTypeNamesMap(allInlineObjects);
|
|
1572
|
+
|
|
1573
|
+
const inlineEnumsFromTypes = collectInlineEnumsFromTypes(
|
|
1574
|
+
input.extractedTypes,
|
|
1575
|
+
);
|
|
1576
|
+
const inlineEnumsFromResolvers = collectInlineEnumsFromResolvers({
|
|
1577
|
+
resolversResult: input.resolversResult,
|
|
1578
|
+
});
|
|
1579
|
+
const inlineEnumsFromPayloads = collectInlineEnumsFromPayloads({
|
|
1580
|
+
resolversResult: input.resolversResult,
|
|
1581
|
+
});
|
|
1582
|
+
const allInlineEnums = [
|
|
1583
|
+
...inlineEnumsFromTypes,
|
|
1584
|
+
...inlineEnumsFromResolvers,
|
|
1585
|
+
...inlineEnumsFromPayloads,
|
|
1586
|
+
];
|
|
1587
|
+
|
|
1588
|
+
const { enumTypeNames, uniqueInlineEnums } =
|
|
1589
|
+
buildEnumTypeNamesMap(allInlineEnums);
|
|
1590
|
+
|
|
1591
|
+
// Collect inline unions from types, resolvers, and payloads
|
|
1592
|
+
const inlineUnionsFromTypes = collectInlineUnionsFromTypes({
|
|
1593
|
+
extractedTypes: input.extractedTypes,
|
|
1594
|
+
knownTypeNames: input.knownTypeNames,
|
|
1595
|
+
});
|
|
1596
|
+
const inlineUnionsFromResolvers = collectInlineUnionsFromResolvers({
|
|
1597
|
+
resolversResult: input.resolversResult,
|
|
1598
|
+
knownTypeNames: input.knownTypeNames,
|
|
1599
|
+
});
|
|
1600
|
+
const inlineUnionsFromPayloads = collectInlineUnionsFromPayloads({
|
|
1601
|
+
resolversResult: input.resolversResult,
|
|
1602
|
+
knownTypeNames: input.knownTypeNames,
|
|
1603
|
+
});
|
|
1604
|
+
const allInlineUnions = [
|
|
1605
|
+
...inlineUnionsFromTypes,
|
|
1606
|
+
...inlineUnionsFromResolvers,
|
|
1607
|
+
...inlineUnionsFromPayloads,
|
|
1608
|
+
];
|
|
1609
|
+
|
|
1610
|
+
// Build union type names map before generating auto types
|
|
1611
|
+
const unionTypeNames = buildUnionTypeNamesMap(allInlineUnions);
|
|
1612
|
+
|
|
1613
|
+
const autoGeneratedTypes: AutoGeneratedType[] = [];
|
|
1614
|
+
const diagnostics: Diagnostic[] = [];
|
|
1615
|
+
|
|
1616
|
+
for (const inlineObj of allInlineObjects) {
|
|
1617
|
+
const result = generateAutoType({
|
|
1618
|
+
inlineObj,
|
|
1619
|
+
generatedTypeNames,
|
|
1620
|
+
enumTypeNames,
|
|
1621
|
+
unionTypeNames,
|
|
1622
|
+
});
|
|
1623
|
+
autoGeneratedTypes.push(result.type);
|
|
1624
|
+
diagnostics.push(...result.diagnostics);
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
for (const inlineEnum of uniqueInlineEnums) {
|
|
1628
|
+
const contextKey = getContextKey(inlineEnum.context);
|
|
1629
|
+
const typeName = enumTypeNames.get(contextKey)!;
|
|
1630
|
+
const result = generateAutoEnumType(inlineEnum, typeName);
|
|
1631
|
+
autoGeneratedTypes.push(result.type);
|
|
1632
|
+
diagnostics.push(...result.diagnostics);
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
// Process inline unions
|
|
1636
|
+
const { types: unionTypes, diagnostics: unionDiagnostics } =
|
|
1637
|
+
processInlineUnions({
|
|
1638
|
+
inlineUnions: allInlineUnions,
|
|
1639
|
+
knownTypeNames: input.knownTypeNames,
|
|
1640
|
+
generatedTypeNames,
|
|
1641
|
+
enumTypeNames,
|
|
1642
|
+
unionTypeNames,
|
|
1643
|
+
extractedTypes: input.extractedTypes,
|
|
1644
|
+
});
|
|
1645
|
+
autoGeneratedTypes.push(...unionTypes);
|
|
1646
|
+
diagnostics.push(...unionDiagnostics);
|
|
1647
|
+
|
|
1648
|
+
const updateParams: UpdateTypeNamesParams = {
|
|
1649
|
+
generatedTypeNames,
|
|
1650
|
+
enumTypeNames,
|
|
1651
|
+
unionTypeNames,
|
|
1652
|
+
};
|
|
1653
|
+
|
|
1654
|
+
const updatedExtractedTypes = updateExtractedTypes(
|
|
1655
|
+
input.extractedTypes,
|
|
1656
|
+
updateParams,
|
|
1657
|
+
);
|
|
1658
|
+
|
|
1659
|
+
const updatedResolversResult = updateResolversResult(
|
|
1660
|
+
input.resolversResult,
|
|
1661
|
+
updateParams,
|
|
1662
|
+
);
|
|
1663
|
+
|
|
1664
|
+
return {
|
|
1665
|
+
autoGeneratedTypes,
|
|
1666
|
+
updatedExtractedTypes,
|
|
1667
|
+
updatedResolversResult,
|
|
1668
|
+
diagnostics,
|
|
1669
|
+
};
|
|
1670
|
+
}
|