@gqlkit-ts/cli 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/auto-type-generator/auto-type-generator.d.ts +46 -0
- package/dist/auto-type-generator/auto-type-generator.d.ts.map +1 -0
- package/dist/auto-type-generator/auto-type-generator.js +353 -0
- package/dist/auto-type-generator/auto-type-generator.js.map +1 -0
- package/dist/auto-type-generator/auto-type-generator.test.d.ts +2 -0
- package/dist/auto-type-generator/auto-type-generator.test.d.ts.map +1 -0
- package/dist/auto-type-generator/auto-type-generator.test.js +613 -0
- package/dist/auto-type-generator/auto-type-generator.test.js.map +1 -0
- package/dist/auto-type-generator/index.d.ts +4 -0
- package/dist/auto-type-generator/index.d.ts.map +1 -0
- package/dist/auto-type-generator/index.js +3 -0
- package/dist/auto-type-generator/index.js.map +1 -0
- package/dist/auto-type-generator/name-collision-validator.d.ts +17 -0
- package/dist/auto-type-generator/name-collision-validator.d.ts.map +1 -0
- package/dist/auto-type-generator/name-collision-validator.js +68 -0
- package/dist/auto-type-generator/name-collision-validator.js.map +1 -0
- package/dist/auto-type-generator/name-collision-validator.test.d.ts +2 -0
- package/dist/auto-type-generator/name-collision-validator.test.d.ts.map +1 -0
- package/dist/auto-type-generator/name-collision-validator.test.js +358 -0
- package/dist/auto-type-generator/name-collision-validator.test.js.map +1 -0
- package/dist/auto-type-generator/naming-convention.d.ts +40 -0
- package/dist/auto-type-generator/naming-convention.d.ts.map +1 -0
- package/dist/auto-type-generator/naming-convention.js +59 -0
- package/dist/auto-type-generator/naming-convention.js.map +1 -0
- package/dist/auto-type-generator/naming-convention.test.d.ts +2 -0
- package/dist/auto-type-generator/naming-convention.test.d.ts.map +1 -0
- package/dist/auto-type-generator/naming-convention.test.js +132 -0
- package/dist/auto-type-generator/naming-convention.test.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +11 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/gen.d.ts +32 -0
- package/dist/commands/gen.d.ts.map +1 -0
- package/dist/commands/gen.js +101 -0
- package/dist/commands/gen.js.map +1 -0
- package/dist/commands/gen.test.d.ts +2 -0
- package/dist/commands/gen.test.d.ts.map +1 -0
- package/dist/commands/gen.test.js +226 -0
- package/dist/commands/gen.test.js.map +1 -0
- package/dist/commands/main.d.ts +12 -0
- package/dist/commands/main.d.ts.map +1 -0
- package/dist/commands/main.js +5 -0
- package/dist/commands/main.js.map +1 -0
- package/dist/config/define-config.d.ts +26 -0
- package/dist/config/define-config.d.ts.map +1 -0
- package/dist/config/define-config.js +27 -0
- package/dist/config/define-config.js.map +1 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +2 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/types.d.ts +131 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +2 -0
- package/dist/config/types.js.map +1 -0
- package/dist/config-loader/index.d.ts +3 -0
- package/dist/config-loader/index.d.ts.map +1 -0
- package/dist/config-loader/index.js +2 -0
- package/dist/config-loader/index.js.map +1 -0
- package/dist/config-loader/loader.d.ts +50 -0
- package/dist/config-loader/loader.d.ts.map +1 -0
- package/dist/config-loader/loader.js +78 -0
- package/dist/config-loader/loader.js.map +1 -0
- package/dist/config-loader/loader.test.d.ts +2 -0
- package/dist/config-loader/loader.test.d.ts.map +1 -0
- package/dist/config-loader/loader.test.js +123 -0
- package/dist/config-loader/loader.test.js.map +1 -0
- package/dist/config-loader/validator.d.ts +13 -0
- package/dist/config-loader/validator.d.ts.map +1 -0
- package/dist/config-loader/validator.js +497 -0
- package/dist/config-loader/validator.js.map +1 -0
- package/dist/config-loader/validator.test.d.ts +2 -0
- package/dist/config-loader/validator.test.d.ts.map +1 -0
- package/dist/config-loader/validator.test.js +846 -0
- package/dist/config-loader/validator.test.js.map +1 -0
- package/dist/gen-orchestrator/golden.test.d.ts +2 -0
- package/dist/gen-orchestrator/golden.test.d.ts.map +1 -0
- package/dist/gen-orchestrator/golden.test.js +102 -0
- package/dist/gen-orchestrator/golden.test.js.map +1 -0
- package/dist/gen-orchestrator/hook-executor/hook-executor.d.ts +25 -0
- package/dist/gen-orchestrator/hook-executor/hook-executor.d.ts.map +1 -0
- package/dist/gen-orchestrator/hook-executor/hook-executor.js +68 -0
- package/dist/gen-orchestrator/hook-executor/hook-executor.js.map +1 -0
- package/dist/gen-orchestrator/hook-executor/hook-executor.test.d.ts +2 -0
- package/dist/gen-orchestrator/hook-executor/hook-executor.test.d.ts.map +1 -0
- package/dist/gen-orchestrator/hook-executor/hook-executor.test.js +167 -0
- package/dist/gen-orchestrator/hook-executor/hook-executor.test.js.map +1 -0
- package/dist/gen-orchestrator/orchestrator.d.ts +30 -0
- package/dist/gen-orchestrator/orchestrator.d.ts.map +1 -0
- package/dist/gen-orchestrator/orchestrator.js +407 -0
- package/dist/gen-orchestrator/orchestrator.js.map +1 -0
- package/dist/gen-orchestrator/reporter/diagnostic-reporter.d.ts +9 -0
- package/dist/gen-orchestrator/reporter/diagnostic-reporter.d.ts.map +1 -0
- package/dist/gen-orchestrator/reporter/diagnostic-reporter.js +32 -0
- package/dist/gen-orchestrator/reporter/diagnostic-reporter.js.map +1 -0
- package/dist/gen-orchestrator/reporter/progress-reporter.d.ts +19 -0
- package/dist/gen-orchestrator/reporter/progress-reporter.d.ts.map +1 -0
- package/dist/gen-orchestrator/reporter/progress-reporter.js +38 -0
- package/dist/gen-orchestrator/reporter/progress-reporter.js.map +1 -0
- package/dist/gen-orchestrator/reporter/progress-reporter.test.d.ts +2 -0
- package/dist/gen-orchestrator/reporter/progress-reporter.test.d.ts.map +1 -0
- package/dist/gen-orchestrator/reporter/progress-reporter.test.js +74 -0
- package/dist/gen-orchestrator/reporter/progress-reporter.test.js.map +1 -0
- package/dist/gen-orchestrator/writer/file-writer.d.ts +13 -0
- package/dist/gen-orchestrator/writer/file-writer.d.ts.map +1 -0
- package/dist/gen-orchestrator/writer/file-writer.js +22 -0
- package/dist/gen-orchestrator/writer/file-writer.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/resolver-extractor/extract-resolvers.d.ts +40 -0
- package/dist/resolver-extractor/extract-resolvers.d.ts.map +1 -0
- package/dist/resolver-extractor/extract-resolvers.js +2 -0
- package/dist/resolver-extractor/extract-resolvers.js.map +1 -0
- package/dist/resolver-extractor/extractor/define-api-extractor.d.ts +50 -0
- package/dist/resolver-extractor/extractor/define-api-extractor.d.ts.map +1 -0
- package/dist/resolver-extractor/extractor/define-api-extractor.js +685 -0
- package/dist/resolver-extractor/extractor/define-api-extractor.js.map +1 -0
- package/dist/resolver-extractor/index.d.ts +5 -0
- package/dist/resolver-extractor/index.d.ts.map +1 -0
- package/dist/resolver-extractor/index.js +2 -0
- package/dist/resolver-extractor/index.js.map +1 -0
- package/dist/resolver-extractor/validator/abstract-resolver-validator.d.ts +25 -0
- package/dist/resolver-extractor/validator/abstract-resolver-validator.d.ts.map +1 -0
- package/dist/resolver-extractor/validator/abstract-resolver-validator.js +172 -0
- package/dist/resolver-extractor/validator/abstract-resolver-validator.js.map +1 -0
- package/dist/resolver-extractor/validator/only-validator.d.ts +61 -0
- package/dist/resolver-extractor/validator/only-validator.d.ts.map +1 -0
- package/dist/resolver-extractor/validator/only-validator.js +76 -0
- package/dist/resolver-extractor/validator/only-validator.js.map +1 -0
- package/dist/resolver-extractor/validator/only-validator.test.d.ts +8 -0
- package/dist/resolver-extractor/validator/only-validator.test.d.ts.map +1 -0
- package/dist/resolver-extractor/validator/only-validator.test.js +352 -0
- package/dist/resolver-extractor/validator/only-validator.test.js.map +1 -0
- package/dist/schema-generator/builder/ast-builder.d.ts +7 -0
- package/dist/schema-generator/builder/ast-builder.d.ts.map +1 -0
- package/dist/schema-generator/builder/ast-builder.js +417 -0
- package/dist/schema-generator/builder/ast-builder.js.map +1 -0
- package/dist/schema-generator/builder/ast-builder.test.d.ts +2 -0
- package/dist/schema-generator/builder/ast-builder.test.d.ts.map +1 -0
- package/dist/schema-generator/builder/ast-builder.test.js +469 -0
- package/dist/schema-generator/builder/ast-builder.test.js.map +1 -0
- package/dist/schema-generator/emitter/code-emitter.d.ts +7 -0
- package/dist/schema-generator/emitter/code-emitter.d.ts.map +1 -0
- package/dist/schema-generator/emitter/code-emitter.js +201 -0
- package/dist/schema-generator/emitter/code-emitter.js.map +1 -0
- package/dist/schema-generator/emitter/sdl-emitter.d.ts +7 -0
- package/dist/schema-generator/emitter/sdl-emitter.d.ts.map +1 -0
- package/dist/schema-generator/emitter/sdl-emitter.js +11 -0
- package/dist/schema-generator/emitter/sdl-emitter.js.map +1 -0
- package/dist/schema-generator/generate-schema.d.ts +26 -0
- package/dist/schema-generator/generate-schema.d.ts.map +1 -0
- package/dist/schema-generator/generate-schema.js +76 -0
- package/dist/schema-generator/generate-schema.js.map +1 -0
- package/dist/schema-generator/index.d.ts +4 -0
- package/dist/schema-generator/index.d.ts.map +1 -0
- package/dist/schema-generator/index.js +2 -0
- package/dist/schema-generator/index.js.map +1 -0
- package/dist/schema-generator/integrator/result-integrator.d.ts +93 -0
- package/dist/schema-generator/integrator/result-integrator.d.ts.map +1 -0
- package/dist/schema-generator/integrator/result-integrator.js +396 -0
- package/dist/schema-generator/integrator/result-integrator.js.map +1 -0
- package/dist/schema-generator/pruner/schema-pruner.d.ts +16 -0
- package/dist/schema-generator/pruner/schema-pruner.d.ts.map +1 -0
- package/dist/schema-generator/pruner/schema-pruner.js +66 -0
- package/dist/schema-generator/pruner/schema-pruner.js.map +1 -0
- package/dist/schema-generator/resolver-collector/resolver-collector.d.ts +24 -0
- package/dist/schema-generator/resolver-collector/resolver-collector.d.ts.map +1 -0
- package/dist/schema-generator/resolver-collector/resolver-collector.js +61 -0
- package/dist/schema-generator/resolver-collector/resolver-collector.js.map +1 -0
- package/dist/shared/constants.d.ts +70 -0
- package/dist/shared/constants.d.ts.map +1 -0
- package/dist/shared/constants.js +128 -0
- package/dist/shared/constants.js.map +1 -0
- package/dist/shared/default-value-detector.d.ts +40 -0
- package/dist/shared/default-value-detector.d.ts.map +1 -0
- package/dist/shared/default-value-detector.js +124 -0
- package/dist/shared/default-value-detector.js.map +1 -0
- package/dist/shared/diagnostics.d.ts +4 -0
- package/dist/shared/diagnostics.d.ts.map +1 -0
- package/dist/shared/diagnostics.js +25 -0
- package/dist/shared/diagnostics.js.map +1 -0
- package/dist/shared/directive-definition-extractor.d.ts +64 -0
- package/dist/shared/directive-definition-extractor.d.ts.map +1 -0
- package/dist/shared/directive-definition-extractor.js +399 -0
- package/dist/shared/directive-definition-extractor.js.map +1 -0
- package/dist/shared/directive-detector.d.ts +102 -0
- package/dist/shared/directive-detector.d.ts.map +1 -0
- package/dist/shared/directive-detector.js +422 -0
- package/dist/shared/directive-detector.js.map +1 -0
- package/dist/shared/file-scanner.d.ts +25 -0
- package/dist/shared/file-scanner.d.ts.map +1 -0
- package/dist/shared/file-scanner.js +99 -0
- package/dist/shared/file-scanner.js.map +1 -0
- package/dist/shared/file-scanner.test.d.ts +2 -0
- package/dist/shared/file-scanner.test.d.ts.map +1 -0
- package/dist/shared/file-scanner.test.js +138 -0
- package/dist/shared/file-scanner.test.js.map +1 -0
- package/dist/shared/index.d.ts +10 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/index.js +8 -0
- package/dist/shared/index.js.map +1 -0
- package/dist/shared/inline-object-extractor.d.ts +13 -0
- package/dist/shared/inline-object-extractor.d.ts.map +1 -0
- package/dist/shared/inline-object-extractor.js +65 -0
- package/dist/shared/inline-object-extractor.js.map +1 -0
- package/dist/shared/inline-object-utils.d.ts +7 -0
- package/dist/shared/inline-object-utils.d.ts.map +1 -0
- package/dist/shared/inline-object-utils.js +23 -0
- package/dist/shared/inline-object-utils.js.map +1 -0
- package/dist/shared/interface-detector.d.ts +22 -0
- package/dist/shared/interface-detector.d.ts.map +1 -0
- package/dist/shared/interface-detector.js +90 -0
- package/dist/shared/interface-detector.js.map +1 -0
- package/dist/shared/interface-validator.d.ts +9 -0
- package/dist/shared/interface-validator.d.ts.map +1 -0
- package/dist/shared/interface-validator.js +152 -0
- package/dist/shared/interface-validator.js.map +1 -0
- package/dist/shared/interface-validator.test.d.ts +2 -0
- package/dist/shared/interface-validator.test.d.ts.map +1 -0
- package/dist/shared/interface-validator.test.js +145 -0
- package/dist/shared/interface-validator.test.js.map +1 -0
- package/dist/shared/metadata-detector.d.ts +65 -0
- package/dist/shared/metadata-detector.d.ts.map +1 -0
- package/dist/shared/metadata-detector.js +333 -0
- package/dist/shared/metadata-detector.js.map +1 -0
- package/dist/shared/program-factory.d.ts +14 -0
- package/dist/shared/program-factory.d.ts.map +1 -0
- package/dist/shared/program-factory.js +29 -0
- package/dist/shared/program-factory.js.map +1 -0
- package/dist/shared/source-location.d.ts +11 -0
- package/dist/shared/source-location.d.ts.map +1 -0
- package/dist/shared/source-location.js +15 -0
- package/dist/shared/source-location.js.map +1 -0
- package/dist/shared/tsconfig-loader.d.ts +13 -0
- package/dist/shared/tsconfig-loader.d.ts.map +1 -0
- package/dist/shared/tsconfig-loader.js +90 -0
- package/dist/shared/tsconfig-loader.js.map +1 -0
- package/dist/shared/tsdoc-parser.d.ts +12 -0
- package/dist/shared/tsdoc-parser.d.ts.map +1 -0
- package/dist/shared/tsdoc-parser.js +101 -0
- package/dist/shared/tsdoc-parser.js.map +1 -0
- package/dist/shared/type-converter.d.ts +3 -0
- package/dist/shared/type-converter.d.ts.map +1 -0
- package/dist/shared/type-converter.js +72 -0
- package/dist/shared/type-converter.js.map +1 -0
- package/dist/shared/typescript-utils.d.ts +55 -0
- package/dist/shared/typescript-utils.d.ts.map +1 -0
- package/dist/shared/typescript-utils.js +149 -0
- package/dist/shared/typescript-utils.js.map +1 -0
- package/dist/type-extractor/collector/result-collector.d.ts +7 -0
- package/dist/type-extractor/collector/result-collector.d.ts.map +1 -0
- package/dist/type-extractor/collector/result-collector.js +35 -0
- package/dist/type-extractor/collector/result-collector.js.map +1 -0
- package/dist/type-extractor/collector/scalar-collector.d.ts +108 -0
- package/dist/type-extractor/collector/scalar-collector.d.ts.map +1 -0
- package/dist/type-extractor/collector/scalar-collector.js +133 -0
- package/dist/type-extractor/collector/scalar-collector.js.map +1 -0
- package/dist/type-extractor/converter/field-eligibility.d.ts +34 -0
- package/dist/type-extractor/converter/field-eligibility.d.ts.map +1 -0
- package/dist/type-extractor/converter/field-eligibility.js +89 -0
- package/dist/type-extractor/converter/field-eligibility.js.map +1 -0
- package/dist/type-extractor/converter/graphql-converter.d.ts +7 -0
- package/dist/type-extractor/converter/graphql-converter.d.ts.map +1 -0
- package/dist/type-extractor/converter/graphql-converter.js +299 -0
- package/dist/type-extractor/converter/graphql-converter.js.map +1 -0
- package/dist/type-extractor/extract-types.d.ts +2 -0
- package/dist/type-extractor/extract-types.d.ts.map +1 -0
- package/dist/type-extractor/extract-types.js +2 -0
- package/dist/type-extractor/extract-types.js.map +1 -0
- package/dist/type-extractor/extractor/type-extractor.d.ts +27 -0
- package/dist/type-extractor/extractor/type-extractor.d.ts.map +1 -0
- package/dist/type-extractor/extractor/type-extractor.js +1116 -0
- package/dist/type-extractor/extractor/type-extractor.js.map +1 -0
- package/dist/type-extractor/index.d.ts +4 -0
- package/dist/type-extractor/index.d.ts.map +1 -0
- package/dist/type-extractor/index.js +2 -0
- package/dist/type-extractor/index.js.map +1 -0
- package/dist/type-extractor/types/diagnostics.d.ts +17 -0
- package/dist/type-extractor/types/diagnostics.d.ts.map +1 -0
- package/dist/type-extractor/types/diagnostics.js +2 -0
- package/dist/type-extractor/types/diagnostics.js.map +1 -0
- package/dist/type-extractor/types/graphql.d.ts +40 -0
- package/dist/type-extractor/types/graphql.d.ts.map +1 -0
- package/dist/type-extractor/types/graphql.js +2 -0
- package/dist/type-extractor/types/graphql.js.map +1 -0
- package/dist/type-extractor/types/index.d.ts +5 -0
- package/dist/type-extractor/types/index.d.ts.map +1 -0
- package/dist/type-extractor/types/index.js +2 -0
- package/dist/type-extractor/types/index.js.map +1 -0
- package/dist/type-extractor/types/typescript.d.ts +86 -0
- package/dist/type-extractor/types/typescript.d.ts.map +1 -0
- package/dist/type-extractor/types/typescript.js +2 -0
- package/dist/type-extractor/types/typescript.js.map +1 -0
- package/dist/type-extractor/types/typescript.test.d.ts +2 -0
- package/dist/type-extractor/types/typescript.test.d.ts.map +1 -0
- package/dist/type-extractor/types/typescript.test.js +287 -0
- package/dist/type-extractor/types/typescript.test.js.map +1 -0
- package/dist/type-extractor/validator/type-validator.d.ts +11 -0
- package/dist/type-extractor/validator/type-validator.d.ts.map +1 -0
- package/dist/type-extractor/validator/type-validator.js +53 -0
- package/dist/type-extractor/validator/type-validator.js.map +1 -0
- package/docs/configuration.md +163 -0
- package/docs/getting-started.md +117 -0
- package/docs/index.md +32 -0
- package/docs/integration/apollo.md +109 -0
- package/docs/integration/yoga.md +108 -0
- package/docs/schema/abstract-resolvers.md +146 -0
- package/docs/schema/directives.md +196 -0
- package/docs/schema/documentation.md +176 -0
- package/docs/schema/enums.md +162 -0
- package/docs/schema/fields.md +184 -0
- package/docs/schema/index.md +38 -0
- package/docs/schema/inputs.md +277 -0
- package/docs/schema/interfaces.md +178 -0
- package/docs/schema/objects.md +186 -0
- package/docs/schema/queries-mutations.md +205 -0
- package/docs/schema/scalars.md +194 -0
- package/docs/schema/unions.md +90 -0
- package/docs/what-is-gqlkit.md +22 -0
- package/package.json +59 -7
- package/README.md +0 -45
|
@@ -0,0 +1,1116 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import ts from "typescript";
|
|
3
|
+
import { isInternalTypeSymbol } from "../../shared/constants.js";
|
|
4
|
+
import { detectDefaultValueMetadata } from "../../shared/default-value-detector.js";
|
|
5
|
+
import { detectDirectiveMetadata, hasDirectiveMetadata, unwrapDirectiveType, } from "../../shared/directive-detector.js";
|
|
6
|
+
import { extractInlineObjectProperties as extractInlineObjectPropertiesShared } from "../../shared/inline-object-extractor.js";
|
|
7
|
+
import { isInlineObjectType } from "../../shared/inline-object-utils.js";
|
|
8
|
+
import { extractImplementsFromDefineInterface, extractImplementsFromGqlTypeDef, isDefineInterfaceTypeAlias, } from "../../shared/interface-detector.js";
|
|
9
|
+
import { detectScalarMetadata } from "../../shared/metadata-detector.js";
|
|
10
|
+
import { getSourceLocationFromNode, } from "../../shared/source-location.js";
|
|
11
|
+
import { extractTsDocFromSymbol, extractTsDocInfo, } from "../../shared/tsdoc-parser.js";
|
|
12
|
+
import { extractPropertySymbols, getNonNullableTypes, hasUndefinedInType, isAnonymousObjectType, isExported, isNullableUnion, isNullOrUndefined, shouldTreatIntersectionAsInline, } from "../../shared/typescript-utils.js";
|
|
13
|
+
/**
|
|
14
|
+
* Finds the parent enum symbol if all types belong to the same enum.
|
|
15
|
+
* Returns null if types are empty, don't have a common parent enum, or belong to different enums.
|
|
16
|
+
*/
|
|
17
|
+
function findEnumParentSymbol(types) {
|
|
18
|
+
if (types.length === 0)
|
|
19
|
+
return null;
|
|
20
|
+
const firstSymbol = types[0].symbol;
|
|
21
|
+
const parentSymbol = firstSymbol?.parent;
|
|
22
|
+
if (!parentSymbol || !(parentSymbol.flags & ts.SymbolFlags.Enum)) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const allBelongToSameEnum = types.every((t) => {
|
|
26
|
+
const sym = t.symbol;
|
|
27
|
+
return sym?.parent === parentSymbol;
|
|
28
|
+
});
|
|
29
|
+
return allBelongToSameEnum ? parentSymbol : null;
|
|
30
|
+
}
|
|
31
|
+
function isDefaultExport(node, sourceFile) {
|
|
32
|
+
let hasDefaultExport = false;
|
|
33
|
+
const nodeName = node.name?.getText(sourceFile);
|
|
34
|
+
ts.forEachChild(sourceFile, (child) => {
|
|
35
|
+
if (ts.isExportAssignment(child) &&
|
|
36
|
+
!child.isExportEquals &&
|
|
37
|
+
ts.isIdentifier(child.expression)) {
|
|
38
|
+
if (child.expression.text === nodeName) {
|
|
39
|
+
hasDefaultExport = true;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
return hasDefaultExport;
|
|
44
|
+
}
|
|
45
|
+
function isBooleanUnion(type) {
|
|
46
|
+
if (!type.isUnion())
|
|
47
|
+
return false;
|
|
48
|
+
const nonNullTypes = getNonNullableTypes(type);
|
|
49
|
+
return (nonNullTypes.length === 2 &&
|
|
50
|
+
nonNullTypes.every((t) => t.flags & ts.TypeFlags.BooleanLiteral));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Attempts to extract a type as an inline object, with cycle detection.
|
|
54
|
+
* Returns a reference type if a cycle is detected, otherwise returns an inline object.
|
|
55
|
+
*/
|
|
56
|
+
function tryExtractAsInlineObject(type, checker, globalTypeMappings, visitedTypes) {
|
|
57
|
+
if (visitedTypes.has(type)) {
|
|
58
|
+
const typeName = type.symbol?.getName() ?? "Object";
|
|
59
|
+
return {
|
|
60
|
+
tsType: {
|
|
61
|
+
kind: "reference",
|
|
62
|
+
name: typeName === "__type" ? "Object" : typeName,
|
|
63
|
+
elementType: null,
|
|
64
|
+
members: null,
|
|
65
|
+
nullable: false,
|
|
66
|
+
scalarInfo: null,
|
|
67
|
+
inlineObjectProperties: null,
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
visitedTypes.add(type);
|
|
72
|
+
const inlineProperties = extractInlineObjectPropertiesShared(type, checker, (t, c) => convertTsTypeToReference(t, c, globalTypeMappings, visitedTypes).tsType);
|
|
73
|
+
return {
|
|
74
|
+
tsType: {
|
|
75
|
+
kind: "inlineObject",
|
|
76
|
+
name: null,
|
|
77
|
+
elementType: null,
|
|
78
|
+
members: null,
|
|
79
|
+
nullable: false,
|
|
80
|
+
scalarInfo: null,
|
|
81
|
+
inlineObjectProperties: inlineProperties,
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function findGlobalTypeMapping(typeName, globalTypeMappings) {
|
|
86
|
+
return globalTypeMappings.find((m) => m.typeName === typeName);
|
|
87
|
+
}
|
|
88
|
+
function convertTsTypeToReference(type, checker, globalTypeMappings = [], visitedTypes = new WeakSet()) {
|
|
89
|
+
const metadataResult = detectScalarMetadata(type, checker);
|
|
90
|
+
// Skip scalar detection if it's an array of scalars (e.g., Int[])
|
|
91
|
+
// Array types should be handled by the array handling logic below
|
|
92
|
+
if (metadataResult.scalarName &&
|
|
93
|
+
!metadataResult.isPrimitive &&
|
|
94
|
+
!metadataResult.isList) {
|
|
95
|
+
return {
|
|
96
|
+
tsType: {
|
|
97
|
+
kind: "scalar",
|
|
98
|
+
name: metadataResult.scalarName,
|
|
99
|
+
elementType: null,
|
|
100
|
+
members: null,
|
|
101
|
+
nullable: metadataResult.nullable,
|
|
102
|
+
scalarInfo: {
|
|
103
|
+
scalarName: metadataResult.scalarName,
|
|
104
|
+
typeName: metadataResult.scalarName,
|
|
105
|
+
baseType: undefined,
|
|
106
|
+
isCustom: true,
|
|
107
|
+
only: metadataResult.only,
|
|
108
|
+
},
|
|
109
|
+
inlineObjectProperties: null,
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
if (isBooleanUnion(type)) {
|
|
114
|
+
const nullable = isNullableUnion(type);
|
|
115
|
+
return {
|
|
116
|
+
tsType: {
|
|
117
|
+
kind: "primitive",
|
|
118
|
+
name: "boolean",
|
|
119
|
+
elementType: null,
|
|
120
|
+
members: null,
|
|
121
|
+
nullable,
|
|
122
|
+
scalarInfo: null,
|
|
123
|
+
inlineObjectProperties: null,
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
if (type.isUnion()) {
|
|
128
|
+
const nullable = isNullableUnion(type);
|
|
129
|
+
// Preserve type alias name for enum types (string literal unions)
|
|
130
|
+
const aliasSymbol = type.aliasSymbol;
|
|
131
|
+
if (aliasSymbol) {
|
|
132
|
+
const name = aliasSymbol.getName();
|
|
133
|
+
return {
|
|
134
|
+
tsType: {
|
|
135
|
+
kind: "reference",
|
|
136
|
+
name,
|
|
137
|
+
elementType: null,
|
|
138
|
+
members: null,
|
|
139
|
+
nullable,
|
|
140
|
+
scalarInfo: null,
|
|
141
|
+
inlineObjectProperties: null,
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
const nonNullTypes = getNonNullableTypes(type);
|
|
146
|
+
// Check if all non-null types belong to the same enum (for numeric enums)
|
|
147
|
+
const enumParentSymbol = findEnumParentSymbol(nonNullTypes);
|
|
148
|
+
if (enumParentSymbol) {
|
|
149
|
+
return {
|
|
150
|
+
tsType: {
|
|
151
|
+
kind: "reference",
|
|
152
|
+
name: enumParentSymbol.getName(),
|
|
153
|
+
elementType: null,
|
|
154
|
+
members: null,
|
|
155
|
+
nullable,
|
|
156
|
+
scalarInfo: null,
|
|
157
|
+
inlineObjectProperties: null,
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
if (nonNullTypes.length === 1) {
|
|
162
|
+
const innerResult = convertTsTypeToReference(nonNullTypes[0], checker, globalTypeMappings, visitedTypes);
|
|
163
|
+
return {
|
|
164
|
+
tsType: { ...innerResult.tsType, nullable },
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
const memberResults = nonNullTypes.map((t) => convertTsTypeToReference(t, checker, globalTypeMappings, visitedTypes));
|
|
168
|
+
return {
|
|
169
|
+
tsType: {
|
|
170
|
+
kind: "union",
|
|
171
|
+
name: null,
|
|
172
|
+
elementType: null,
|
|
173
|
+
members: memberResults.map((r) => r.tsType),
|
|
174
|
+
nullable,
|
|
175
|
+
scalarInfo: null,
|
|
176
|
+
inlineObjectProperties: null,
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
if (checker.isArrayType(type)) {
|
|
181
|
+
const typeArgs = type.typeArguments;
|
|
182
|
+
const elementType = typeArgs?.[0];
|
|
183
|
+
const elementResult = elementType
|
|
184
|
+
? convertTsTypeToReference(elementType, checker, globalTypeMappings, visitedTypes)
|
|
185
|
+
: {
|
|
186
|
+
tsType: {
|
|
187
|
+
kind: "primitive",
|
|
188
|
+
name: "unknown",
|
|
189
|
+
elementType: null,
|
|
190
|
+
members: null,
|
|
191
|
+
nullable: false,
|
|
192
|
+
scalarInfo: null,
|
|
193
|
+
inlineObjectProperties: null,
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
return {
|
|
197
|
+
tsType: {
|
|
198
|
+
kind: "array",
|
|
199
|
+
name: null,
|
|
200
|
+
elementType: elementResult.tsType,
|
|
201
|
+
members: null,
|
|
202
|
+
nullable: false,
|
|
203
|
+
scalarInfo: null,
|
|
204
|
+
inlineObjectProperties: null,
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
const typeString = checker.typeToString(type);
|
|
209
|
+
if (type.flags & ts.TypeFlags.String) {
|
|
210
|
+
return {
|
|
211
|
+
tsType: {
|
|
212
|
+
kind: "primitive",
|
|
213
|
+
name: "string",
|
|
214
|
+
elementType: null,
|
|
215
|
+
members: null,
|
|
216
|
+
nullable: false,
|
|
217
|
+
scalarInfo: null,
|
|
218
|
+
inlineObjectProperties: null,
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
if (type.flags & ts.TypeFlags.Number) {
|
|
223
|
+
return {
|
|
224
|
+
tsType: {
|
|
225
|
+
kind: "primitive",
|
|
226
|
+
name: "number",
|
|
227
|
+
elementType: null,
|
|
228
|
+
members: null,
|
|
229
|
+
nullable: false,
|
|
230
|
+
scalarInfo: null,
|
|
231
|
+
inlineObjectProperties: null,
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
if (type.flags & ts.TypeFlags.Boolean ||
|
|
236
|
+
type.flags & ts.TypeFlags.BooleanLiteral) {
|
|
237
|
+
return {
|
|
238
|
+
tsType: {
|
|
239
|
+
kind: "primitive",
|
|
240
|
+
name: "boolean",
|
|
241
|
+
elementType: null,
|
|
242
|
+
members: null,
|
|
243
|
+
nullable: false,
|
|
244
|
+
scalarInfo: null,
|
|
245
|
+
inlineObjectProperties: null,
|
|
246
|
+
},
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
if (type.flags & ts.TypeFlags.StringLiteral) {
|
|
250
|
+
return {
|
|
251
|
+
tsType: {
|
|
252
|
+
kind: "literal",
|
|
253
|
+
name: typeString.replace(/"/g, ""),
|
|
254
|
+
elementType: null,
|
|
255
|
+
members: null,
|
|
256
|
+
nullable: false,
|
|
257
|
+
scalarInfo: null,
|
|
258
|
+
inlineObjectProperties: null,
|
|
259
|
+
},
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
if (type.flags & ts.TypeFlags.NumberLiteral) {
|
|
263
|
+
return {
|
|
264
|
+
tsType: {
|
|
265
|
+
kind: "literal",
|
|
266
|
+
name: typeString,
|
|
267
|
+
elementType: null,
|
|
268
|
+
members: null,
|
|
269
|
+
nullable: false,
|
|
270
|
+
scalarInfo: null,
|
|
271
|
+
inlineObjectProperties: null,
|
|
272
|
+
},
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
// Handle intersection types that should be treated as inline objects
|
|
276
|
+
// This includes intersections with anonymous members OR intersections of
|
|
277
|
+
// named object types (interfaces) that are not exported as GraphQL types
|
|
278
|
+
if (type.isIntersection()) {
|
|
279
|
+
// If the intersection type has an alias symbol (e.g., Comment = GqlObject<...>),
|
|
280
|
+
// treat it as a named reference to avoid infinite recursion with self-referential types
|
|
281
|
+
if (type.aliasSymbol) {
|
|
282
|
+
const aliasName = type.aliasSymbol.getName();
|
|
283
|
+
return {
|
|
284
|
+
tsType: {
|
|
285
|
+
kind: "reference",
|
|
286
|
+
name: aliasName,
|
|
287
|
+
elementType: null,
|
|
288
|
+
members: null,
|
|
289
|
+
nullable: false,
|
|
290
|
+
scalarInfo: null,
|
|
291
|
+
inlineObjectProperties: null,
|
|
292
|
+
},
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
const shouldTreatAsInline = shouldTreatIntersectionAsInline(type);
|
|
296
|
+
if (shouldTreatAsInline) {
|
|
297
|
+
return tryExtractAsInlineObject(type, checker, globalTypeMappings, visitedTypes);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
if (isInlineObjectType(type)) {
|
|
301
|
+
return tryExtractAsInlineObject(type, checker, globalTypeMappings, visitedTypes);
|
|
302
|
+
}
|
|
303
|
+
// Check for utility types (Omit, Pick, Partial, Required, etc.)
|
|
304
|
+
// These create mapped types that should be treated as inline objects
|
|
305
|
+
if (type.flags & ts.TypeFlags.Object) {
|
|
306
|
+
const objectType = type;
|
|
307
|
+
if (objectType.objectFlags & ts.ObjectFlags.Mapped) {
|
|
308
|
+
return tryExtractAsInlineObject(type, checker, globalTypeMappings, visitedTypes);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
if (type.symbol) {
|
|
312
|
+
const symbolName = type.symbol.getName();
|
|
313
|
+
// Skip internal TypeScript symbols (see constants.ts for details)
|
|
314
|
+
if (!isInternalTypeSymbol(symbolName)) {
|
|
315
|
+
const globalMapping = findGlobalTypeMapping(symbolName, globalTypeMappings);
|
|
316
|
+
if (globalMapping) {
|
|
317
|
+
return {
|
|
318
|
+
tsType: {
|
|
319
|
+
kind: "scalar",
|
|
320
|
+
name: globalMapping.scalarName,
|
|
321
|
+
elementType: null,
|
|
322
|
+
members: null,
|
|
323
|
+
nullable: false,
|
|
324
|
+
scalarInfo: {
|
|
325
|
+
scalarName: globalMapping.scalarName,
|
|
326
|
+
typeName: globalMapping.typeName,
|
|
327
|
+
baseType: undefined,
|
|
328
|
+
isCustom: true,
|
|
329
|
+
only: globalMapping.only,
|
|
330
|
+
},
|
|
331
|
+
inlineObjectProperties: null,
|
|
332
|
+
},
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
return {
|
|
336
|
+
tsType: {
|
|
337
|
+
kind: "reference",
|
|
338
|
+
name: symbolName,
|
|
339
|
+
elementType: null,
|
|
340
|
+
members: null,
|
|
341
|
+
nullable: false,
|
|
342
|
+
scalarInfo: null,
|
|
343
|
+
inlineObjectProperties: null,
|
|
344
|
+
},
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return {
|
|
349
|
+
tsType: {
|
|
350
|
+
kind: "reference",
|
|
351
|
+
name: typeString,
|
|
352
|
+
elementType: null,
|
|
353
|
+
members: null,
|
|
354
|
+
nullable: false,
|
|
355
|
+
scalarInfo: null,
|
|
356
|
+
inlineObjectProperties: null,
|
|
357
|
+
},
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
function extractFieldsFromType(type, checker, globalTypeMappings = []) {
|
|
361
|
+
const fields = [];
|
|
362
|
+
const diagnostics = [];
|
|
363
|
+
const properties = extractPropertySymbols(type, checker);
|
|
364
|
+
for (const prop of properties) {
|
|
365
|
+
const propName = prop.getName();
|
|
366
|
+
if (propName.startsWith(" $")) {
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
const propType = checker.getTypeOfSymbol(prop);
|
|
370
|
+
const declarations = prop.getDeclarations();
|
|
371
|
+
const declaration = declarations?.[0];
|
|
372
|
+
const optional = hasUndefinedInType(propType);
|
|
373
|
+
const tsdocInfo = extractTsDocFromSymbol(prop, checker);
|
|
374
|
+
let actualPropType = propType;
|
|
375
|
+
let directives = null;
|
|
376
|
+
let directiveNullable = false;
|
|
377
|
+
let defaultValue = null;
|
|
378
|
+
if (hasDirectiveMetadata(propType)) {
|
|
379
|
+
const directiveResult = detectDirectiveMetadata(propType, checker);
|
|
380
|
+
if (directiveResult.directives.length > 0) {
|
|
381
|
+
directives = directiveResult.directives;
|
|
382
|
+
}
|
|
383
|
+
// Detect default value from $gqlkitFieldMeta
|
|
384
|
+
const defaultValueResult = detectDefaultValueMetadata(propType, checker);
|
|
385
|
+
if (defaultValueResult.defaultValue) {
|
|
386
|
+
defaultValue = defaultValueResult.defaultValue;
|
|
387
|
+
}
|
|
388
|
+
if (defaultValueResult.errors.length > 0) {
|
|
389
|
+
for (const error of defaultValueResult.errors) {
|
|
390
|
+
diagnostics.push({
|
|
391
|
+
code: error.code,
|
|
392
|
+
message: `Field '${propName}': ${error.message}`,
|
|
393
|
+
severity: "warning",
|
|
394
|
+
location: getSourceLocationFromNode(declaration),
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
// Check if the original type is nullable before unwrapping
|
|
399
|
+
// TypeScript normalizes WithDirectives<T | null, [...]> to (T & Directive) | null
|
|
400
|
+
if (isNullableUnion(propType)) {
|
|
401
|
+
directiveNullable = true;
|
|
402
|
+
}
|
|
403
|
+
actualPropType = unwrapDirectiveType(propType, checker);
|
|
404
|
+
// Check if the unwrapped type (from $gqlkitOriginalType) is nullable
|
|
405
|
+
// This handles cases where TypeScript normalizes intersection types
|
|
406
|
+
// and loses the null from the outer union
|
|
407
|
+
if (!directiveNullable && isNullableUnion(actualPropType)) {
|
|
408
|
+
directiveNullable = true;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
const typeResult = convertTsTypeToReference(actualPropType, checker, globalTypeMappings);
|
|
412
|
+
// Preserve nullability from original WithDirectives type
|
|
413
|
+
const tsType = directiveNullable && !typeResult.tsType.nullable
|
|
414
|
+
? { ...typeResult.tsType, nullable: true }
|
|
415
|
+
: typeResult.tsType;
|
|
416
|
+
fields.push({
|
|
417
|
+
name: propName,
|
|
418
|
+
tsType,
|
|
419
|
+
optional,
|
|
420
|
+
description: tsdocInfo.description ?? null,
|
|
421
|
+
deprecated: tsdocInfo.deprecated ?? null,
|
|
422
|
+
directives,
|
|
423
|
+
defaultValue,
|
|
424
|
+
sourceLocation: getSourceLocationFromNode(declaration),
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
return { fields, diagnostics };
|
|
428
|
+
}
|
|
429
|
+
function isHeterogeneousEnum(node) {
|
|
430
|
+
if (!ts.isEnumDeclaration(node))
|
|
431
|
+
return false;
|
|
432
|
+
const members = node.members;
|
|
433
|
+
if (members.length <= 1)
|
|
434
|
+
return false;
|
|
435
|
+
let hasString = false;
|
|
436
|
+
let hasNumeric = false;
|
|
437
|
+
for (const member of members) {
|
|
438
|
+
const initializer = member.initializer;
|
|
439
|
+
if (initializer === undefined) {
|
|
440
|
+
hasNumeric = true;
|
|
441
|
+
}
|
|
442
|
+
else if (ts.isStringLiteral(initializer)) {
|
|
443
|
+
hasString = true;
|
|
444
|
+
}
|
|
445
|
+
else if (ts.isNumericLiteral(initializer) ||
|
|
446
|
+
ts.isPrefixUnaryExpression(initializer)) {
|
|
447
|
+
hasNumeric = true;
|
|
448
|
+
}
|
|
449
|
+
if (hasString && hasNumeric)
|
|
450
|
+
return true;
|
|
451
|
+
}
|
|
452
|
+
return false;
|
|
453
|
+
}
|
|
454
|
+
function isConstEnum(node) {
|
|
455
|
+
if (!ts.isEnumDeclaration(node))
|
|
456
|
+
return false;
|
|
457
|
+
const modifiers = ts.getCombinedModifierFlags(node);
|
|
458
|
+
return (modifiers & ts.ModifierFlags.Const) !== 0;
|
|
459
|
+
}
|
|
460
|
+
function isStringLiteralUnion(type) {
|
|
461
|
+
if (!type.isUnion())
|
|
462
|
+
return false;
|
|
463
|
+
const nonNullTypes = getNonNullableTypes(type);
|
|
464
|
+
if (nonNullTypes.length === 0)
|
|
465
|
+
return false;
|
|
466
|
+
return nonNullTypes.every((t) => t.flags & ts.TypeFlags.StringLiteral);
|
|
467
|
+
}
|
|
468
|
+
function getEnumMemberName(memberName) {
|
|
469
|
+
if (ts.isIdentifier(memberName) || ts.isStringLiteral(memberName)) {
|
|
470
|
+
return memberName.text;
|
|
471
|
+
}
|
|
472
|
+
return memberName.getText();
|
|
473
|
+
}
|
|
474
|
+
function extractEnumMembers(node, checker) {
|
|
475
|
+
const members = [];
|
|
476
|
+
for (const member of node.members) {
|
|
477
|
+
const name = getEnumMemberName(member.name);
|
|
478
|
+
const initializer = member.initializer;
|
|
479
|
+
const symbol = checker.getSymbolAtLocation(member.name);
|
|
480
|
+
const tsdocInfo = symbol
|
|
481
|
+
? extractTsDocFromSymbol(symbol, checker)
|
|
482
|
+
: { description: undefined, deprecated: undefined };
|
|
483
|
+
if (initializer && ts.isStringLiteral(initializer)) {
|
|
484
|
+
members.push({
|
|
485
|
+
name,
|
|
486
|
+
value: initializer.text,
|
|
487
|
+
numericValue: null,
|
|
488
|
+
description: tsdocInfo.description ?? null,
|
|
489
|
+
deprecated: tsdocInfo.deprecated ?? null,
|
|
490
|
+
sourceLocation: getSourceLocationFromNode(member),
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
const constantValue = checker.getConstantValue(member);
|
|
495
|
+
if (typeof constantValue === "number") {
|
|
496
|
+
members.push({
|
|
497
|
+
name,
|
|
498
|
+
value: name,
|
|
499
|
+
numericValue: constantValue,
|
|
500
|
+
description: tsdocInfo.description ?? null,
|
|
501
|
+
deprecated: tsdocInfo.deprecated ?? null,
|
|
502
|
+
sourceLocation: getSourceLocationFromNode(member),
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
return members;
|
|
508
|
+
}
|
|
509
|
+
const GRAPHQL_NAME_REGEX = /^[_A-Za-z][_0-9A-Za-z]*$/;
|
|
510
|
+
function isValidGraphQLName(name) {
|
|
511
|
+
return GRAPHQL_NAME_REGEX.test(name);
|
|
512
|
+
}
|
|
513
|
+
function validateNumericEnumMembers(members, enumName, enumLocation) {
|
|
514
|
+
const diagnostics = [];
|
|
515
|
+
const numericMembers = members.filter((m) => m.numericValue !== null);
|
|
516
|
+
if (numericMembers.length === 0) {
|
|
517
|
+
return diagnostics;
|
|
518
|
+
}
|
|
519
|
+
const valueToMembers = new Map();
|
|
520
|
+
for (const member of numericMembers) {
|
|
521
|
+
const value = member.numericValue;
|
|
522
|
+
const existing = valueToMembers.get(value) ?? [];
|
|
523
|
+
existing.push(member.name);
|
|
524
|
+
valueToMembers.set(value, existing);
|
|
525
|
+
}
|
|
526
|
+
for (const [value, memberNames] of valueToMembers) {
|
|
527
|
+
if (memberNames.length > 1) {
|
|
528
|
+
diagnostics.push({
|
|
529
|
+
code: "DUPLICATE_ENUM_VALUE",
|
|
530
|
+
message: `Enum '${enumName}' has duplicate numeric value ${value} (used by ${memberNames.join(" and ")})`,
|
|
531
|
+
severity: "error",
|
|
532
|
+
location: enumLocation,
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
for (const member of members) {
|
|
537
|
+
if (!isValidGraphQLName(member.name)) {
|
|
538
|
+
diagnostics.push({
|
|
539
|
+
code: "INVALID_ENUM_MEMBER_NAME",
|
|
540
|
+
message: `Enum member '${enumName}.${member.name}' is not a valid GraphQL identifier`,
|
|
541
|
+
severity: "error",
|
|
542
|
+
location: member.sourceLocation ?? enumLocation,
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
return diagnostics;
|
|
547
|
+
}
|
|
548
|
+
function extractStringLiteralUnionMembers(type, checker) {
|
|
549
|
+
if (!type.isUnion())
|
|
550
|
+
return [];
|
|
551
|
+
const members = [];
|
|
552
|
+
for (const t of type.types) {
|
|
553
|
+
if (isNullOrUndefined(t)) {
|
|
554
|
+
continue;
|
|
555
|
+
}
|
|
556
|
+
if (t.flags & ts.TypeFlags.StringLiteral) {
|
|
557
|
+
const value = checker.typeToString(t).replace(/^"|"$/g, "");
|
|
558
|
+
members.push({
|
|
559
|
+
name: value,
|
|
560
|
+
value: value,
|
|
561
|
+
numericValue: null,
|
|
562
|
+
description: null,
|
|
563
|
+
deprecated: null,
|
|
564
|
+
sourceLocation: null,
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
return members;
|
|
569
|
+
}
|
|
570
|
+
function determineTypeKind(node, type, sourceFile) {
|
|
571
|
+
if (ts.isInterfaceDeclaration(node)) {
|
|
572
|
+
return "interface";
|
|
573
|
+
}
|
|
574
|
+
if (ts.isTypeAliasDeclaration(node)) {
|
|
575
|
+
if (isDefineInterfaceTypeAlias(node, sourceFile)) {
|
|
576
|
+
return "graphqlInterface";
|
|
577
|
+
}
|
|
578
|
+
const unionKind = determineTypeKindFromUnion(type);
|
|
579
|
+
if (unionKind) {
|
|
580
|
+
return unionKind;
|
|
581
|
+
}
|
|
582
|
+
return "object";
|
|
583
|
+
}
|
|
584
|
+
return "object";
|
|
585
|
+
}
|
|
586
|
+
function determineTypeKindFromUnion(type) {
|
|
587
|
+
if (!type.isUnion()) {
|
|
588
|
+
return null;
|
|
589
|
+
}
|
|
590
|
+
const nonNullTypes = getNonNullableTypes(type);
|
|
591
|
+
if (isStringLiteralUnion(type)) {
|
|
592
|
+
return "enum";
|
|
593
|
+
}
|
|
594
|
+
const allObjectTypes = nonNullTypes.every((t) => (t.flags & ts.TypeFlags.Object) !== 0 ||
|
|
595
|
+
(t.flags & ts.TypeFlags.Intersection) !== 0 ||
|
|
596
|
+
t.symbol !== undefined);
|
|
597
|
+
if (nonNullTypes.length > 1 && allObjectTypes) {
|
|
598
|
+
return "union";
|
|
599
|
+
}
|
|
600
|
+
return null;
|
|
601
|
+
}
|
|
602
|
+
function determineTypeKindFromType(type, originalSymbol) {
|
|
603
|
+
const declarations = originalSymbol.getDeclarations();
|
|
604
|
+
const declaration = declarations?.[0];
|
|
605
|
+
if (declaration && ts.isInterfaceDeclaration(declaration)) {
|
|
606
|
+
return "interface";
|
|
607
|
+
}
|
|
608
|
+
if (declaration && ts.isEnumDeclaration(declaration)) {
|
|
609
|
+
return "enum";
|
|
610
|
+
}
|
|
611
|
+
const unionKind = determineTypeKindFromUnion(type);
|
|
612
|
+
if (unionKind) {
|
|
613
|
+
return unionKind;
|
|
614
|
+
}
|
|
615
|
+
return "object";
|
|
616
|
+
}
|
|
617
|
+
function isDeclarationInScannedFiles(declaration, scannedSourceFiles) {
|
|
618
|
+
const declSourceFileName = resolve(declaration.getSourceFile().fileName);
|
|
619
|
+
return Array.from(scannedSourceFiles).some((sf) => resolve(sf) === declSourceFileName);
|
|
620
|
+
}
|
|
621
|
+
function createGenericTypeDiagnostic(declaration, exportedName, location) {
|
|
622
|
+
if ((ts.isTypeAliasDeclaration(declaration) ||
|
|
623
|
+
ts.isInterfaceDeclaration(declaration)) &&
|
|
624
|
+
declaration.typeParameters &&
|
|
625
|
+
declaration.typeParameters.length > 0) {
|
|
626
|
+
return {
|
|
627
|
+
code: "UNSUPPORTED_SYNTAX",
|
|
628
|
+
message: `Generic type '${exportedName}' is not supported. Consider using a concrete type instead.`,
|
|
629
|
+
severity: "warning",
|
|
630
|
+
location,
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
return null;
|
|
634
|
+
}
|
|
635
|
+
function processReexportedSymbol(params) {
|
|
636
|
+
const { exportedName, resolvedSymbol, type, location, filePath, checker, globalTypeMappings, scannedSourceFiles, } = params;
|
|
637
|
+
const diagnostics = [];
|
|
638
|
+
const scalarMetadataResult = detectScalarMetadata(type, checker);
|
|
639
|
+
if (scalarMetadataResult.scalarName && !scalarMetadataResult.isPrimitive) {
|
|
640
|
+
const tsdocInfo = extractTsDocFromSymbol(resolvedSymbol, checker);
|
|
641
|
+
return {
|
|
642
|
+
typeInfo: null,
|
|
643
|
+
diagnostics: [],
|
|
644
|
+
scalarName: scalarMetadataResult.scalarName,
|
|
645
|
+
scalarMetadata: {
|
|
646
|
+
scalarName: scalarMetadataResult.scalarName,
|
|
647
|
+
typeName: exportedName,
|
|
648
|
+
only: scalarMetadataResult.only,
|
|
649
|
+
sourceFile: filePath,
|
|
650
|
+
line: location.line,
|
|
651
|
+
description: tsdocInfo.description ?? null,
|
|
652
|
+
},
|
|
653
|
+
skip: false,
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
const declarations = resolvedSymbol.getDeclarations();
|
|
657
|
+
const declaration = declarations?.[0];
|
|
658
|
+
if (declaration) {
|
|
659
|
+
if (isDeclarationInScannedFiles(declaration, scannedSourceFiles) &&
|
|
660
|
+
(ts.isTypeAliasDeclaration(declaration) ||
|
|
661
|
+
ts.isInterfaceDeclaration(declaration) ||
|
|
662
|
+
ts.isEnumDeclaration(declaration))) {
|
|
663
|
+
return {
|
|
664
|
+
typeInfo: null,
|
|
665
|
+
diagnostics: [],
|
|
666
|
+
scalarName: null,
|
|
667
|
+
scalarMetadata: null,
|
|
668
|
+
skip: true,
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
const genericDiagnostic = createGenericTypeDiagnostic(declaration, exportedName, location);
|
|
672
|
+
if (genericDiagnostic) {
|
|
673
|
+
diagnostics.push(genericDiagnostic);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
const kind = determineTypeKindFromType(type, resolvedSymbol);
|
|
677
|
+
const tsdocInfo = extractTsDocFromSymbol(resolvedSymbol, checker);
|
|
678
|
+
const metadata = {
|
|
679
|
+
name: exportedName,
|
|
680
|
+
kind,
|
|
681
|
+
sourceFile: filePath,
|
|
682
|
+
sourceLocation: location,
|
|
683
|
+
exportKind: "named",
|
|
684
|
+
description: tsdocInfo.description ?? null,
|
|
685
|
+
deprecated: tsdocInfo.deprecated ?? null,
|
|
686
|
+
directives: null,
|
|
687
|
+
};
|
|
688
|
+
if (kind === "enum") {
|
|
689
|
+
const declarations = resolvedSymbol.getDeclarations();
|
|
690
|
+
const declaration = declarations?.[0];
|
|
691
|
+
let enumMembers;
|
|
692
|
+
if (declaration && ts.isEnumDeclaration(declaration)) {
|
|
693
|
+
enumMembers = extractEnumMembers(declaration, checker);
|
|
694
|
+
}
|
|
695
|
+
else {
|
|
696
|
+
enumMembers = extractStringLiteralUnionMembers(type, checker);
|
|
697
|
+
}
|
|
698
|
+
return {
|
|
699
|
+
typeInfo: {
|
|
700
|
+
metadata,
|
|
701
|
+
fields: [],
|
|
702
|
+
unionMembers: null,
|
|
703
|
+
inlineObjectMembers: null,
|
|
704
|
+
enumMembers,
|
|
705
|
+
implementedInterfaces: null,
|
|
706
|
+
},
|
|
707
|
+
diagnostics,
|
|
708
|
+
scalarName: null,
|
|
709
|
+
scalarMetadata: null,
|
|
710
|
+
skip: false,
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
const unionMembers = extractUnionMembers(type);
|
|
714
|
+
const fieldResult = kind === "union"
|
|
715
|
+
? { fields: [], diagnostics: [] }
|
|
716
|
+
: extractFieldsFromType(type, checker, globalTypeMappings);
|
|
717
|
+
diagnostics.push(...fieldResult.diagnostics);
|
|
718
|
+
return {
|
|
719
|
+
typeInfo: {
|
|
720
|
+
metadata,
|
|
721
|
+
fields: fieldResult.fields,
|
|
722
|
+
unionMembers: unionMembers ?? null,
|
|
723
|
+
inlineObjectMembers: null,
|
|
724
|
+
enumMembers: null,
|
|
725
|
+
implementedInterfaces: null,
|
|
726
|
+
},
|
|
727
|
+
diagnostics,
|
|
728
|
+
scalarName: null,
|
|
729
|
+
scalarMetadata: null,
|
|
730
|
+
skip: false,
|
|
731
|
+
};
|
|
732
|
+
}
|
|
733
|
+
function processExportDeclaration(node, sourceFile, filePath, checker, globalTypeMappings, scannedSourceFiles) {
|
|
734
|
+
const types = [];
|
|
735
|
+
const diagnostics = [];
|
|
736
|
+
const detectedScalarNames = [];
|
|
737
|
+
const detectedScalars = [];
|
|
738
|
+
if (!node.isTypeOnly) {
|
|
739
|
+
return { types, diagnostics, detectedScalarNames, detectedScalars };
|
|
740
|
+
}
|
|
741
|
+
const exportClause = node.exportClause;
|
|
742
|
+
const symbolsToProcess = [];
|
|
743
|
+
if (exportClause && ts.isNamedExports(exportClause)) {
|
|
744
|
+
for (const specifier of exportClause.elements) {
|
|
745
|
+
const exportedName = specifier.name.text;
|
|
746
|
+
const localTargetSymbol = checker.getExportSpecifierLocalTargetSymbol(specifier);
|
|
747
|
+
if (!localTargetSymbol)
|
|
748
|
+
continue;
|
|
749
|
+
const originalSymbol = localTargetSymbol.flags & ts.SymbolFlags.Alias
|
|
750
|
+
? checker.getAliasedSymbol(localTargetSymbol)
|
|
751
|
+
: localTargetSymbol;
|
|
752
|
+
if (!originalSymbol)
|
|
753
|
+
continue;
|
|
754
|
+
const type = checker.getDeclaredTypeOfSymbol(originalSymbol);
|
|
755
|
+
symbolsToProcess.push({
|
|
756
|
+
exportedName,
|
|
757
|
+
resolvedSymbol: originalSymbol,
|
|
758
|
+
type,
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
else if (!exportClause && node.moduleSpecifier) {
|
|
763
|
+
const moduleSymbol = checker.getSymbolAtLocation(node.moduleSpecifier);
|
|
764
|
+
if (!moduleSymbol) {
|
|
765
|
+
const location = getSourceLocationFromNode(node);
|
|
766
|
+
const modulePath = ts.isStringLiteral(node.moduleSpecifier)
|
|
767
|
+
? node.moduleSpecifier.text
|
|
768
|
+
: node.moduleSpecifier.getText(sourceFile);
|
|
769
|
+
diagnostics.push({
|
|
770
|
+
code: "MODULE_RESOLUTION_ERROR",
|
|
771
|
+
message: `Could not resolve module '${modulePath}'`,
|
|
772
|
+
severity: "error",
|
|
773
|
+
location,
|
|
774
|
+
});
|
|
775
|
+
return { types, diagnostics, detectedScalarNames, detectedScalars };
|
|
776
|
+
}
|
|
777
|
+
const exports = checker.getExportsOfModule(moduleSymbol);
|
|
778
|
+
for (const exportedSymbol of exports) {
|
|
779
|
+
const resolvedSymbol = exportedSymbol.flags & ts.SymbolFlags.Alias
|
|
780
|
+
? checker.getAliasedSymbol(exportedSymbol)
|
|
781
|
+
: exportedSymbol;
|
|
782
|
+
if (!(resolvedSymbol.flags & ts.SymbolFlags.TypeAlias ||
|
|
783
|
+
resolvedSymbol.flags & ts.SymbolFlags.Interface ||
|
|
784
|
+
resolvedSymbol.flags & ts.SymbolFlags.Enum)) {
|
|
785
|
+
continue;
|
|
786
|
+
}
|
|
787
|
+
const type = checker.getDeclaredTypeOfSymbol(resolvedSymbol);
|
|
788
|
+
symbolsToProcess.push({
|
|
789
|
+
exportedName: exportedSymbol.getName(),
|
|
790
|
+
resolvedSymbol,
|
|
791
|
+
type,
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
const location = getSourceLocationFromNode(node);
|
|
796
|
+
for (const { exportedName, resolvedSymbol, type } of symbolsToProcess) {
|
|
797
|
+
const result = processReexportedSymbol({
|
|
798
|
+
exportedName,
|
|
799
|
+
resolvedSymbol,
|
|
800
|
+
type,
|
|
801
|
+
location,
|
|
802
|
+
filePath,
|
|
803
|
+
checker,
|
|
804
|
+
globalTypeMappings,
|
|
805
|
+
scannedSourceFiles,
|
|
806
|
+
});
|
|
807
|
+
if (result.skip)
|
|
808
|
+
continue;
|
|
809
|
+
if (result.scalarName && result.scalarMetadata) {
|
|
810
|
+
detectedScalarNames.push(result.scalarName);
|
|
811
|
+
detectedScalars.push(result.scalarMetadata);
|
|
812
|
+
continue;
|
|
813
|
+
}
|
|
814
|
+
diagnostics.push(...result.diagnostics);
|
|
815
|
+
if (result.typeInfo) {
|
|
816
|
+
types.push(result.typeInfo);
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
return { types, diagnostics, detectedScalarNames, detectedScalars };
|
|
820
|
+
}
|
|
821
|
+
function getNamedTypeName(memberType) {
|
|
822
|
+
// For type aliases (e.g., GqlObject<...>), use aliasSymbol
|
|
823
|
+
if (memberType.aliasSymbol) {
|
|
824
|
+
return memberType.aliasSymbol.getName();
|
|
825
|
+
}
|
|
826
|
+
// For regular types, use symbol
|
|
827
|
+
return memberType.symbol?.getName() ?? "";
|
|
828
|
+
}
|
|
829
|
+
function extractInlineObjectMembers(type, checker, globalTypeMappings = []) {
|
|
830
|
+
if (!type.isUnion()) {
|
|
831
|
+
return null;
|
|
832
|
+
}
|
|
833
|
+
const nonNullTypes = getNonNullableTypes(type);
|
|
834
|
+
const allObjectTypes = nonNullTypes.every((t) => (t.flags & ts.TypeFlags.Object) !== 0 ||
|
|
835
|
+
(t.flags & ts.TypeFlags.Intersection) !== 0);
|
|
836
|
+
if (nonNullTypes.length < 2 || !allObjectTypes) {
|
|
837
|
+
return null;
|
|
838
|
+
}
|
|
839
|
+
let hasInlineObjects = false;
|
|
840
|
+
let hasNamedTypes = false;
|
|
841
|
+
const members = [];
|
|
842
|
+
for (const memberType of nonNullTypes) {
|
|
843
|
+
if (isAnonymousObjectType(memberType)) {
|
|
844
|
+
hasInlineObjects = true;
|
|
845
|
+
const properties = memberType.getProperties();
|
|
846
|
+
const memberProperties = [];
|
|
847
|
+
for (const prop of properties) {
|
|
848
|
+
const propType = checker.getTypeOfSymbol(prop);
|
|
849
|
+
const tsdocInfo = extractTsDocFromSymbol(prop, checker);
|
|
850
|
+
const typeResult = convertTsTypeToReference(propType, checker, globalTypeMappings);
|
|
851
|
+
memberProperties.push({
|
|
852
|
+
propertyName: prop.getName(),
|
|
853
|
+
propertyType: typeResult.tsType,
|
|
854
|
+
description: tsdocInfo.description ?? null,
|
|
855
|
+
deprecated: tsdocInfo.deprecated ?? null,
|
|
856
|
+
});
|
|
857
|
+
}
|
|
858
|
+
members.push({ properties: memberProperties });
|
|
859
|
+
}
|
|
860
|
+
else {
|
|
861
|
+
hasNamedTypes = true;
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
return { members, hasInlineObjects, hasNamedTypes };
|
|
865
|
+
}
|
|
866
|
+
function extractUnionMembers(type) {
|
|
867
|
+
if (!type.isUnion()) {
|
|
868
|
+
return undefined;
|
|
869
|
+
}
|
|
870
|
+
const nonNullTypes = getNonNullableTypes(type);
|
|
871
|
+
const allObjectTypes = nonNullTypes.every((t) => (t.flags & ts.TypeFlags.Object) !== 0 ||
|
|
872
|
+
(t.flags & ts.TypeFlags.Intersection) !== 0 ||
|
|
873
|
+
t.symbol !== undefined);
|
|
874
|
+
if (nonNullTypes.length > 1 && allObjectTypes) {
|
|
875
|
+
const namedMembers = nonNullTypes
|
|
876
|
+
.filter((t) => !isAnonymousObjectType(t))
|
|
877
|
+
.map((t) => getNamedTypeName(t))
|
|
878
|
+
.filter((name) => name !== "" && name !== "__type");
|
|
879
|
+
if (namedMembers.length > 0) {
|
|
880
|
+
return namedMembers.sort();
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
return undefined;
|
|
884
|
+
}
|
|
885
|
+
export function extractTypesFromProgram(program, sourceFiles, options = {}) {
|
|
886
|
+
const checker = program.getTypeChecker();
|
|
887
|
+
const types = [];
|
|
888
|
+
const diagnostics = [];
|
|
889
|
+
const detectedScalarNames = new Set();
|
|
890
|
+
const detectedScalars = [];
|
|
891
|
+
const globalTypeMappings = options.globalTypeMappings ?? [];
|
|
892
|
+
const scannedSourceFilesSet = new Set(sourceFiles);
|
|
893
|
+
for (const filePath of sourceFiles) {
|
|
894
|
+
const sourceFile = program.getSourceFile(filePath);
|
|
895
|
+
if (!sourceFile) {
|
|
896
|
+
diagnostics.push({
|
|
897
|
+
code: "PARSE_ERROR",
|
|
898
|
+
message: `Could not load source file: ${filePath}`,
|
|
899
|
+
severity: "error",
|
|
900
|
+
location: { file: filePath, line: 1, column: 1 },
|
|
901
|
+
});
|
|
902
|
+
continue;
|
|
903
|
+
}
|
|
904
|
+
ts.forEachChild(sourceFile, (node) => {
|
|
905
|
+
if (ts.isEnumDeclaration(node)) {
|
|
906
|
+
const hasExport = isExported(node);
|
|
907
|
+
const hasDefaultExport = isDefaultExport(node, sourceFile);
|
|
908
|
+
if (!hasExport && !hasDefaultExport) {
|
|
909
|
+
return;
|
|
910
|
+
}
|
|
911
|
+
const name = node.name.getText(sourceFile);
|
|
912
|
+
const location = getSourceLocationFromNode(node);
|
|
913
|
+
if (isConstEnum(node)) {
|
|
914
|
+
diagnostics.push({
|
|
915
|
+
code: "UNSUPPORTED_ENUM_TYPE",
|
|
916
|
+
message: `Const enum '${name}' is not supported. Use a regular enum instead.`,
|
|
917
|
+
severity: "error",
|
|
918
|
+
location,
|
|
919
|
+
});
|
|
920
|
+
return;
|
|
921
|
+
}
|
|
922
|
+
if (isHeterogeneousEnum(node)) {
|
|
923
|
+
diagnostics.push({
|
|
924
|
+
code: "UNSUPPORTED_ENUM_TYPE",
|
|
925
|
+
message: `Heterogeneous enum '${name}' is not supported. Use a string enum instead.`,
|
|
926
|
+
severity: "error",
|
|
927
|
+
location,
|
|
928
|
+
});
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
const enumMembers = extractEnumMembers(node, checker);
|
|
932
|
+
const validationDiagnostics = validateNumericEnumMembers(enumMembers, name, location);
|
|
933
|
+
if (validationDiagnostics.length > 0) {
|
|
934
|
+
diagnostics.push(...validationDiagnostics);
|
|
935
|
+
return;
|
|
936
|
+
}
|
|
937
|
+
const tsdocInfo = extractTsDocInfo(node, checker);
|
|
938
|
+
const metadata = {
|
|
939
|
+
name,
|
|
940
|
+
kind: "enum",
|
|
941
|
+
sourceFile: filePath,
|
|
942
|
+
sourceLocation: location,
|
|
943
|
+
exportKind: hasDefaultExport ? "default" : "named",
|
|
944
|
+
description: tsdocInfo.description,
|
|
945
|
+
deprecated: tsdocInfo.deprecated,
|
|
946
|
+
directives: null,
|
|
947
|
+
};
|
|
948
|
+
types.push({
|
|
949
|
+
metadata,
|
|
950
|
+
fields: [],
|
|
951
|
+
unionMembers: null,
|
|
952
|
+
inlineObjectMembers: null,
|
|
953
|
+
enumMembers,
|
|
954
|
+
implementedInterfaces: null,
|
|
955
|
+
});
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
958
|
+
if (ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node)) {
|
|
959
|
+
const hasExport = isExported(node);
|
|
960
|
+
const hasDefaultExport = isDefaultExport(node, sourceFile);
|
|
961
|
+
if (!hasExport && !hasDefaultExport) {
|
|
962
|
+
return;
|
|
963
|
+
}
|
|
964
|
+
const name = node.name.getText(sourceFile);
|
|
965
|
+
const typeSourceLocation = getSourceLocationFromNode(node);
|
|
966
|
+
if (node.typeParameters && node.typeParameters.length > 0) {
|
|
967
|
+
diagnostics.push({
|
|
968
|
+
code: "UNSUPPORTED_SYNTAX",
|
|
969
|
+
message: `Generic type '${name}' is not supported. Consider using a concrete type instead.`,
|
|
970
|
+
severity: "warning",
|
|
971
|
+
location: typeSourceLocation,
|
|
972
|
+
});
|
|
973
|
+
}
|
|
974
|
+
const symbol = checker.getSymbolAtLocation(node.name);
|
|
975
|
+
if (!symbol) {
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
const type = checker.getDeclaredTypeOfSymbol(symbol);
|
|
979
|
+
const scalarMetadata = detectScalarMetadata(type, checker);
|
|
980
|
+
if (scalarMetadata.scalarName && !scalarMetadata.isPrimitive) {
|
|
981
|
+
detectedScalarNames.add(scalarMetadata.scalarName);
|
|
982
|
+
const tsdocInfo = extractTsDocInfo(node, checker);
|
|
983
|
+
detectedScalars.push({
|
|
984
|
+
scalarName: scalarMetadata.scalarName,
|
|
985
|
+
typeName: name,
|
|
986
|
+
only: scalarMetadata.only,
|
|
987
|
+
sourceFile: filePath,
|
|
988
|
+
line: typeSourceLocation.line,
|
|
989
|
+
description: tsdocInfo.description ?? null,
|
|
990
|
+
});
|
|
991
|
+
return;
|
|
992
|
+
}
|
|
993
|
+
let typeDirectives = null;
|
|
994
|
+
let actualType = type;
|
|
995
|
+
if (hasDirectiveMetadata(type)) {
|
|
996
|
+
const directiveResult = detectDirectiveMetadata(type, checker);
|
|
997
|
+
if (directiveResult.directives.length > 0) {
|
|
998
|
+
typeDirectives = directiveResult.directives;
|
|
999
|
+
}
|
|
1000
|
+
if (directiveResult.errors.length > 0) {
|
|
1001
|
+
for (const error of directiveResult.errors) {
|
|
1002
|
+
diagnostics.push({
|
|
1003
|
+
code: error.code,
|
|
1004
|
+
message: `Type '${name}': ${error.message}`,
|
|
1005
|
+
severity: "error",
|
|
1006
|
+
location: typeSourceLocation,
|
|
1007
|
+
});
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
actualType = type;
|
|
1011
|
+
}
|
|
1012
|
+
const kind = determineTypeKind(node, actualType, sourceFile);
|
|
1013
|
+
const unionMembers = extractUnionMembers(actualType);
|
|
1014
|
+
const inlineObjectResult = extractInlineObjectMembers(actualType, checker, globalTypeMappings);
|
|
1015
|
+
const tsdocInfo = extractTsDocInfo(node, checker);
|
|
1016
|
+
let implementedInterfaces = null;
|
|
1017
|
+
if (ts.isTypeAliasDeclaration(node)) {
|
|
1018
|
+
if (kind === "graphqlInterface") {
|
|
1019
|
+
const interfaces = extractImplementsFromDefineInterface(node, sourceFile, checker);
|
|
1020
|
+
if (interfaces.length > 0) {
|
|
1021
|
+
implementedInterfaces = interfaces;
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
else {
|
|
1025
|
+
const interfaces = extractImplementsFromGqlTypeDef(node, sourceFile, checker);
|
|
1026
|
+
if (interfaces.length > 0) {
|
|
1027
|
+
implementedInterfaces = interfaces;
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
const metadata = {
|
|
1032
|
+
name,
|
|
1033
|
+
kind,
|
|
1034
|
+
sourceFile: filePath,
|
|
1035
|
+
sourceLocation: typeSourceLocation,
|
|
1036
|
+
exportKind: hasDefaultExport ? "default" : "named",
|
|
1037
|
+
description: tsdocInfo.description,
|
|
1038
|
+
deprecated: tsdocInfo.deprecated,
|
|
1039
|
+
directives: typeDirectives,
|
|
1040
|
+
};
|
|
1041
|
+
if (kind === "enum") {
|
|
1042
|
+
const enumMembers = extractStringLiteralUnionMembers(actualType, checker);
|
|
1043
|
+
types.push({
|
|
1044
|
+
metadata,
|
|
1045
|
+
fields: [],
|
|
1046
|
+
unionMembers: null,
|
|
1047
|
+
inlineObjectMembers: null,
|
|
1048
|
+
enumMembers,
|
|
1049
|
+
implementedInterfaces: null,
|
|
1050
|
+
});
|
|
1051
|
+
return;
|
|
1052
|
+
}
|
|
1053
|
+
const fieldResult = kind === "union"
|
|
1054
|
+
? { fields: [], diagnostics: [] }
|
|
1055
|
+
: extractFieldsFromType(actualType, checker, globalTypeMappings);
|
|
1056
|
+
const fields = fieldResult.fields;
|
|
1057
|
+
diagnostics.push(...fieldResult.diagnostics);
|
|
1058
|
+
if (name.endsWith("Input") && kind === "union") {
|
|
1059
|
+
if (inlineObjectResult?.hasInlineObjects &&
|
|
1060
|
+
inlineObjectResult.hasNamedTypes) {
|
|
1061
|
+
diagnostics.push({
|
|
1062
|
+
code: "ONEOF_MIXED_MEMBERS",
|
|
1063
|
+
message: `Input union type '${name}' mixes inline object literals with named type references. Use only inline object literals for oneOf input types.`,
|
|
1064
|
+
severity: "error",
|
|
1065
|
+
location: {
|
|
1066
|
+
...typeSourceLocation,
|
|
1067
|
+
column: 1,
|
|
1068
|
+
},
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
1071
|
+
else if (inlineObjectResult?.hasNamedTypes &&
|
|
1072
|
+
!inlineObjectResult.hasInlineObjects) {
|
|
1073
|
+
diagnostics.push({
|
|
1074
|
+
code: "ONEOF_NAMED_TYPE_UNION",
|
|
1075
|
+
message: `Input union type '${name}' uses named type references instead of inline object literals. Use inline object pattern: type ${name} = { field1: Type1 } | { field2: Type2 }`,
|
|
1076
|
+
severity: "error",
|
|
1077
|
+
location: {
|
|
1078
|
+
...typeSourceLocation,
|
|
1079
|
+
column: 1,
|
|
1080
|
+
},
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
const inlineObjectMembers = inlineObjectResult?.hasInlineObjects &&
|
|
1085
|
+
!inlineObjectResult.hasNamedTypes
|
|
1086
|
+
? inlineObjectResult.members
|
|
1087
|
+
: null;
|
|
1088
|
+
const typeInfo = {
|
|
1089
|
+
metadata,
|
|
1090
|
+
fields,
|
|
1091
|
+
unionMembers: unionMembers ?? null,
|
|
1092
|
+
inlineObjectMembers,
|
|
1093
|
+
enumMembers: null,
|
|
1094
|
+
implementedInterfaces,
|
|
1095
|
+
};
|
|
1096
|
+
types.push(typeInfo);
|
|
1097
|
+
}
|
|
1098
|
+
if (ts.isExportDeclaration(node)) {
|
|
1099
|
+
const result = processExportDeclaration(node, sourceFile, filePath, checker, globalTypeMappings, scannedSourceFilesSet);
|
|
1100
|
+
types.push(...result.types);
|
|
1101
|
+
diagnostics.push(...result.diagnostics);
|
|
1102
|
+
for (const scalarName of result.detectedScalarNames) {
|
|
1103
|
+
detectedScalarNames.add(scalarName);
|
|
1104
|
+
}
|
|
1105
|
+
detectedScalars.push(...result.detectedScalars);
|
|
1106
|
+
}
|
|
1107
|
+
});
|
|
1108
|
+
}
|
|
1109
|
+
return {
|
|
1110
|
+
types,
|
|
1111
|
+
diagnostics,
|
|
1112
|
+
detectedScalarNames: [...detectedScalarNames],
|
|
1113
|
+
detectedScalars,
|
|
1114
|
+
};
|
|
1115
|
+
}
|
|
1116
|
+
//# sourceMappingURL=type-extractor.js.map
|