@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,556 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Directive metadata detector.
|
|
3
|
+
*
|
|
4
|
+
* This module provides functions to detect directive metadata embedded
|
|
5
|
+
* in TypeScript intersection types using the $gqlkitFieldMeta or $gqlkitTypeMeta properties.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import ts from "typescript";
|
|
9
|
+
import { METADATA_PROPERTIES } from "./constants.js";
|
|
10
|
+
import { getActualMetadataType } from "./metadata-detector.js";
|
|
11
|
+
|
|
12
|
+
const FIELD_META_PROPERTY = METADATA_PROPERTIES.FIELD_META;
|
|
13
|
+
const TYPE_META_PROPERTY = METADATA_PROPERTIES.TYPE_META;
|
|
14
|
+
const DIRECTIVE_NAME_PROPERTY = METADATA_PROPERTIES.DIRECTIVE_NAME;
|
|
15
|
+
const DIRECTIVE_ARGS_PROPERTY = METADATA_PROPERTIES.DIRECTIVE_ARGS;
|
|
16
|
+
const ORIGINAL_TYPE_PROPERTY = METADATA_PROPERTIES.ORIGINAL_TYPE;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Gets the metadata property from a type, checking both field and type meta properties.
|
|
20
|
+
*/
|
|
21
|
+
function getMetaProperty(type: ts.Type): ts.Symbol | undefined {
|
|
22
|
+
return (
|
|
23
|
+
type.getProperty(FIELD_META_PROPERTY) ??
|
|
24
|
+
type.getProperty(TYPE_META_PROPERTY)
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Represents a single directive argument value.
|
|
30
|
+
*/
|
|
31
|
+
export type DirectiveArgumentValue =
|
|
32
|
+
| { readonly kind: "string"; readonly value: string }
|
|
33
|
+
| { readonly kind: "number"; readonly value: number }
|
|
34
|
+
| { readonly kind: "boolean"; readonly value: boolean }
|
|
35
|
+
| { readonly kind: "null"; readonly value: null }
|
|
36
|
+
| { readonly kind: "enum"; readonly value: string }
|
|
37
|
+
| {
|
|
38
|
+
readonly kind: "list";
|
|
39
|
+
readonly values: ReadonlyArray<DirectiveArgumentValue>;
|
|
40
|
+
}
|
|
41
|
+
| {
|
|
42
|
+
readonly kind: "object";
|
|
43
|
+
readonly fields: ReadonlyArray<DirectiveArgument>;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Represents a directive argument (name-value pair).
|
|
48
|
+
*/
|
|
49
|
+
export interface DirectiveArgument {
|
|
50
|
+
readonly name: string;
|
|
51
|
+
readonly value: DirectiveArgumentValue;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Represents a detected directive with its name and arguments.
|
|
56
|
+
*/
|
|
57
|
+
export interface DirectiveInfo {
|
|
58
|
+
readonly name: string;
|
|
59
|
+
readonly args: ReadonlyArray<DirectiveArgument>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Error codes for directive detection.
|
|
64
|
+
*/
|
|
65
|
+
export type DirectiveDetectionErrorCode =
|
|
66
|
+
| "EMPTY_DIRECTIVE_NAME"
|
|
67
|
+
| "UNRESOLVABLE_ARGUMENT";
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Error information for directive detection.
|
|
71
|
+
*/
|
|
72
|
+
export interface DirectiveDetectionError {
|
|
73
|
+
readonly code: DirectiveDetectionErrorCode;
|
|
74
|
+
readonly message: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Result of directive detection.
|
|
79
|
+
*/
|
|
80
|
+
export interface DirectiveDetectionResult {
|
|
81
|
+
readonly directives: ReadonlyArray<DirectiveInfo>;
|
|
82
|
+
readonly errors: ReadonlyArray<DirectiveDetectionError>;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function createEmptyResult(): DirectiveDetectionResult {
|
|
86
|
+
return {
|
|
87
|
+
directives: [],
|
|
88
|
+
errors: [],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Resolves a directive argument value from a TypeScript type.
|
|
94
|
+
*/
|
|
95
|
+
export function resolveArgumentValue(
|
|
96
|
+
type: ts.Type,
|
|
97
|
+
checker: ts.TypeChecker,
|
|
98
|
+
): DirectiveArgumentValue | null {
|
|
99
|
+
if (type.flags & ts.TypeFlags.Null) {
|
|
100
|
+
return { kind: "null", value: null };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (type.isStringLiteral()) {
|
|
104
|
+
// Check enum pattern: starts with uppercase and contains only uppercase letters, digits, and underscores
|
|
105
|
+
if (/^[A-Z][A-Z0-9_]*$/.test(type.value)) {
|
|
106
|
+
return { kind: "enum", value: type.value };
|
|
107
|
+
}
|
|
108
|
+
return { kind: "string", value: type.value };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (type.isNumberLiteral()) {
|
|
112
|
+
return { kind: "number", value: type.value };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (type.flags & ts.TypeFlags.BooleanLiteral) {
|
|
116
|
+
const intrinsicName = (type as unknown as { intrinsicName?: string })
|
|
117
|
+
.intrinsicName;
|
|
118
|
+
if (intrinsicName === "true") {
|
|
119
|
+
return { kind: "boolean", value: true };
|
|
120
|
+
}
|
|
121
|
+
if (intrinsicName === "false") {
|
|
122
|
+
return { kind: "boolean", value: false };
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (checker.isTupleType(type)) {
|
|
127
|
+
const typeArgs = checker.getTypeArguments(type as ts.TypeReference);
|
|
128
|
+
const values: DirectiveArgumentValue[] = [];
|
|
129
|
+
for (const arg of typeArgs) {
|
|
130
|
+
const resolved = resolveArgumentValue(arg, checker);
|
|
131
|
+
if (resolved) {
|
|
132
|
+
values.push(resolved);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return { kind: "list", values };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (checker.isArrayType(type)) {
|
|
139
|
+
const typeArgs = checker.getTypeArguments(type as ts.TypeReference);
|
|
140
|
+
if (typeArgs.length > 0 && typeArgs[0]) {
|
|
141
|
+
const elemType = typeArgs[0];
|
|
142
|
+
if (elemType.isUnion()) {
|
|
143
|
+
const values: DirectiveArgumentValue[] = [];
|
|
144
|
+
for (const member of elemType.types) {
|
|
145
|
+
const resolved = resolveArgumentValue(member, checker);
|
|
146
|
+
if (resolved) {
|
|
147
|
+
values.push(resolved);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return { kind: "list", values };
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const properties = type.getProperties();
|
|
156
|
+
if (properties.length > 0) {
|
|
157
|
+
const isMetadataProperty = properties.some(
|
|
158
|
+
(p) =>
|
|
159
|
+
p.getName().startsWith(" $") ||
|
|
160
|
+
p.getName() === DIRECTIVE_NAME_PROPERTY ||
|
|
161
|
+
p.getName() === DIRECTIVE_ARGS_PROPERTY,
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
if (!isMetadataProperty) {
|
|
165
|
+
const fields: DirectiveArgument[] = [];
|
|
166
|
+
for (const prop of properties) {
|
|
167
|
+
const propType = checker.getTypeOfSymbol(prop);
|
|
168
|
+
const resolved = resolveArgumentValue(propType, checker);
|
|
169
|
+
if (resolved) {
|
|
170
|
+
fields.push({ name: prop.getName(), value: resolved });
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (fields.length > 0) {
|
|
174
|
+
return { kind: "object", fields };
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const symbol = type.getSymbol();
|
|
180
|
+
if (symbol) {
|
|
181
|
+
const name = symbol.getName();
|
|
182
|
+
if (
|
|
183
|
+
name !== "__type" &&
|
|
184
|
+
name !== "Array" &&
|
|
185
|
+
!name.includes("<") &&
|
|
186
|
+
/^[A-Z][A-Z0-9_]*$/.test(name)
|
|
187
|
+
) {
|
|
188
|
+
return { kind: "enum", value: name };
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
interface ExtractDirectiveArgsResult {
|
|
196
|
+
readonly args: DirectiveArgument[];
|
|
197
|
+
readonly errors: DirectiveDetectionError[];
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Extracts directive arguments from a type.
|
|
202
|
+
*/
|
|
203
|
+
function extractDirectiveArgs(
|
|
204
|
+
argsType: ts.Type,
|
|
205
|
+
checker: ts.TypeChecker,
|
|
206
|
+
directiveName: string,
|
|
207
|
+
): ExtractDirectiveArgsResult {
|
|
208
|
+
const args: DirectiveArgument[] = [];
|
|
209
|
+
const errors: DirectiveDetectionError[] = [];
|
|
210
|
+
const properties = argsType.getProperties();
|
|
211
|
+
|
|
212
|
+
for (const prop of properties) {
|
|
213
|
+
const propName = prop.getName();
|
|
214
|
+
const propType = checker.getTypeOfSymbol(prop);
|
|
215
|
+
const resolved = resolveArgumentValue(propType, checker);
|
|
216
|
+
if (resolved) {
|
|
217
|
+
args.push({ name: propName, value: resolved });
|
|
218
|
+
} else {
|
|
219
|
+
errors.push({
|
|
220
|
+
code: "UNRESOLVABLE_ARGUMENT",
|
|
221
|
+
message: `Cannot resolve argument '${propName}' for directive '@${directiveName}'`,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return { args, errors };
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Extracts a single directive from a type.
|
|
231
|
+
*/
|
|
232
|
+
function extractDirectiveFromType(
|
|
233
|
+
type: ts.Type,
|
|
234
|
+
checker: ts.TypeChecker,
|
|
235
|
+
): { directive: DirectiveInfo | null; errors: DirectiveDetectionError[] } {
|
|
236
|
+
const nameProp = type.getProperty(DIRECTIVE_NAME_PROPERTY);
|
|
237
|
+
if (!nameProp) {
|
|
238
|
+
return { directive: null, errors: [] };
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const rawNameType = checker.getTypeOfSymbol(nameProp);
|
|
242
|
+
const nameType = getActualMetadataType(rawNameType);
|
|
243
|
+
if (!nameType || !nameType.isStringLiteral()) {
|
|
244
|
+
return { directive: null, errors: [] };
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const directiveName = nameType.value;
|
|
248
|
+
|
|
249
|
+
if (directiveName === "") {
|
|
250
|
+
return {
|
|
251
|
+
directive: null,
|
|
252
|
+
errors: [
|
|
253
|
+
{
|
|
254
|
+
code: "EMPTY_DIRECTIVE_NAME",
|
|
255
|
+
message: "Directive name cannot be empty",
|
|
256
|
+
},
|
|
257
|
+
],
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const argsProp = type.getProperty(DIRECTIVE_ARGS_PROPERTY);
|
|
262
|
+
let args: DirectiveArgument[] = [];
|
|
263
|
+
let argErrors: DirectiveDetectionError[] = [];
|
|
264
|
+
|
|
265
|
+
if (argsProp) {
|
|
266
|
+
const rawArgsType = checker.getTypeOfSymbol(argsProp);
|
|
267
|
+
const argsType = getActualMetadataType(rawArgsType);
|
|
268
|
+
if (argsType) {
|
|
269
|
+
const argsResult = extractDirectiveArgs(argsType, checker, directiveName);
|
|
270
|
+
args = argsResult.args;
|
|
271
|
+
argErrors = argsResult.errors;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return {
|
|
276
|
+
directive: { name: directiveName, args },
|
|
277
|
+
errors: argErrors,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Detects directive metadata from a TypeScript type.
|
|
283
|
+
*
|
|
284
|
+
* This function analyzes TypeScript types to detect directive metadata:
|
|
285
|
+
* - Intersection types with " $gqlkitFieldMeta" or " $gqlkitTypeMeta" property indicate directives
|
|
286
|
+
* - Each directive has a name and optional arguments
|
|
287
|
+
* - Arguments are resolved from TypeScript literal types
|
|
288
|
+
*
|
|
289
|
+
* @param type - The TypeScript type to analyze
|
|
290
|
+
* @param checker - The TypeScript type checker
|
|
291
|
+
* @returns Detection result with directives and any errors
|
|
292
|
+
*/
|
|
293
|
+
export function detectDirectiveMetadata(
|
|
294
|
+
type: ts.Type,
|
|
295
|
+
checker: ts.TypeChecker,
|
|
296
|
+
): DirectiveDetectionResult {
|
|
297
|
+
const metaProp = getMetaProperty(type);
|
|
298
|
+
if (!metaProp) {
|
|
299
|
+
if (type.isIntersection()) {
|
|
300
|
+
for (const member of type.types) {
|
|
301
|
+
const memberProp = getMetaProperty(member);
|
|
302
|
+
if (memberProp) {
|
|
303
|
+
return detectDirectiveMetadataFromProperty(memberProp, checker);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
// Handle union types: (T & Directive) | null
|
|
308
|
+
if (type.isUnion()) {
|
|
309
|
+
for (const member of type.types) {
|
|
310
|
+
// Skip null/undefined members
|
|
311
|
+
if (
|
|
312
|
+
member.flags & ts.TypeFlags.Null ||
|
|
313
|
+
member.flags & ts.TypeFlags.Undefined
|
|
314
|
+
) {
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
const result = detectDirectiveMetadata(member, checker);
|
|
318
|
+
if (result.directives.length > 0) {
|
|
319
|
+
return result;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return createEmptyResult();
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return detectDirectiveMetadataFromProperty(metaProp, checker);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function detectDirectiveMetadataFromProperty(
|
|
330
|
+
directivesProp: ts.Symbol,
|
|
331
|
+
checker: ts.TypeChecker,
|
|
332
|
+
): DirectiveDetectionResult {
|
|
333
|
+
const rawDirectivesType = checker.getTypeOfSymbol(directivesProp);
|
|
334
|
+
const directivesType = getActualMetadataType(rawDirectivesType);
|
|
335
|
+
|
|
336
|
+
if (!directivesType) {
|
|
337
|
+
return createEmptyResult();
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// New structure: { directives: Ds }
|
|
341
|
+
// Check if the type has a "directives" property
|
|
342
|
+
const directivesArrayProp = directivesType.getProperty("directives");
|
|
343
|
+
if (directivesArrayProp) {
|
|
344
|
+
const rawDirectivesArrayType = checker.getTypeOfSymbol(directivesArrayProp);
|
|
345
|
+
const directivesArrayType = getActualMetadataType(rawDirectivesArrayType);
|
|
346
|
+
if (directivesArrayType) {
|
|
347
|
+
return extractDirectivesFromType(directivesArrayType, checker);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Fallback: Old structure - direct array/tuple form (for backward compatibility)
|
|
352
|
+
return extractDirectivesFromType(directivesType, checker);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Extracts directives from a tuple or array type.
|
|
357
|
+
* Use this to extract directives from a type like [AuthDirective, CacheDirective].
|
|
358
|
+
*/
|
|
359
|
+
export function extractDirectivesFromType(
|
|
360
|
+
directivesType: ts.Type,
|
|
361
|
+
checker: ts.TypeChecker,
|
|
362
|
+
): DirectiveDetectionResult {
|
|
363
|
+
const directives: DirectiveInfo[] = [];
|
|
364
|
+
const errors: DirectiveDetectionError[] = [];
|
|
365
|
+
|
|
366
|
+
if (checker.isTupleType(directivesType)) {
|
|
367
|
+
const typeArgs = checker.getTypeArguments(
|
|
368
|
+
directivesType as ts.TypeReference,
|
|
369
|
+
);
|
|
370
|
+
for (const arg of typeArgs) {
|
|
371
|
+
const result = extractDirectiveFromType(arg, checker);
|
|
372
|
+
if (result.directive) {
|
|
373
|
+
directives.push(result.directive);
|
|
374
|
+
}
|
|
375
|
+
errors.push(...result.errors);
|
|
376
|
+
}
|
|
377
|
+
} else if (checker.isArrayType(directivesType)) {
|
|
378
|
+
const typeArgs = checker.getTypeArguments(
|
|
379
|
+
directivesType as ts.TypeReference,
|
|
380
|
+
);
|
|
381
|
+
if (typeArgs.length > 0 && typeArgs[0]) {
|
|
382
|
+
const elemType = typeArgs[0];
|
|
383
|
+
if (elemType.isUnion()) {
|
|
384
|
+
for (const member of elemType.types) {
|
|
385
|
+
const result = extractDirectiveFromType(member, checker);
|
|
386
|
+
if (result.directive) {
|
|
387
|
+
directives.push(result.directive);
|
|
388
|
+
}
|
|
389
|
+
errors.push(...result.errors);
|
|
390
|
+
}
|
|
391
|
+
} else {
|
|
392
|
+
const result = extractDirectiveFromType(elemType, checker);
|
|
393
|
+
if (result.directive) {
|
|
394
|
+
directives.push(result.directive);
|
|
395
|
+
}
|
|
396
|
+
errors.push(...result.errors);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
} else {
|
|
400
|
+
const result = extractDirectiveFromType(directivesType, checker);
|
|
401
|
+
if (result.directive) {
|
|
402
|
+
directives.push(result.directive);
|
|
403
|
+
}
|
|
404
|
+
errors.push(...result.errors);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
return { directives, errors };
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Checks if a type is wrapped with GqlField or GqlObject.
|
|
412
|
+
*/
|
|
413
|
+
export function hasDirectiveMetadata(type: ts.Type): boolean {
|
|
414
|
+
const metaProp = getMetaProperty(type);
|
|
415
|
+
if (metaProp) {
|
|
416
|
+
return true;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// Also check for the original type property (GqlField marker)
|
|
420
|
+
const originalTypeProp = type.getProperty(ORIGINAL_TYPE_PROPERTY);
|
|
421
|
+
if (originalTypeProp) {
|
|
422
|
+
return true;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
if (type.isIntersection()) {
|
|
426
|
+
for (const member of type.types) {
|
|
427
|
+
const prop = getMetaProperty(member);
|
|
428
|
+
if (prop) {
|
|
429
|
+
return true;
|
|
430
|
+
}
|
|
431
|
+
// Also check for original type property in intersection members
|
|
432
|
+
const origProp = member.getProperty(ORIGINAL_TYPE_PROPERTY);
|
|
433
|
+
if (origProp) {
|
|
434
|
+
return true;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Handle union types: (T & Meta) | null is normalized by TypeScript
|
|
440
|
+
// to (T & Meta) | null, so we need to check each member recursively
|
|
441
|
+
if (type.isUnion()) {
|
|
442
|
+
for (const member of type.types) {
|
|
443
|
+
if (hasDirectiveMetadata(member)) {
|
|
444
|
+
return true;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
return false;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Unwraps a GqlField or GqlObject type and returns the base type.
|
|
454
|
+
* For GqlField<T, Meta> which is T & { " $gqlkitFieldMeta"?: ...; " $gqlkitOriginalType"?: T },
|
|
455
|
+
* this extracts and returns T from the $gqlkitOriginalType property.
|
|
456
|
+
*
|
|
457
|
+
* The $gqlkitOriginalType property preserves nullability information that would otherwise
|
|
458
|
+
* be lost due to TypeScript's union type normalization.
|
|
459
|
+
*
|
|
460
|
+
* If the type is not wrapped with GqlField or GqlObject, returns the original type.
|
|
461
|
+
*/
|
|
462
|
+
export function unwrapDirectiveType(
|
|
463
|
+
type: ts.Type,
|
|
464
|
+
checker: ts.TypeChecker,
|
|
465
|
+
): ts.Type {
|
|
466
|
+
// 1. Check aliasTypeArguments first (most reliable)
|
|
467
|
+
// Get T directly from GqlField<T, Meta> or GqlObject<T, Meta>
|
|
468
|
+
// This works when the type alias hasn't been expanded by TypeScript
|
|
469
|
+
// We detect GqlField/GqlObject by checking for metadata properties, not by type name.
|
|
470
|
+
if (type.aliasTypeArguments && type.aliasTypeArguments.length > 0) {
|
|
471
|
+
const metaProp = getMetaProperty(type);
|
|
472
|
+
const originalTypeProp = type.getProperty(ORIGINAL_TYPE_PROPERTY);
|
|
473
|
+
if (metaProp || originalTypeProp) {
|
|
474
|
+
return type.aliasTypeArguments[0]!;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// 2. Check intersection members' aliasTypeArguments
|
|
479
|
+
// When TypeScript expands the type alias to an intersection,
|
|
480
|
+
// one of the intersection members might still have aliasTypeArguments
|
|
481
|
+
if (type.isIntersection()) {
|
|
482
|
+
for (const member of type.types) {
|
|
483
|
+
if (member.aliasTypeArguments && member.aliasTypeArguments.length > 0) {
|
|
484
|
+
const memberMetaProp = getMetaProperty(member);
|
|
485
|
+
const memberOriginalTypeProp = member.getProperty(
|
|
486
|
+
ORIGINAL_TYPE_PROPERTY,
|
|
487
|
+
);
|
|
488
|
+
if (memberMetaProp || memberOriginalTypeProp) {
|
|
489
|
+
return member.aliasTypeArguments[0]!;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// 3. Fall back to $gqlkitOriginalType property
|
|
496
|
+
// This property preserves the original type information including array types.
|
|
497
|
+
// The type's symbol name may be __type (internal TypeScript symbol), but that's
|
|
498
|
+
// handled by the caller using checker.typeToString() for correct type name resolution.
|
|
499
|
+
const originalTypeProp = type.getProperty(ORIGINAL_TYPE_PROPERTY);
|
|
500
|
+
if (originalTypeProp) {
|
|
501
|
+
const rawOriginalType = checker.getTypeOfSymbol(originalTypeProp);
|
|
502
|
+
const originalType = getActualMetadataType(rawOriginalType);
|
|
503
|
+
if (originalType) {
|
|
504
|
+
return originalType;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// Check intersection members for $gqlkitOriginalType
|
|
509
|
+
if (type.isIntersection()) {
|
|
510
|
+
for (const member of type.types) {
|
|
511
|
+
const originalProp = member.getProperty(ORIGINAL_TYPE_PROPERTY);
|
|
512
|
+
if (originalProp) {
|
|
513
|
+
const rawOriginalType = checker.getTypeOfSymbol(originalProp);
|
|
514
|
+
const originalType = getActualMetadataType(rawOriginalType);
|
|
515
|
+
if (originalType) {
|
|
516
|
+
return originalType;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Fallback: filter out metadata members
|
|
522
|
+
const nonDirectiveMembers: ts.Type[] = [];
|
|
523
|
+
for (const member of type.types) {
|
|
524
|
+
const metaProp = getMetaProperty(member);
|
|
525
|
+
const originalTypeProp = member.getProperty(ORIGINAL_TYPE_PROPERTY);
|
|
526
|
+
if (!metaProp && !originalTypeProp) {
|
|
527
|
+
nonDirectiveMembers.push(member);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
if (nonDirectiveMembers.length === 1 && nonDirectiveMembers[0]) {
|
|
531
|
+
return nonDirectiveMembers[0];
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// Handle union types: (T & Meta) | null
|
|
536
|
+
// We extract the base type from the non-null member and return it.
|
|
537
|
+
// Nullability is handled separately in the type-extractor.
|
|
538
|
+
if (type.isUnion()) {
|
|
539
|
+
for (const member of type.types) {
|
|
540
|
+
// Skip null/undefined members
|
|
541
|
+
if (
|
|
542
|
+
member.flags & ts.TypeFlags.Null ||
|
|
543
|
+
member.flags & ts.TypeFlags.Undefined
|
|
544
|
+
) {
|
|
545
|
+
continue;
|
|
546
|
+
}
|
|
547
|
+
// Recursively unwrap if this member has metadata
|
|
548
|
+
const unwrapped = unwrapDirectiveType(member, checker);
|
|
549
|
+
if (unwrapped !== member) {
|
|
550
|
+
return unwrapped;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
return type;
|
|
556
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts an enum name from any naming convention to UPPER_SNAKE_CASE.
|
|
3
|
+
*
|
|
4
|
+
* Supports PascalCase, camelCase, UPPER_SNAKE_CASE, and single word inputs.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* toUpperSnakeCase("UserStatus") // => "USER_STATUS"
|
|
8
|
+
* toUpperSnakeCase("userStatus") // => "USER_STATUS"
|
|
9
|
+
* toUpperSnakeCase("USER_STATUS") // => "USER_STATUS"
|
|
10
|
+
* toUpperSnakeCase("Status") // => "STATUS"
|
|
11
|
+
*/
|
|
12
|
+
export function toUpperSnakeCase(name: string): string {
|
|
13
|
+
return name
|
|
14
|
+
.replace(/([a-z])([A-Z])/g, "$1_$2")
|
|
15
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2")
|
|
16
|
+
.toUpperCase();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Builds the prefix candidate string for enum prefix stripping.
|
|
21
|
+
*
|
|
22
|
+
* Converts the enum name to UPPER_SNAKE_CASE and appends "_" to create
|
|
23
|
+
* the prefix that will be checked against all enum values.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* buildEnumPrefixCandidate("UserStatus") // => "USER_STATUS_"
|
|
27
|
+
* buildEnumPrefixCandidate("userStatus") // => "USER_STATUS_"
|
|
28
|
+
* buildEnumPrefixCandidate("USER_STATUS") // => "USER_STATUS_"
|
|
29
|
+
* buildEnumPrefixCandidate("Status") // => "STATUS_"
|
|
30
|
+
*/
|
|
31
|
+
export function buildEnumPrefixCandidate(enumName: string): string {
|
|
32
|
+
return `${toUpperSnakeCase(enumName)}_`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface DetectEnumPrefixParams {
|
|
36
|
+
readonly enumName: string;
|
|
37
|
+
readonly memberValues: ReadonlyArray<string>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface DetectEnumPrefixResult {
|
|
41
|
+
readonly shouldStrip: boolean;
|
|
42
|
+
readonly prefix: string | null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Detects whether an enum is a candidate for prefix stripping.
|
|
47
|
+
*
|
|
48
|
+
* Conditions for stripping:
|
|
49
|
+
* 1. All memberValues must start with `${toUpperSnakeCase(enumName)}_`
|
|
50
|
+
* 2. After removing the prefix, the remaining string must be non-empty
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* detectEnumPrefix({
|
|
54
|
+
* enumName: "UserStatus",
|
|
55
|
+
* memberValues: ["USER_STATUS_ACTIVE", "USER_STATUS_INACTIVE"]
|
|
56
|
+
* })
|
|
57
|
+
* // => { shouldStrip: true, prefix: "USER_STATUS_" }
|
|
58
|
+
*
|
|
59
|
+
* detectEnumPrefix({
|
|
60
|
+
* enumName: "UserStatus",
|
|
61
|
+
* memberValues: ["ACTIVE", "INACTIVE"]
|
|
62
|
+
* })
|
|
63
|
+
* // => { shouldStrip: false, prefix: null }
|
|
64
|
+
*/
|
|
65
|
+
export function detectEnumPrefix(
|
|
66
|
+
params: DetectEnumPrefixParams,
|
|
67
|
+
): DetectEnumPrefixResult {
|
|
68
|
+
const { enumName, memberValues } = params;
|
|
69
|
+
|
|
70
|
+
if (memberValues.length === 0) {
|
|
71
|
+
return { shouldStrip: false, prefix: null };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const prefixCandidate = buildEnumPrefixCandidate(enumName);
|
|
75
|
+
|
|
76
|
+
for (const value of memberValues) {
|
|
77
|
+
if (!value.startsWith(prefixCandidate)) {
|
|
78
|
+
return { shouldStrip: false, prefix: null };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const stripped = value.slice(prefixCandidate.length);
|
|
82
|
+
if (stripped === "") {
|
|
83
|
+
return { shouldStrip: false, prefix: null };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return { shouldStrip: true, prefix: prefixCandidate };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Removes the detected prefix from an enum value.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* stripEnumPrefix("USER_STATUS_ACTIVE", "USER_STATUS_")
|
|
95
|
+
* // => "ACTIVE"
|
|
96
|
+
*/
|
|
97
|
+
export function stripEnumPrefix(value: string, prefix: string): string {
|
|
98
|
+
return value.slice(prefix.length);
|
|
99
|
+
}
|