@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,170 @@
|
|
|
1
|
+
import { readdir, stat } from "node:fs/promises";
|
|
2
|
+
import { join, matchesGlob, relative, resolve } from "node:path";
|
|
3
|
+
import type { Diagnostic } from "../type-extractor/types/index.js";
|
|
4
|
+
import { toPosixPath } from "./path-utils.js";
|
|
5
|
+
|
|
6
|
+
export interface ScanResult {
|
|
7
|
+
readonly files: ReadonlyArray<string>;
|
|
8
|
+
readonly errors: ReadonlyArray<Diagnostic>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ScanOptions {
|
|
12
|
+
/**
|
|
13
|
+
* Glob patterns to exclude files.
|
|
14
|
+
* Patterns are matched against file paths relative to the scan directory.
|
|
15
|
+
*/
|
|
16
|
+
readonly excludeGlobs?: ReadonlyArray<string>;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* File paths to exclude (for generated files).
|
|
20
|
+
* Each path is individually excluded from scanning.
|
|
21
|
+
*/
|
|
22
|
+
readonly excludePaths?: ReadonlyArray<string>;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Simple suffix patterns to exclude (existing behavior).
|
|
26
|
+
* @deprecated Use excludeGlobs instead
|
|
27
|
+
*/
|
|
28
|
+
readonly excludePatterns?: ReadonlyArray<string>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const TS_SOURCE_EXTENSIONS = [".ts", ".cts", ".mts"];
|
|
32
|
+
const TS_DEFINITION_SUFFIXES = [".d.ts", ".d.cts", ".d.mts"];
|
|
33
|
+
|
|
34
|
+
export function isTypeScriptSourceFile(fileName: string): boolean {
|
|
35
|
+
if (TS_DEFINITION_SUFFIXES.some((suffix) => fileName.endsWith(suffix))) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
return TS_SOURCE_EXTENSIONS.some((ext) => fileName.endsWith(ext));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function matchesSuffixPattern(fileName: string, pattern: string): boolean {
|
|
42
|
+
return fileName.endsWith(pattern);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function shouldExcludeBySuffix(
|
|
46
|
+
fileName: string,
|
|
47
|
+
excludePatterns: ReadonlyArray<string>,
|
|
48
|
+
): boolean {
|
|
49
|
+
return excludePatterns.some((pattern) =>
|
|
50
|
+
matchesSuffixPattern(fileName, pattern),
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function shouldExcludeByGlobs(
|
|
55
|
+
filePath: string,
|
|
56
|
+
rootDir: string,
|
|
57
|
+
excludeGlobs: ReadonlyArray<string>,
|
|
58
|
+
): boolean {
|
|
59
|
+
if (excludeGlobs.length === 0) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const relativePath = toPosixPath(relative(rootDir, filePath));
|
|
64
|
+
return excludeGlobs.some((pattern) => matchesGlob(relativePath, pattern));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function shouldExcludeByPaths(
|
|
68
|
+
filePath: string,
|
|
69
|
+
excludePaths: ReadonlyArray<string>,
|
|
70
|
+
): boolean {
|
|
71
|
+
const normalizedFilePath = toPosixPath(filePath);
|
|
72
|
+
return excludePaths.some(
|
|
73
|
+
(excludePath) => normalizedFilePath === toPosixPath(excludePath),
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
interface CollectFilesContext {
|
|
78
|
+
readonly rootDir: string;
|
|
79
|
+
readonly excludePatterns: ReadonlyArray<string>;
|
|
80
|
+
readonly excludeGlobs: ReadonlyArray<string>;
|
|
81
|
+
readonly excludePaths: ReadonlyArray<string>;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function collectFiles(
|
|
85
|
+
directory: string,
|
|
86
|
+
files: string[],
|
|
87
|
+
context: CollectFilesContext,
|
|
88
|
+
): Promise<void> {
|
|
89
|
+
const entries = await readdir(directory, { withFileTypes: true });
|
|
90
|
+
|
|
91
|
+
for (const entry of entries) {
|
|
92
|
+
const fullPath = join(directory, entry.name);
|
|
93
|
+
|
|
94
|
+
if (entry.isDirectory()) {
|
|
95
|
+
if (entry.name === "node_modules") {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
await collectFiles(fullPath, files, context);
|
|
99
|
+
} else if (entry.isFile()) {
|
|
100
|
+
if (!isTypeScriptSourceFile(entry.name)) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (shouldExcludeBySuffix(entry.name, context.excludePatterns)) {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (
|
|
107
|
+
shouldExcludeByGlobs(fullPath, context.rootDir, context.excludeGlobs)
|
|
108
|
+
) {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
if (shouldExcludeByPaths(fullPath, context.excludePaths)) {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
files.push(toPosixPath(fullPath));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export async function scanDirectory(
|
|
120
|
+
directory: string,
|
|
121
|
+
options: ScanOptions = {},
|
|
122
|
+
): Promise<ScanResult> {
|
|
123
|
+
const absolutePath = resolve(directory);
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
const stats = await stat(absolutePath);
|
|
127
|
+
if (!stats.isDirectory()) {
|
|
128
|
+
return {
|
|
129
|
+
files: [],
|
|
130
|
+
errors: [
|
|
131
|
+
{
|
|
132
|
+
code: "DIRECTORY_NOT_FOUND",
|
|
133
|
+
message: `Path is not a directory: ${absolutePath}`,
|
|
134
|
+
severity: "error",
|
|
135
|
+
location: null,
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
} catch {
|
|
141
|
+
return {
|
|
142
|
+
files: [],
|
|
143
|
+
errors: [
|
|
144
|
+
{
|
|
145
|
+
code: "DIRECTORY_NOT_FOUND",
|
|
146
|
+
message: `Directory not found: ${absolutePath}`,
|
|
147
|
+
severity: "error",
|
|
148
|
+
location: null,
|
|
149
|
+
},
|
|
150
|
+
],
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const context: CollectFilesContext = {
|
|
155
|
+
rootDir: absolutePath,
|
|
156
|
+
excludePatterns: options.excludePatterns ?? [],
|
|
157
|
+
excludeGlobs: options.excludeGlobs ?? [],
|
|
158
|
+
excludePaths: options.excludePaths ?? [],
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const files: string[] = [];
|
|
162
|
+
await collectFiles(absolutePath, files, context);
|
|
163
|
+
|
|
164
|
+
files.sort();
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
files,
|
|
168
|
+
errors: [],
|
|
169
|
+
};
|
|
170
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IgnoreFields metadata detector.
|
|
3
|
+
*
|
|
4
|
+
* This module provides functions to detect ignoreFields metadata embedded
|
|
5
|
+
* in TypeScript intersection types using the $gqlkitTypeMeta property.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import ts from "typescript";
|
|
9
|
+
import { METADATA_PROPERTIES } from "./constants.js";
|
|
10
|
+
import { getActualMetadataType } from "./metadata-detector.js";
|
|
11
|
+
|
|
12
|
+
const TYPE_META_PROPERTY = METADATA_PROPERTIES.TYPE_META;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Parameters for detectIgnoreFieldsMetadata function.
|
|
16
|
+
*/
|
|
17
|
+
export interface DetectIgnoreFieldsParams {
|
|
18
|
+
readonly type: ts.Type;
|
|
19
|
+
readonly checker: ts.TypeChecker;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Extracts ignoreFields from a type's metadata.
|
|
24
|
+
* Returns null if the type doesn't have $gqlkitTypeMeta or ignoreFields is not specified.
|
|
25
|
+
*/
|
|
26
|
+
function extractIgnoreFieldsFromType(
|
|
27
|
+
type: ts.Type,
|
|
28
|
+
checker: ts.TypeChecker,
|
|
29
|
+
): ReadonlySet<string> | null {
|
|
30
|
+
const metaProp = type.getProperty(TYPE_META_PROPERTY);
|
|
31
|
+
if (!metaProp) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const rawMetadataType = checker.getTypeOfSymbol(metaProp);
|
|
36
|
+
const metadataType = getActualMetadataType(rawMetadataType);
|
|
37
|
+
if (!metadataType) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const ignoreFieldsProp = metadataType.getProperty("ignoreFields");
|
|
42
|
+
if (!ignoreFieldsProp) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const rawIgnoreFieldsType = checker.getTypeOfSymbol(ignoreFieldsProp);
|
|
47
|
+
const ignoreFieldsType = getActualMetadataType(rawIgnoreFieldsType);
|
|
48
|
+
if (!ignoreFieldsType) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return extractStringLiteralUnion(ignoreFieldsType);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Extracts string literals from a type (single literal or union of literals).
|
|
57
|
+
*/
|
|
58
|
+
function extractStringLiteralUnion(type: ts.Type): ReadonlySet<string> | null {
|
|
59
|
+
if (type.flags & ts.TypeFlags.StringLiteral) {
|
|
60
|
+
const value = (type as ts.StringLiteralType).value;
|
|
61
|
+
return new Set([value]);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (type.isUnion()) {
|
|
65
|
+
const values = new Set<string>();
|
|
66
|
+
for (const member of type.types) {
|
|
67
|
+
if (member.flags & ts.TypeFlags.StringLiteral) {
|
|
68
|
+
values.add((member as ts.StringLiteralType).value);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (values.size > 0) {
|
|
72
|
+
return values;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Detects ignoreFields metadata from a TypeScript type.
|
|
81
|
+
*
|
|
82
|
+
* This function analyzes TypeScript types to detect ignoreFields metadata
|
|
83
|
+
* from the $gqlkitTypeMeta property. It extracts string literal or string
|
|
84
|
+
* literal union types and returns them as a Set.
|
|
85
|
+
*
|
|
86
|
+
* @param params - The detection parameters containing type and checker
|
|
87
|
+
* @returns The ignoreFields set or null if not specified
|
|
88
|
+
*/
|
|
89
|
+
export function detectIgnoreFieldsMetadata(
|
|
90
|
+
params: DetectIgnoreFieldsParams,
|
|
91
|
+
): ReadonlySet<string> | null {
|
|
92
|
+
const { type, checker } = params;
|
|
93
|
+
|
|
94
|
+
const result = extractIgnoreFieldsFromType(type, checker);
|
|
95
|
+
if (result) {
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (type.isIntersection()) {
|
|
100
|
+
for (const member of type.types) {
|
|
101
|
+
const memberResult = extractIgnoreFieldsFromType(member, checker);
|
|
102
|
+
if (memberResult) {
|
|
103
|
+
return memberResult;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IgnoreFields validator.
|
|
3
|
+
*
|
|
4
|
+
* This module provides validation functions for ignoreFields metadata,
|
|
5
|
+
* checking that specified field names exist in the type and that not
|
|
6
|
+
* all fields are excluded.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type {
|
|
10
|
+
Diagnostic,
|
|
11
|
+
SourceLocation,
|
|
12
|
+
} from "../type-extractor/types/diagnostics.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Parameters for validateIgnoreFields function.
|
|
16
|
+
*/
|
|
17
|
+
export interface ValidateIgnoreFieldsParams {
|
|
18
|
+
readonly typeName: string;
|
|
19
|
+
readonly ignoreFields: ReadonlySet<string>;
|
|
20
|
+
readonly allFieldNames: ReadonlySet<string>;
|
|
21
|
+
readonly sourceLocation: SourceLocation;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Validates ignoreFields metadata.
|
|
26
|
+
*
|
|
27
|
+
* This function checks:
|
|
28
|
+
* 1. All field names in ignoreFields exist in the type
|
|
29
|
+
* 2. Not all fields are excluded (at least one field must remain)
|
|
30
|
+
*
|
|
31
|
+
* @param params - The validation parameters
|
|
32
|
+
* @returns Array of diagnostics (empty if valid)
|
|
33
|
+
*/
|
|
34
|
+
export function validateIgnoreFields(
|
|
35
|
+
params: ValidateIgnoreFieldsParams,
|
|
36
|
+
): ReadonlyArray<Diagnostic> {
|
|
37
|
+
const { typeName, ignoreFields, allFieldNames, sourceLocation } = params;
|
|
38
|
+
const diagnostics: Diagnostic[] = [];
|
|
39
|
+
|
|
40
|
+
for (const fieldName of ignoreFields) {
|
|
41
|
+
if (!allFieldNames.has(fieldName)) {
|
|
42
|
+
const availableFields = [...allFieldNames].sort().join(", ");
|
|
43
|
+
diagnostics.push({
|
|
44
|
+
code: "IGNORE_FIELD_NOT_FOUND",
|
|
45
|
+
message: `Type '${typeName}': ignoreFields contains unknown field '${fieldName}'. Available fields: ${availableFields}`,
|
|
46
|
+
severity: "error",
|
|
47
|
+
location: sourceLocation,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const remainingFieldCount = [...allFieldNames].filter(
|
|
53
|
+
(f) => !ignoreFields.has(f),
|
|
54
|
+
).length;
|
|
55
|
+
|
|
56
|
+
if (remainingFieldCount === 0 && allFieldNames.size > 0) {
|
|
57
|
+
diagnostics.push({
|
|
58
|
+
code: "IGNORE_ALL_FIELDS",
|
|
59
|
+
message: `Type '${typeName}': ignoreFields excludes all fields. At least one field must remain.`,
|
|
60
|
+
severity: "error",
|
|
61
|
+
location: sourceLocation,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return diagnostics;
|
|
66
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export type {
|
|
2
|
+
DefaultValueDetectionError,
|
|
3
|
+
DefaultValueDetectionErrorCode,
|
|
4
|
+
DefaultValueDetectionResult,
|
|
5
|
+
} from "./default-value-detector.js";
|
|
6
|
+
export { collectDiagnostics, deduplicateDiagnostics } from "./diagnostics.js";
|
|
7
|
+
export {
|
|
8
|
+
type DirectiveArgumentDefinition,
|
|
9
|
+
type DirectiveDefinitionError,
|
|
10
|
+
type DirectiveDefinitionErrorCode,
|
|
11
|
+
type DirectiveDefinitionExtractionResult,
|
|
12
|
+
type DirectiveDefinitionInfo,
|
|
13
|
+
type DirectiveLocation,
|
|
14
|
+
extractDirectiveDefinitions,
|
|
15
|
+
} from "./directive-definition-extractor.js";
|
|
16
|
+
export type {
|
|
17
|
+
DirectiveArgument,
|
|
18
|
+
DirectiveArgumentValue,
|
|
19
|
+
DirectiveDetectionError,
|
|
20
|
+
DirectiveDetectionErrorCode,
|
|
21
|
+
DirectiveDetectionResult,
|
|
22
|
+
DirectiveInfo,
|
|
23
|
+
} from "./directive-detector.js";
|
|
24
|
+
export {
|
|
25
|
+
type ScanOptions,
|
|
26
|
+
type ScanResult,
|
|
27
|
+
scanDirectory,
|
|
28
|
+
} from "./file-scanner.js";
|
|
29
|
+
export type { DetectIgnoreFieldsParams } from "./ignore-fields-detector.js";
|
|
30
|
+
export type { ValidateIgnoreFieldsParams } from "./ignore-fields-validator.js";
|
|
31
|
+
export type { TypeConverter } from "./inline-object-extractor.js";
|
|
32
|
+
export { toPosixPath } from "./path-utils.js";
|
|
33
|
+
export type { SourceLocation } from "./source-location.js";
|
|
34
|
+
export { convertTsTypeToGraphQLType } from "./type-converter.js";
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type ts from "typescript";
|
|
2
|
+
import type {
|
|
3
|
+
InlineObjectPropertyDef,
|
|
4
|
+
TSTypeReference,
|
|
5
|
+
} from "../type-extractor/types/index.js";
|
|
6
|
+
import { detectDefaultValueMetadata } from "./default-value-detector.js";
|
|
7
|
+
import {
|
|
8
|
+
type DirectiveArgumentValue,
|
|
9
|
+
type DirectiveInfo,
|
|
10
|
+
detectDirectiveMetadata,
|
|
11
|
+
hasDirectiveMetadata,
|
|
12
|
+
unwrapDirectiveType,
|
|
13
|
+
} from "./directive-detector.js";
|
|
14
|
+
import { getSourceLocationFromNode } from "./source-location.js";
|
|
15
|
+
import { extractTsDocFromSymbol } from "./tsdoc-parser.js";
|
|
16
|
+
import {
|
|
17
|
+
extractPropertySymbols,
|
|
18
|
+
hasUndefinedInType,
|
|
19
|
+
isNullableUnion,
|
|
20
|
+
} from "./typescript-utils.js";
|
|
21
|
+
|
|
22
|
+
export type TypeConverter = (
|
|
23
|
+
type: ts.Type,
|
|
24
|
+
checker: ts.TypeChecker,
|
|
25
|
+
) => TSTypeReference;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Extracts inline object properties from a TypeScript type.
|
|
29
|
+
*
|
|
30
|
+
* @param type - The TypeScript type to extract properties from
|
|
31
|
+
* @param checker - The TypeScript type checker
|
|
32
|
+
* @param convertType - A function to convert TypeScript types to TSTypeReference
|
|
33
|
+
* @returns An array of inline object property definitions
|
|
34
|
+
*/
|
|
35
|
+
export function extractInlineObjectProperties(
|
|
36
|
+
type: ts.Type,
|
|
37
|
+
checker: ts.TypeChecker,
|
|
38
|
+
convertType: TypeConverter,
|
|
39
|
+
): InlineObjectPropertyDef[] {
|
|
40
|
+
const properties: InlineObjectPropertyDef[] = [];
|
|
41
|
+
const typeProperties = extractPropertySymbols(type, checker);
|
|
42
|
+
|
|
43
|
+
for (const prop of typeProperties) {
|
|
44
|
+
const propName = prop.getName();
|
|
45
|
+
if (propName.startsWith(" $")) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const propType = checker.getTypeOfSymbol(prop);
|
|
50
|
+
const declarations = prop.getDeclarations();
|
|
51
|
+
const declaration = declarations?.[0];
|
|
52
|
+
|
|
53
|
+
const optional = hasUndefinedInType(propType);
|
|
54
|
+
|
|
55
|
+
const tsdocInfo = extractTsDocFromSymbol(prop, checker);
|
|
56
|
+
|
|
57
|
+
let actualPropType = propType;
|
|
58
|
+
let directives: ReadonlyArray<DirectiveInfo> | null = null;
|
|
59
|
+
let directiveNullable = false;
|
|
60
|
+
let defaultValue: DirectiveArgumentValue | null = null;
|
|
61
|
+
|
|
62
|
+
if (hasDirectiveMetadata(propType)) {
|
|
63
|
+
const directiveResult = detectDirectiveMetadata(propType, checker);
|
|
64
|
+
if (directiveResult.directives.length > 0) {
|
|
65
|
+
directives = directiveResult.directives;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const defaultValueResult = detectDefaultValueMetadata(propType, checker);
|
|
69
|
+
if (defaultValueResult.defaultValue) {
|
|
70
|
+
defaultValue = defaultValueResult.defaultValue;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (isNullableUnion(propType)) {
|
|
74
|
+
directiveNullable = true;
|
|
75
|
+
}
|
|
76
|
+
actualPropType = unwrapDirectiveType(propType, checker);
|
|
77
|
+
|
|
78
|
+
if (!directiveNullable && isNullableUnion(actualPropType)) {
|
|
79
|
+
directiveNullable = true;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const tsType = convertType(actualPropType, checker);
|
|
84
|
+
const finalTsType =
|
|
85
|
+
directiveNullable && !tsType.nullable
|
|
86
|
+
? { ...tsType, nullable: true }
|
|
87
|
+
: tsType;
|
|
88
|
+
|
|
89
|
+
properties.push({
|
|
90
|
+
name: propName,
|
|
91
|
+
tsType: finalTsType,
|
|
92
|
+
optional,
|
|
93
|
+
description: tsdocInfo.description ?? null,
|
|
94
|
+
deprecated: tsdocInfo.deprecated ?? null,
|
|
95
|
+
directives,
|
|
96
|
+
defaultValue,
|
|
97
|
+
sourceLocation: getSourceLocationFromNode(declaration),
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return properties;
|
|
102
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Checks if a TypeScript type is an inline object type (anonymous type literal).
|
|
5
|
+
* Returns true for types like `{ foo: string; bar: number }` but not for named types.
|
|
6
|
+
*/
|
|
7
|
+
export function isInlineObjectType(type: ts.Type): boolean {
|
|
8
|
+
if (type.aliasSymbol) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
if (!type.symbol) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
const symbolName = type.symbol.getName();
|
|
15
|
+
if (symbolName !== "__type") {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
if (!(type.flags & ts.TypeFlags.Object)) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
const objectType = type as ts.ObjectType;
|
|
22
|
+
return (objectType.objectFlags & ts.ObjectFlags.Anonymous) !== 0;
|
|
23
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface metadata detector.
|
|
3
|
+
*
|
|
4
|
+
* This module provides functions to detect interface metadata embedded
|
|
5
|
+
* in TypeScript intersection types using the $gqlkitInterfaceMeta property,
|
|
6
|
+
* and to extract implements declarations from types using $gqlkitTypeMeta.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import ts from "typescript";
|
|
10
|
+
import { METADATA_PROPERTIES } from "./constants.js";
|
|
11
|
+
|
|
12
|
+
const INTERFACE_META_PROPERTY = METADATA_PROPERTIES.INTERFACE_META;
|
|
13
|
+
const TYPE_META_PROPERTY = METADATA_PROPERTIES.TYPE_META;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Checks if a type alias declaration uses GqlInterface.
|
|
17
|
+
* Detects by checking for the $gqlkitInterfaceMeta property in the resolved type.
|
|
18
|
+
*/
|
|
19
|
+
export function isDefineInterfaceTypeAlias(
|
|
20
|
+
node: ts.TypeAliasDeclaration,
|
|
21
|
+
checker: ts.TypeChecker,
|
|
22
|
+
): boolean {
|
|
23
|
+
const symbol = checker.getSymbolAtLocation(node.name);
|
|
24
|
+
if (!symbol) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const type = checker.getDeclaredTypeOfSymbol(symbol);
|
|
29
|
+
return hasInterfaceMetadata(type);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Checks if a type has the $gqlkitInterfaceMeta property.
|
|
34
|
+
*/
|
|
35
|
+
function hasInterfaceMetadata(type: ts.Type): boolean {
|
|
36
|
+
const metaProp = type.getProperty(INTERFACE_META_PROPERTY);
|
|
37
|
+
if (metaProp) {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (type.isIntersection()) {
|
|
42
|
+
for (const member of type.types) {
|
|
43
|
+
const prop = member.getProperty(INTERFACE_META_PROPERTY);
|
|
44
|
+
if (prop) {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Checks if a type has the $gqlkitTypeMeta property (GqlObject).
|
|
55
|
+
*/
|
|
56
|
+
function hasTypeMetadata(type: ts.Type): boolean {
|
|
57
|
+
const metaProp = type.getProperty(TYPE_META_PROPERTY);
|
|
58
|
+
if (metaProp) {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (type.isIntersection()) {
|
|
63
|
+
for (const member of type.types) {
|
|
64
|
+
const prop = member.getProperty(TYPE_META_PROPERTY);
|
|
65
|
+
if (prop) {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Extracts implements from GqlInterface type alias.
|
|
76
|
+
*/
|
|
77
|
+
export function extractImplementsFromDefineInterface(
|
|
78
|
+
node: ts.TypeAliasDeclaration,
|
|
79
|
+
sourceFile: ts.SourceFile,
|
|
80
|
+
checker: ts.TypeChecker,
|
|
81
|
+
): ReadonlyArray<string> {
|
|
82
|
+
const typeNode = node.type;
|
|
83
|
+
if (!ts.isTypeReferenceNode(typeNode)) {
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const typeArgs = typeNode.typeArguments;
|
|
88
|
+
if (!typeArgs || typeArgs.length < 2) {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const metaArg = typeArgs[1];
|
|
93
|
+
if (!metaArg || !ts.isTypeLiteralNode(metaArg)) {
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return extractImplementsFromTypeLiteral(metaArg, sourceFile, checker);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Extracts implements from GqlObject type alias.
|
|
102
|
+
* Detects GqlObject by checking for the $gqlkitTypeMeta property in the resolved type.
|
|
103
|
+
*/
|
|
104
|
+
export function extractImplementsFromGqlTypeDef(
|
|
105
|
+
node: ts.TypeAliasDeclaration,
|
|
106
|
+
sourceFile: ts.SourceFile,
|
|
107
|
+
checker: ts.TypeChecker,
|
|
108
|
+
): ReadonlyArray<string> {
|
|
109
|
+
const symbol = checker.getSymbolAtLocation(node.name);
|
|
110
|
+
if (!symbol) {
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const type = checker.getDeclaredTypeOfSymbol(symbol);
|
|
115
|
+
if (!hasTypeMetadata(type)) {
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const typeNode = node.type;
|
|
120
|
+
if (!ts.isTypeReferenceNode(typeNode)) {
|
|
121
|
+
return [];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const typeArgs = typeNode.typeArguments;
|
|
125
|
+
if (!typeArgs || typeArgs.length < 2) {
|
|
126
|
+
return [];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const metaArg = typeArgs[1];
|
|
130
|
+
if (!metaArg || !ts.isTypeLiteralNode(metaArg)) {
|
|
131
|
+
return [];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return extractImplementsFromTypeLiteral(metaArg, sourceFile, checker);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function extractImplementsFromTypeLiteral(
|
|
138
|
+
typeLiteral: ts.TypeLiteralNode,
|
|
139
|
+
sourceFile: ts.SourceFile,
|
|
140
|
+
_checker: ts.TypeChecker,
|
|
141
|
+
): ReadonlyArray<string> {
|
|
142
|
+
for (const member of typeLiteral.members) {
|
|
143
|
+
if (ts.isPropertySignature(member) && member.name) {
|
|
144
|
+
const propName = member.name.getText(sourceFile);
|
|
145
|
+
if (propName === "implements" && member.type) {
|
|
146
|
+
return extractInterfaceNamesFromTupleNode(member.type, sourceFile);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return [];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function extractInterfaceNamesFromTupleNode(
|
|
154
|
+
typeNode: ts.TypeNode,
|
|
155
|
+
sourceFile: ts.SourceFile,
|
|
156
|
+
): ReadonlyArray<string> {
|
|
157
|
+
if (ts.isTupleTypeNode(typeNode)) {
|
|
158
|
+
return typeNode.elements
|
|
159
|
+
.map((elem) => {
|
|
160
|
+
if (ts.isTypeReferenceNode(elem)) {
|
|
161
|
+
return elem.typeName.getText(sourceFile);
|
|
162
|
+
}
|
|
163
|
+
return null;
|
|
164
|
+
})
|
|
165
|
+
.filter((name): name is string => name !== null);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (
|
|
169
|
+
ts.isArrayTypeNode(typeNode) &&
|
|
170
|
+
ts.isTypeReferenceNode(typeNode.elementType)
|
|
171
|
+
) {
|
|
172
|
+
return [typeNode.elementType.typeName.getText(sourceFile)];
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return [];
|
|
176
|
+
}
|