@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,211 @@
|
|
|
1
|
+
import type { GraphQLTypeInfo } from "../type-extractor/types/graphql.js";
|
|
2
|
+
import type { Diagnostic } from "../type-extractor/types/index.js";
|
|
3
|
+
|
|
4
|
+
export interface InterfaceValidationResult {
|
|
5
|
+
readonly isValid: boolean;
|
|
6
|
+
readonly diagnostics: ReadonlyArray<Diagnostic>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function validateInterfaceImplementations(
|
|
10
|
+
types: ReadonlyArray<GraphQLTypeInfo>,
|
|
11
|
+
): InterfaceValidationResult {
|
|
12
|
+
const diagnostics: Diagnostic[] = [];
|
|
13
|
+
const typeMap = new Map<string, GraphQLTypeInfo>();
|
|
14
|
+
|
|
15
|
+
for (const type of types) {
|
|
16
|
+
typeMap.set(type.name, type);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
for (const type of types) {
|
|
20
|
+
if (
|
|
21
|
+
!type.implementedInterfaces ||
|
|
22
|
+
type.implementedInterfaces.length === 0
|
|
23
|
+
) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
for (const interfaceName of type.implementedInterfaces) {
|
|
28
|
+
const interfaceType = typeMap.get(interfaceName);
|
|
29
|
+
|
|
30
|
+
if (!interfaceType) {
|
|
31
|
+
diagnostics.push({
|
|
32
|
+
code: "INTERFACE_NOT_FOUND",
|
|
33
|
+
message: `Type '${type.name}' implements unknown interface '${interfaceName}'`,
|
|
34
|
+
severity: "error",
|
|
35
|
+
location: {
|
|
36
|
+
file: type.sourceFile,
|
|
37
|
+
line: 1,
|
|
38
|
+
column: 1,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (interfaceType.kind !== "Interface") {
|
|
45
|
+
diagnostics.push({
|
|
46
|
+
code: "INTERFACE_NOT_INTERFACE",
|
|
47
|
+
message: `Type '${type.name}' attempts to implement '${interfaceName}' which is not an interface`,
|
|
48
|
+
severity: "error",
|
|
49
|
+
location: {
|
|
50
|
+
file: type.sourceFile,
|
|
51
|
+
line: 1,
|
|
52
|
+
column: 1,
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!interfaceType.fields) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const typeFields = new Map(type.fields?.map((f) => [f.name, f]) ?? []);
|
|
63
|
+
|
|
64
|
+
for (const interfaceField of interfaceType.fields) {
|
|
65
|
+
const typeField = typeFields.get(interfaceField.name);
|
|
66
|
+
|
|
67
|
+
if (!typeField) {
|
|
68
|
+
diagnostics.push({
|
|
69
|
+
code: "INTERFACE_MISSING_FIELD",
|
|
70
|
+
message: `Type '${type.name}' implements interface '${interfaceName}' but is missing field '${interfaceField.name}'`,
|
|
71
|
+
severity: "error",
|
|
72
|
+
location: {
|
|
73
|
+
file: type.sourceFile,
|
|
74
|
+
line: 1,
|
|
75
|
+
column: 1,
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (!isTypeCompatible(typeField.type, interfaceField.type)) {
|
|
82
|
+
diagnostics.push({
|
|
83
|
+
code: "INTERFACE_FIELD_TYPE_MISMATCH",
|
|
84
|
+
message: `Type '${type.name}' field '${interfaceField.name}' has incompatible type with interface '${interfaceName}'`,
|
|
85
|
+
severity: "error",
|
|
86
|
+
location: {
|
|
87
|
+
file: type.sourceFile,
|
|
88
|
+
line: 1,
|
|
89
|
+
column: 1,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
isValid: diagnostics.length === 0,
|
|
99
|
+
diagnostics,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
interface FieldType {
|
|
104
|
+
readonly typeName: string;
|
|
105
|
+
readonly nullable: boolean;
|
|
106
|
+
readonly list: boolean;
|
|
107
|
+
readonly listItemNullable?: boolean | null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function isTypeCompatible(
|
|
111
|
+
implementingType: FieldType,
|
|
112
|
+
interfaceType: FieldType,
|
|
113
|
+
): boolean {
|
|
114
|
+
if (implementingType.typeName !== interfaceType.typeName) {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (implementingType.list !== interfaceType.list) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (implementingType.nullable && !interfaceType.nullable) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (implementingType.list) {
|
|
127
|
+
if (implementingType.listItemNullable && !interfaceType.listItemNullable) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function detectCircularInterfaceReferences(
|
|
136
|
+
types: ReadonlyArray<GraphQLTypeInfo>,
|
|
137
|
+
): InterfaceValidationResult {
|
|
138
|
+
const diagnostics: Diagnostic[] = [];
|
|
139
|
+
const typeMap = new Map<string, GraphQLTypeInfo>();
|
|
140
|
+
const reportedCycles = new Set<string>();
|
|
141
|
+
|
|
142
|
+
for (const type of types) {
|
|
143
|
+
if (type.kind === "Interface") {
|
|
144
|
+
typeMap.set(type.name, type);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
for (const type of types) {
|
|
149
|
+
if (type.kind !== "Interface" || !type.implementedInterfaces) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const cyclePath = findCircularReference(type.name, typeMap, new Set(), []);
|
|
154
|
+
if (cyclePath) {
|
|
155
|
+
const cycleStart = cyclePath.indexOf(cyclePath[cyclePath.length - 1]!);
|
|
156
|
+
const cycleMembers = cyclePath.slice(cycleStart, -1);
|
|
157
|
+
const cycleKey = [...cycleMembers].sort().join(",");
|
|
158
|
+
if (!reportedCycles.has(cycleKey)) {
|
|
159
|
+
reportedCycles.add(cycleKey);
|
|
160
|
+
diagnostics.push({
|
|
161
|
+
code: "INTERFACE_CIRCULAR_REFERENCE",
|
|
162
|
+
message: `Circular interface inheritance detected: ${cyclePath.join(" -> ")}`,
|
|
163
|
+
severity: "error",
|
|
164
|
+
location: {
|
|
165
|
+
file: type.sourceFile,
|
|
166
|
+
line: 1,
|
|
167
|
+
column: 1,
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return {
|
|
175
|
+
isValid: diagnostics.length === 0,
|
|
176
|
+
diagnostics,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function findCircularReference(
|
|
181
|
+
typeName: string,
|
|
182
|
+
typeMap: Map<string, GraphQLTypeInfo>,
|
|
183
|
+
visited: Set<string>,
|
|
184
|
+
path: string[],
|
|
185
|
+
): string[] | null {
|
|
186
|
+
if (visited.has(typeName)) {
|
|
187
|
+
return [...path, typeName];
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
visited.add(typeName);
|
|
191
|
+
path.push(typeName);
|
|
192
|
+
|
|
193
|
+
const type = typeMap.get(typeName);
|
|
194
|
+
if (!type || !type.implementedInterfaces) {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
for (const interfaceName of type.implementedInterfaces) {
|
|
199
|
+
const result = findCircularReference(
|
|
200
|
+
interfaceName,
|
|
201
|
+
typeMap,
|
|
202
|
+
new Set(visited),
|
|
203
|
+
[...path],
|
|
204
|
+
);
|
|
205
|
+
if (result) {
|
|
206
|
+
return result;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scalar metadata detector.
|
|
3
|
+
*
|
|
4
|
+
* This module provides functions to detect scalar metadata embedded
|
|
5
|
+
* in TypeScript intersection types using the $gqlkitScalar property.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import ts from "typescript";
|
|
9
|
+
import { METADATA_PROPERTIES } from "./constants.js";
|
|
10
|
+
import { isNullOrUndefined } from "./typescript-utils.js";
|
|
11
|
+
|
|
12
|
+
const SCALAR_METADATA_PROPERTY = METADATA_PROPERTIES.SCALAR;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Error information for mixed scalar union detection.
|
|
16
|
+
*/
|
|
17
|
+
export interface ScalarMetadataError {
|
|
18
|
+
readonly code: "MIXED_SCALAR_UNION";
|
|
19
|
+
readonly message: string;
|
|
20
|
+
readonly scalarNames: ReadonlyArray<string>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Result of scalar metadata detection.
|
|
25
|
+
*/
|
|
26
|
+
export interface ScalarMetadataResult {
|
|
27
|
+
/** The GraphQL scalar name if detected, null otherwise */
|
|
28
|
+
readonly scalarName: string | null;
|
|
29
|
+
/** Usage constraint: "input", "output", or null for both */
|
|
30
|
+
readonly only: "input" | "output" | null;
|
|
31
|
+
/** Whether the type is nullable (union with null) */
|
|
32
|
+
readonly nullable: boolean;
|
|
33
|
+
/** Whether the type is a list (array type) */
|
|
34
|
+
readonly isList: boolean;
|
|
35
|
+
/** Whether list items are nullable (for list types) */
|
|
36
|
+
readonly listItemNullable: boolean;
|
|
37
|
+
/** Whether this is a TypeScript primitive type */
|
|
38
|
+
readonly isPrimitive: boolean;
|
|
39
|
+
/** Whether this is an object type (not a scalar) */
|
|
40
|
+
readonly isObjectType: boolean;
|
|
41
|
+
/** Error if mixed scalar union is detected */
|
|
42
|
+
readonly error: ScalarMetadataError | undefined;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface InternalMetadata {
|
|
46
|
+
scalarName: string | null;
|
|
47
|
+
only: "input" | "output" | null;
|
|
48
|
+
isPrimitive: boolean;
|
|
49
|
+
isObjectType: boolean;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function createDefaultResult(): ScalarMetadataResult {
|
|
53
|
+
return {
|
|
54
|
+
scalarName: null,
|
|
55
|
+
only: null,
|
|
56
|
+
nullable: false,
|
|
57
|
+
isList: false,
|
|
58
|
+
listItemNullable: false,
|
|
59
|
+
isPrimitive: false,
|
|
60
|
+
isObjectType: false,
|
|
61
|
+
error: undefined,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Extracts the actual type from an optional property type (T | undefined).
|
|
67
|
+
* Used by both scalar and resolver metadata detection.
|
|
68
|
+
*
|
|
69
|
+
* For simple cases like `T | undefined`, returns T.
|
|
70
|
+
* For union cases like `T | null | undefined`, returns the original union type
|
|
71
|
+
* so the caller can analyze it (e.g., check for null members).
|
|
72
|
+
* For boolean types (true | false | undefined), reconstructs the boolean type.
|
|
73
|
+
*
|
|
74
|
+
* @param metadataType - The type of the metadata property (may be union with undefined)
|
|
75
|
+
* @returns The actual type excluding undefined, or null if extraction fails
|
|
76
|
+
*/
|
|
77
|
+
export function getActualMetadataType(metadataType: ts.Type): ts.Type | null {
|
|
78
|
+
if (metadataType.isUnion()) {
|
|
79
|
+
const nonUndefinedTypes = metadataType.types.filter(
|
|
80
|
+
(t) => !(t.flags & ts.TypeFlags.Undefined),
|
|
81
|
+
);
|
|
82
|
+
if (nonUndefinedTypes.length === 1) {
|
|
83
|
+
return nonUndefinedTypes[0]!;
|
|
84
|
+
}
|
|
85
|
+
// Special case: boolean (true | false) optionally with undefined
|
|
86
|
+
// TypeScript represents boolean | undefined as true | false | undefined
|
|
87
|
+
if (
|
|
88
|
+
nonUndefinedTypes.length === 2 &&
|
|
89
|
+
nonUndefinedTypes.every((t) => t.flags & ts.TypeFlags.BooleanLiteral)
|
|
90
|
+
) {
|
|
91
|
+
// This is effectively "boolean" - return the first member to preserve
|
|
92
|
+
// the boolean literal nature, or we could return the union
|
|
93
|
+
return metadataType;
|
|
94
|
+
}
|
|
95
|
+
// If there are multiple non-undefined types (e.g., string | null),
|
|
96
|
+
// return the original metadataType. The caller should analyze this
|
|
97
|
+
// union type and handle null members appropriately.
|
|
98
|
+
if (nonUndefinedTypes.length > 1) {
|
|
99
|
+
// Return the original type - caller will need to filter out undefined
|
|
100
|
+
// when checking for nullability
|
|
101
|
+
return metadataType;
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
return metadataType;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function extractMetadataFromType(
|
|
109
|
+
type: ts.Type,
|
|
110
|
+
checker: ts.TypeChecker,
|
|
111
|
+
): InternalMetadata | null {
|
|
112
|
+
const metadataProp = type.getProperty(SCALAR_METADATA_PROPERTY);
|
|
113
|
+
if (!metadataProp) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const rawMetadataType = checker.getTypeOfSymbol(metadataProp);
|
|
118
|
+
const metadataType = getActualMetadataType(rawMetadataType);
|
|
119
|
+
if (!metadataType) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const nameProp = metadataType.getProperty("name");
|
|
124
|
+
if (!nameProp) {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const nameType = checker.getTypeOfSymbol(nameProp);
|
|
129
|
+
if (!(nameType.flags & ts.TypeFlags.StringLiteral)) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const scalarName = (nameType as ts.StringLiteralType).value;
|
|
134
|
+
|
|
135
|
+
const onlyProp = metadataType.getProperty("only");
|
|
136
|
+
let only: "input" | "output" | null = null;
|
|
137
|
+
if (onlyProp) {
|
|
138
|
+
const onlyType = checker.getTypeOfSymbol(onlyProp);
|
|
139
|
+
if (onlyType.flags & ts.TypeFlags.StringLiteral) {
|
|
140
|
+
const onlyValue = (onlyType as ts.StringLiteralType).value;
|
|
141
|
+
if (onlyValue === "input" || onlyValue === "output") {
|
|
142
|
+
only = onlyValue;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
scalarName,
|
|
149
|
+
only,
|
|
150
|
+
isPrimitive: false,
|
|
151
|
+
isObjectType: false,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function detectScalarMetadataFromIntersection(
|
|
156
|
+
type: ts.Type,
|
|
157
|
+
checker: ts.TypeChecker,
|
|
158
|
+
): InternalMetadata | null {
|
|
159
|
+
if (!type.isIntersection()) {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
for (const member of type.types) {
|
|
164
|
+
const metadata = extractMetadataFromType(member, checker);
|
|
165
|
+
if (metadata) {
|
|
166
|
+
return metadata;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function detectPrimitiveScalar(type: ts.Type): InternalMetadata | null {
|
|
174
|
+
if (type.flags & ts.TypeFlags.String) {
|
|
175
|
+
return {
|
|
176
|
+
scalarName: "String",
|
|
177
|
+
only: null,
|
|
178
|
+
isPrimitive: true,
|
|
179
|
+
isObjectType: false,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
if (type.flags & ts.TypeFlags.Number) {
|
|
183
|
+
return {
|
|
184
|
+
scalarName: "Float",
|
|
185
|
+
only: null,
|
|
186
|
+
isPrimitive: true,
|
|
187
|
+
isObjectType: false,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
if (
|
|
191
|
+
type.flags & ts.TypeFlags.Boolean ||
|
|
192
|
+
type.flags & ts.TypeFlags.BooleanLiteral
|
|
193
|
+
) {
|
|
194
|
+
return {
|
|
195
|
+
scalarName: "Boolean",
|
|
196
|
+
only: null,
|
|
197
|
+
isPrimitive: true,
|
|
198
|
+
isObjectType: false,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function isBooleanLiteralUnion(types: readonly ts.Type[]): boolean {
|
|
206
|
+
const nonNullTypes = types.filter((t) => !isNullOrUndefined(t));
|
|
207
|
+
return (
|
|
208
|
+
nonNullTypes.length === 2 &&
|
|
209
|
+
nonNullTypes.every((t) => t.flags & ts.TypeFlags.BooleanLiteral)
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function detectScalarMetadataCore(
|
|
214
|
+
type: ts.Type,
|
|
215
|
+
checker: ts.TypeChecker,
|
|
216
|
+
): InternalMetadata | null {
|
|
217
|
+
const primitiveResult = detectPrimitiveScalar(type);
|
|
218
|
+
if (primitiveResult) {
|
|
219
|
+
return primitiveResult;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const intersectionResult = detectScalarMetadataFromIntersection(
|
|
223
|
+
type,
|
|
224
|
+
checker,
|
|
225
|
+
);
|
|
226
|
+
if (intersectionResult) {
|
|
227
|
+
return intersectionResult;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const directMetadata = extractMetadataFromType(type, checker);
|
|
231
|
+
if (directMetadata) {
|
|
232
|
+
return directMetadata;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (type.aliasSymbol) {
|
|
236
|
+
const aliasedType = checker.getDeclaredTypeOfSymbol(type.aliasSymbol);
|
|
237
|
+
if (aliasedType !== type) {
|
|
238
|
+
const aliasResult = detectScalarMetadataCore(aliasedType, checker);
|
|
239
|
+
if (aliasResult) {
|
|
240
|
+
return aliasResult;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const symbol = type.getSymbol();
|
|
246
|
+
if (symbol) {
|
|
247
|
+
const declarations = symbol.getDeclarations();
|
|
248
|
+
if (declarations && declarations.length > 0) {
|
|
249
|
+
for (const decl of declarations) {
|
|
250
|
+
if (ts.isTypeAliasDeclaration(decl)) {
|
|
251
|
+
const declSymbol = checker.getSymbolAtLocation(decl.name);
|
|
252
|
+
if (declSymbol) {
|
|
253
|
+
const declType = checker.getDeclaredTypeOfSymbol(declSymbol);
|
|
254
|
+
if (declType !== type && declType.isIntersection()) {
|
|
255
|
+
const result = detectScalarMetadataFromIntersection(
|
|
256
|
+
declType,
|
|
257
|
+
checker,
|
|
258
|
+
);
|
|
259
|
+
if (result) {
|
|
260
|
+
return result;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function isObjectLikeType(type: ts.Type): boolean {
|
|
273
|
+
if (type.flags & ts.TypeFlags.Object) {
|
|
274
|
+
const objectType = type as ts.ObjectType;
|
|
275
|
+
if (
|
|
276
|
+
objectType.objectFlags & ts.ObjectFlags.Anonymous ||
|
|
277
|
+
objectType.objectFlags & ts.ObjectFlags.Interface ||
|
|
278
|
+
objectType.objectFlags & ts.ObjectFlags.Reference
|
|
279
|
+
) {
|
|
280
|
+
const properties = type.getProperties();
|
|
281
|
+
const hasOnlyMetadataProperty =
|
|
282
|
+
properties.length === 1 &&
|
|
283
|
+
properties[0]?.getName() === SCALAR_METADATA_PROPERTY;
|
|
284
|
+
|
|
285
|
+
if (!hasOnlyMetadataProperty && properties.length > 0) {
|
|
286
|
+
const metadataProp = type.getProperty(SCALAR_METADATA_PROPERTY);
|
|
287
|
+
if (!metadataProp) {
|
|
288
|
+
return true;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Detects scalar metadata from a TypeScript type.
|
|
298
|
+
*
|
|
299
|
+
* This function analyzes TypeScript types to detect scalar metadata:
|
|
300
|
+
* - TypeScript primitives (string, boolean, number) map to GraphQL scalars
|
|
301
|
+
* - Intersection types with " $gqlkitScalar" property indicate custom scalars
|
|
302
|
+
* - Type aliases are followed to find the underlying scalar metadata
|
|
303
|
+
* - Unions with null indicate nullable types
|
|
304
|
+
* - Array types indicate list types
|
|
305
|
+
*
|
|
306
|
+
* @param type - The TypeScript type to analyze
|
|
307
|
+
* @param checker - The TypeScript type checker
|
|
308
|
+
* @returns Detection result with scalar information
|
|
309
|
+
*/
|
|
310
|
+
export function detectScalarMetadata(
|
|
311
|
+
type: ts.Type,
|
|
312
|
+
checker: ts.TypeChecker,
|
|
313
|
+
): ScalarMetadataResult {
|
|
314
|
+
const result = createDefaultResult();
|
|
315
|
+
|
|
316
|
+
if (checker.isArrayType(type)) {
|
|
317
|
+
const typeRef = type as ts.TypeReference;
|
|
318
|
+
const elementType = typeRef.typeArguments?.[0];
|
|
319
|
+
|
|
320
|
+
if (!elementType) {
|
|
321
|
+
return {
|
|
322
|
+
...result,
|
|
323
|
+
isList: true,
|
|
324
|
+
scalarName: "String",
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const elementResult = detectScalarMetadata(elementType, checker);
|
|
329
|
+
return {
|
|
330
|
+
...result,
|
|
331
|
+
scalarName: elementResult.scalarName,
|
|
332
|
+
only: elementResult.only,
|
|
333
|
+
isList: true,
|
|
334
|
+
listItemNullable: elementResult.nullable,
|
|
335
|
+
isPrimitive: elementResult.isPrimitive,
|
|
336
|
+
error: elementResult.error,
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (type.isUnion()) {
|
|
341
|
+
const nonNullTypes = type.types.filter((t) => !isNullOrUndefined(t));
|
|
342
|
+
const hasNull = type.types.some((t) => isNullOrUndefined(t));
|
|
343
|
+
|
|
344
|
+
if (isBooleanLiteralUnion(type.types)) {
|
|
345
|
+
return {
|
|
346
|
+
...result,
|
|
347
|
+
scalarName: "Boolean",
|
|
348
|
+
isPrimitive: true,
|
|
349
|
+
nullable: hasNull,
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (nonNullTypes.length === 0) {
|
|
354
|
+
return result;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if (nonNullTypes.length === 1) {
|
|
358
|
+
const innerType = nonNullTypes[0]!;
|
|
359
|
+
|
|
360
|
+
if (checker.isArrayType(innerType)) {
|
|
361
|
+
const innerResult = detectScalarMetadata(innerType, checker);
|
|
362
|
+
return {
|
|
363
|
+
...innerResult,
|
|
364
|
+
nullable: hasNull,
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
const innerResult = detectScalarMetadata(innerType, checker);
|
|
369
|
+
return {
|
|
370
|
+
...innerResult,
|
|
371
|
+
nullable: hasNull || innerResult.nullable,
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
const scalarNames = new Set<string>();
|
|
376
|
+
const detectedResults: InternalMetadata[] = [];
|
|
377
|
+
|
|
378
|
+
for (const unionMember of nonNullTypes) {
|
|
379
|
+
const memberResult = detectScalarMetadataCore(unionMember, checker);
|
|
380
|
+
if (memberResult?.scalarName) {
|
|
381
|
+
scalarNames.add(memberResult.scalarName);
|
|
382
|
+
detectedResults.push(memberResult);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (scalarNames.size > 1) {
|
|
387
|
+
const scalarNameArray = Array.from(scalarNames).sort();
|
|
388
|
+
return {
|
|
389
|
+
...result,
|
|
390
|
+
nullable: hasNull,
|
|
391
|
+
error: {
|
|
392
|
+
code: "MIXED_SCALAR_UNION",
|
|
393
|
+
message: `Cannot use union of different scalar types: ${scalarNameArray.join(", ")}`,
|
|
394
|
+
scalarNames: scalarNameArray,
|
|
395
|
+
},
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (scalarNames.size === 1 && detectedResults.length > 0) {
|
|
400
|
+
const firstResult = detectedResults[0]!;
|
|
401
|
+
return {
|
|
402
|
+
...result,
|
|
403
|
+
scalarName: firstResult.scalarName,
|
|
404
|
+
only: firstResult.only,
|
|
405
|
+
nullable: hasNull,
|
|
406
|
+
isPrimitive: firstResult.isPrimitive,
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
if (nonNullTypes.every((t) => isObjectLikeType(t))) {
|
|
411
|
+
return {
|
|
412
|
+
...result,
|
|
413
|
+
isObjectType: true,
|
|
414
|
+
nullable: hasNull,
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return {
|
|
419
|
+
...result,
|
|
420
|
+
nullable: hasNull,
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const coreResult = detectScalarMetadataCore(type, checker);
|
|
425
|
+
if (coreResult) {
|
|
426
|
+
return {
|
|
427
|
+
...result,
|
|
428
|
+
scalarName: coreResult.scalarName,
|
|
429
|
+
only: coreResult.only,
|
|
430
|
+
isPrimitive: coreResult.isPrimitive,
|
|
431
|
+
isObjectType: coreResult.isObjectType,
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (isObjectLikeType(type)) {
|
|
436
|
+
return {
|
|
437
|
+
...result,
|
|
438
|
+
isObjectType: true,
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
return result;
|
|
443
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import type { Diagnostic } from "../type-extractor/types/index.js";
|
|
3
|
+
import { loadTsconfig } from "./tsconfig-loader.js";
|
|
4
|
+
|
|
5
|
+
const DEFAULT_COMPILER_OPTIONS: ts.CompilerOptions = {
|
|
6
|
+
target: ts.ScriptTarget.ES2022,
|
|
7
|
+
module: ts.ModuleKind.NodeNext,
|
|
8
|
+
moduleResolution: ts.ModuleResolutionKind.Node16,
|
|
9
|
+
strict: true,
|
|
10
|
+
esModuleInterop: true,
|
|
11
|
+
skipLibCheck: true,
|
|
12
|
+
noEmit: true,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export interface CreateSharedProgramOptions {
|
|
16
|
+
readonly cwd: string;
|
|
17
|
+
readonly tsconfigPath: string | null;
|
|
18
|
+
readonly typeFiles: ReadonlyArray<string>;
|
|
19
|
+
readonly resolverFiles: ReadonlyArray<string>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface CreateSharedProgramResult {
|
|
23
|
+
readonly program: ts.Program | null;
|
|
24
|
+
readonly diagnostics: ReadonlyArray<Diagnostic>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function createSharedProgram(
|
|
28
|
+
options: CreateSharedProgramOptions,
|
|
29
|
+
): CreateSharedProgramResult {
|
|
30
|
+
const { cwd, tsconfigPath, typeFiles, resolverFiles } = options;
|
|
31
|
+
|
|
32
|
+
const tsconfigResult = loadTsconfig({ cwd, tsconfigPath });
|
|
33
|
+
|
|
34
|
+
if (tsconfigResult.diagnostics.length > 0) {
|
|
35
|
+
return {
|
|
36
|
+
program: null,
|
|
37
|
+
diagnostics: tsconfigResult.diagnostics,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const compilerOptions: ts.CompilerOptions =
|
|
42
|
+
tsconfigResult.compilerOptions ?? DEFAULT_COMPILER_OPTIONS;
|
|
43
|
+
|
|
44
|
+
const allFiles = [...typeFiles, ...resolverFiles];
|
|
45
|
+
const program = ts.createProgram(allFiles, compilerOptions);
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
program,
|
|
49
|
+
diagnostics: [],
|
|
50
|
+
};
|
|
51
|
+
}
|