@gqlkit-ts/cli 0.3.0 → 0.4.1
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/README.md +143 -0
- package/dist/auto-type-generator/auto-type-generator.d.ts.map +1 -1
- package/dist/auto-type-generator/auto-type-generator.js +16 -13
- package/dist/auto-type-generator/auto-type-generator.js.map +1 -1
- package/dist/commands/docs.d.ts.map +1 -1
- package/dist/commands/docs.js +33 -13
- package/dist/commands/docs.js.map +1 -1
- package/dist/config/types.d.ts +13 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config-loader/loader.d.ts +3 -0
- package/dist/config-loader/loader.d.ts.map +1 -1
- package/dist/config-loader/loader.js +1 -0
- package/dist/config-loader/loader.js.map +1 -1
- package/dist/config-loader/validator.d.ts.map +1 -1
- package/dist/config-loader/validator.js +23 -0
- package/dist/config-loader/validator.js.map +1 -1
- package/dist/gen-orchestrator/orchestrator.d.ts.map +1 -1
- package/dist/gen-orchestrator/orchestrator.js +19 -6
- package/dist/gen-orchestrator/orchestrator.js.map +1 -1
- package/dist/resolver-extractor/extractor/define-api-extractor.js +4 -4
- package/dist/resolver-extractor/extractor/define-api-extractor.js.map +1 -1
- package/dist/schema-generator/builder/ast-builder.d.ts +2 -2
- package/dist/schema-generator/builder/ast-builder.d.ts.map +1 -1
- package/dist/schema-generator/builder/ast-builder.js +12 -34
- package/dist/schema-generator/builder/ast-builder.js.map +1 -1
- package/dist/schema-generator/emitter/code-emitter.d.ts +3 -1
- package/dist/schema-generator/emitter/code-emitter.d.ts.map +1 -1
- package/dist/schema-generator/emitter/code-emitter.js +22 -12
- package/dist/schema-generator/emitter/code-emitter.js.map +1 -1
- package/dist/schema-generator/emitter/sdl-emitter.d.ts +0 -4
- package/dist/schema-generator/emitter/sdl-emitter.d.ts.map +1 -1
- package/dist/schema-generator/emitter/sdl-emitter.js +0 -4
- package/dist/schema-generator/emitter/sdl-emitter.js.map +1 -1
- package/dist/schema-generator/generate-schema.d.ts +2 -0
- package/dist/schema-generator/generate-schema.d.ts.map +1 -1
- package/dist/schema-generator/generate-schema.js +13 -4
- package/dist/schema-generator/generate-schema.js.map +1 -1
- package/dist/schema-generator/integrator/result-integrator.d.ts +10 -12
- package/dist/schema-generator/integrator/result-integrator.d.ts.map +1 -1
- package/dist/schema-generator/integrator/result-integrator.js +18 -55
- package/dist/schema-generator/integrator/result-integrator.js.map +1 -1
- package/dist/shared/branded-type-detector.d.ts +43 -0
- package/dist/shared/branded-type-detector.d.ts.map +1 -0
- package/dist/shared/branded-type-detector.js +146 -0
- package/dist/shared/branded-type-detector.js.map +1 -0
- package/dist/shared/string-utils.d.ts +2 -0
- package/dist/shared/string-utils.d.ts.map +1 -0
- package/dist/shared/string-utils.js +8 -0
- package/dist/shared/string-utils.js.map +1 -0
- package/dist/type-extractor/converter/field-eligibility.d.ts +8 -6
- package/dist/type-extractor/converter/field-eligibility.d.ts.map +1 -1
- package/dist/type-extractor/converter/field-eligibility.js +7 -28
- package/dist/type-extractor/converter/field-eligibility.js.map +1 -1
- package/dist/type-extractor/converter/graphql-converter.d.ts.map +1 -1
- package/dist/type-extractor/converter/graphql-converter.js +6 -11
- package/dist/type-extractor/converter/graphql-converter.js.map +1 -1
- package/dist/type-extractor/extractor/field-type-resolver.d.ts.map +1 -1
- package/dist/type-extractor/extractor/field-type-resolver.js +39 -4
- package/dist/type-extractor/extractor/field-type-resolver.js.map +1 -1
- 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/validator/type-validator.d.ts +1 -1
- package/dist/type-extractor/validator/type-validator.d.ts.map +1 -1
- package/dist/type-extractor/validator/type-validator.js +2 -10
- package/dist/type-extractor/validator/type-validator.js.map +1 -1
- package/docs/configuration.md +9 -0
- package/package.json +3 -3
- package/src/auto-type-generator/auto-type-generator.ts +23 -26
- package/src/commands/docs.ts +50 -24
- package/src/config/types.ts +15 -0
- package/src/config-loader/loader.ts +4 -0
- package/src/config-loader/validator.ts +33 -0
- package/src/gen-orchestrator/orchestrator.ts +30 -11
- package/src/resolver-extractor/extractor/define-api-extractor.ts +5 -5
- package/src/schema-generator/builder/ast-builder.ts +52 -81
- package/src/schema-generator/emitter/code-emitter.ts +48 -11
- package/src/schema-generator/emitter/sdl-emitter.ts +0 -4
- package/src/schema-generator/generate-schema.ts +13 -15
- package/src/schema-generator/integrator/result-integrator.ts +37 -78
- package/src/shared/branded-type-detector.ts +182 -0
- package/src/shared/string-utils.ts +7 -0
- package/src/type-extractor/converter/field-eligibility.ts +13 -29
- package/src/type-extractor/converter/graphql-converter.ts +6 -16
- package/src/type-extractor/extractor/field-type-resolver.ts +49 -4
- package/src/type-extractor/types/diagnostics.ts +1 -0
- package/src/type-extractor/validator/type-validator.ts +2 -15
package/docs/configuration.md
CHANGED
|
@@ -40,6 +40,8 @@ export default defineConfig({
|
|
|
40
40
|
schemaPath: "src/gqlkit/__generated__/schema.graphql",
|
|
41
41
|
// Set to null to disable output:
|
|
42
42
|
// schemaPath: null,
|
|
43
|
+
// Import extension in generated files (default: "js")
|
|
44
|
+
// importExtension: "none", // for bundlers
|
|
43
45
|
},
|
|
44
46
|
|
|
45
47
|
// Hooks
|
|
@@ -89,9 +91,16 @@ export default defineConfig({
|
|
|
89
91
|
| `typeDefsPath` | `string` \| `null` | `"src/gqlkit/__generated__/typeDefs.ts"` | Path for the TypeDefs output |
|
|
90
92
|
| `resolversPath` | `string` \| `null` | `"src/gqlkit/__generated__/resolvers.ts"` | Path for the resolvers output |
|
|
91
93
|
| `schemaPath` | `string` \| `null` | `"src/gqlkit/__generated__/schema.graphql"` | Path for the SDL output |
|
|
94
|
+
| `importExtension` | `"js"` \| `"none"` \| `"ts"` | `"js"` | File extension for import statements |
|
|
92
95
|
|
|
93
96
|
Set any path to `null` to disable that output.
|
|
94
97
|
|
|
98
|
+
The `importExtension` option controls file extensions in generated import statements:
|
|
99
|
+
|
|
100
|
+
- `"js"` (default): Converts `.ts` to `.js` (compatible with ESM + Node16)
|
|
101
|
+
- `"none"`: No extension (for bundlers like webpack, vite)
|
|
102
|
+
- `"ts"`: Keeps `.ts` extension (for Deno)
|
|
103
|
+
|
|
95
104
|
## Hooks
|
|
96
105
|
|
|
97
106
|
Execute commands after file generation:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gqlkit-ts/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Just types and functions — write TypeScript, generate GraphQL.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -60,8 +60,8 @@
|
|
|
60
60
|
"devDependencies": {
|
|
61
61
|
"@types/shell-quote": "1.7.5",
|
|
62
62
|
"memfs": "4.56.10",
|
|
63
|
-
"@gqlkit-ts/
|
|
64
|
-
"@gqlkit-ts/
|
|
63
|
+
"@gqlkit-ts/docs": "0.0.1",
|
|
64
|
+
"@gqlkit-ts/runtime": "0.2.0"
|
|
65
65
|
},
|
|
66
66
|
"scripts": {
|
|
67
67
|
"build": "tsc --build && bundle-docs --target ./docs",
|
|
@@ -12,12 +12,10 @@ import {
|
|
|
12
12
|
stripEnumPrefix,
|
|
13
13
|
} from "../shared/enum-prefix-detector.js";
|
|
14
14
|
import { getSourceLocationOrDefault } from "../shared/source-location.js";
|
|
15
|
+
import { toScreamingSnakeCase } from "../shared/string-utils.js";
|
|
15
16
|
import type { DeprecationInfo } from "../shared/tsdoc-parser.js";
|
|
16
17
|
import { convertTsTypeToGraphQLType } from "../shared/type-converter.js";
|
|
17
|
-
import {
|
|
18
|
-
isEligibleAsInputObjectField,
|
|
19
|
-
isEligibleAsObjectField,
|
|
20
|
-
} from "../type-extractor/converter/field-eligibility.js";
|
|
18
|
+
import { isEligibleField } from "../type-extractor/converter/field-eligibility.js";
|
|
21
19
|
import {
|
|
22
20
|
createReferenceType,
|
|
23
21
|
type Diagnostic,
|
|
@@ -259,27 +257,33 @@ function collectInlineObjectsFromType(
|
|
|
259
257
|
const isInput = isInputTypeName(typeInfo.metadata.name);
|
|
260
258
|
|
|
261
259
|
for (const field of typeInfo.fields) {
|
|
262
|
-
collectInlineObjectsFromField(
|
|
260
|
+
collectInlineObjectsFromField({
|
|
263
261
|
field,
|
|
264
|
-
typeInfo.metadata.name,
|
|
265
|
-
[],
|
|
262
|
+
parentTypeName: typeInfo.metadata.name,
|
|
263
|
+
parentPath: [],
|
|
266
264
|
isInput,
|
|
267
|
-
typeInfo.metadata.sourceFile,
|
|
265
|
+
sourceFile: typeInfo.metadata.sourceFile,
|
|
268
266
|
results,
|
|
269
|
-
);
|
|
267
|
+
});
|
|
270
268
|
}
|
|
271
269
|
|
|
272
270
|
return results;
|
|
273
271
|
}
|
|
274
272
|
|
|
273
|
+
interface CollectInlineObjectsFromFieldParams {
|
|
274
|
+
readonly field: FieldDefinition;
|
|
275
|
+
readonly parentTypeName: string;
|
|
276
|
+
readonly parentPath: ReadonlyArray<string>;
|
|
277
|
+
readonly isInput: boolean;
|
|
278
|
+
readonly sourceFile: string;
|
|
279
|
+
readonly results: InlineObjectWithContext[];
|
|
280
|
+
}
|
|
281
|
+
|
|
275
282
|
function collectInlineObjectsFromField(
|
|
276
|
-
|
|
277
|
-
parentTypeName: string,
|
|
278
|
-
parentPath: ReadonlyArray<string>,
|
|
279
|
-
isInput: boolean,
|
|
280
|
-
sourceFile: string,
|
|
281
|
-
results: InlineObjectWithContext[],
|
|
283
|
+
params: CollectInlineObjectsFromFieldParams,
|
|
282
284
|
): void {
|
|
285
|
+
const { field, parentTypeName, parentPath, isInput, sourceFile, results } =
|
|
286
|
+
params;
|
|
283
287
|
const tsType = field.tsType;
|
|
284
288
|
|
|
285
289
|
if (tsType.kind !== "inlineObject" || !tsType.inlineObjectProperties) {
|
|
@@ -481,9 +485,10 @@ function generateAutoType(
|
|
|
481
485
|
const diagnostics: Diagnostic[] = [];
|
|
482
486
|
|
|
483
487
|
for (const prop of inlineObj.properties) {
|
|
484
|
-
const eligibility =
|
|
485
|
-
|
|
486
|
-
:
|
|
488
|
+
const eligibility = isEligibleField({
|
|
489
|
+
fieldName: prop.name,
|
|
490
|
+
kind: isInput ? "input" : "object",
|
|
491
|
+
});
|
|
487
492
|
|
|
488
493
|
if (!eligibility.eligible) {
|
|
489
494
|
diagnostics.push({
|
|
@@ -853,14 +858,6 @@ function buildGeneratedTypeNamesMap(
|
|
|
853
858
|
return map;
|
|
854
859
|
}
|
|
855
860
|
|
|
856
|
-
function toScreamingSnakeCase(value: string): string {
|
|
857
|
-
return value
|
|
858
|
-
.replace(/[-\s]+/g, "_")
|
|
859
|
-
.replace(/([a-z])([A-Z])/g, "$1_$2")
|
|
860
|
-
.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2")
|
|
861
|
-
.toUpperCase();
|
|
862
|
-
}
|
|
863
|
-
|
|
864
861
|
interface ConvertInlineEnumMembersParams {
|
|
865
862
|
readonly members: ReadonlyArray<InlineEnumMemberInfo>;
|
|
866
863
|
readonly enumName: string;
|
package/src/commands/docs.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { access, mkdir, readFile, symlink, writeFile } from "node:fs/promises";
|
|
2
|
-
import { dirname, join, relative } from "node:path";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
2
|
+
import { dirname, join, parse, relative, resolve } from "node:path";
|
|
4
3
|
import { define } from "gunshi";
|
|
5
4
|
|
|
6
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
|
-
const CLI_DOCS_DIR = join(__dirname, "../../docs");
|
|
8
5
|
const SKILL_NAME = "gqlkit-guide";
|
|
9
6
|
|
|
10
7
|
export interface RunDocsCommandOptions {
|
|
@@ -27,6 +24,27 @@ async function exists(path: string): Promise<boolean> {
|
|
|
27
24
|
}
|
|
28
25
|
}
|
|
29
26
|
|
|
27
|
+
async function findNodeModulesDocsPath(
|
|
28
|
+
startDir: string,
|
|
29
|
+
): Promise<string | null> {
|
|
30
|
+
let currentDir = resolve(startDir);
|
|
31
|
+
const root = parse(currentDir).root;
|
|
32
|
+
|
|
33
|
+
while (currentDir !== root) {
|
|
34
|
+
const candidate = join(currentDir, "node_modules/@gqlkit-ts/cli/docs");
|
|
35
|
+
if (await exists(candidate)) {
|
|
36
|
+
return candidate;
|
|
37
|
+
}
|
|
38
|
+
const parent = dirname(currentDir);
|
|
39
|
+
if (parent === currentDir) {
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
currentDir = parent;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
|
|
30
48
|
async function detectClaudeEnvironment(dir: string): Promise<boolean> {
|
|
31
49
|
const claudeMdExists = await exists(join(dir, "CLAUDE.md"));
|
|
32
50
|
const claudeDirExists = await exists(join(dir, ".claude"));
|
|
@@ -124,8 +142,16 @@ async function generateToolFiles(
|
|
|
124
142
|
await writeFile(skillMdPath, generateSkillMd());
|
|
125
143
|
filesWritten.push(skillMdPath);
|
|
126
144
|
|
|
145
|
+
const docsPath = await findNodeModulesDocsPath(skillDir);
|
|
146
|
+
if (docsPath === null) {
|
|
147
|
+
throw new Error(
|
|
148
|
+
`Could not find @gqlkit-ts/cli docs directory under node_modules (starting from ${resolve(skillDir)}). ` +
|
|
149
|
+
"Ensure @gqlkit-ts/cli is installed.",
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
127
153
|
const referencesPath = join(skillDir, "references");
|
|
128
|
-
const relativePath = relative(skillDir,
|
|
154
|
+
const relativePath = relative(skillDir, docsPath);
|
|
129
155
|
await createSymlinkIfNotExists(referencesPath, relativePath);
|
|
130
156
|
filesWritten.push(referencesPath);
|
|
131
157
|
|
|
@@ -137,13 +163,6 @@ async function generateToolFiles(
|
|
|
137
163
|
export async function runDocsCommand(
|
|
138
164
|
options: RunDocsCommandOptions,
|
|
139
165
|
): Promise<RunDocsCommandResult> {
|
|
140
|
-
if (!(await exists(CLI_DOCS_DIR))) {
|
|
141
|
-
console.error(
|
|
142
|
-
`Documentation directory not found: ${CLI_DOCS_DIR}\nRun "pnpm build" to generate documentation files.`,
|
|
143
|
-
);
|
|
144
|
-
return { exitCode: 1, filesWritten: [] };
|
|
145
|
-
}
|
|
146
|
-
|
|
147
166
|
const filesWritten: string[] = [];
|
|
148
167
|
|
|
149
168
|
const autoDetect = !options.claude && !options.codex;
|
|
@@ -161,20 +180,27 @@ export async function runDocsCommand(
|
|
|
161
180
|
return { exitCode: 0, filesWritten: [] };
|
|
162
181
|
}
|
|
163
182
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
183
|
+
try {
|
|
184
|
+
if (generateClaude) {
|
|
185
|
+
await generateToolFiles(
|
|
186
|
+
options.output,
|
|
187
|
+
{ configDir: ".claude", rulesFile: "CLAUDE.md" },
|
|
188
|
+
filesWritten,
|
|
189
|
+
);
|
|
190
|
+
}
|
|
171
191
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
192
|
+
if (generateCodex) {
|
|
193
|
+
await generateToolFiles(
|
|
194
|
+
options.output,
|
|
195
|
+
{ configDir: ".codex", rulesFile: "AGENTS.md" },
|
|
196
|
+
filesWritten,
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
} catch (error) {
|
|
200
|
+
console.error(
|
|
201
|
+
error instanceof Error ? (error.stack ?? error.message) : String(error),
|
|
177
202
|
);
|
|
203
|
+
return { exitCode: 1, filesWritten: [] };
|
|
178
204
|
}
|
|
179
205
|
|
|
180
206
|
return { exitCode: 0, filesWritten };
|
package/src/config/types.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File extension mode for generated import statements.
|
|
3
|
+
* - "js": Convert .ts to .js (default, compatible with ESM + Node16)
|
|
4
|
+
* - "none": No extension (for bundlers)
|
|
5
|
+
* - "ts": Keep .ts extension (for Deno)
|
|
6
|
+
*/
|
|
7
|
+
export type ImportExtension = "js" | "none" | "ts";
|
|
8
|
+
|
|
1
9
|
/**
|
|
2
10
|
* Output configuration for generated files.
|
|
3
11
|
* All paths are relative to project root.
|
|
@@ -29,6 +37,13 @@ export interface OutputConfig {
|
|
|
29
37
|
* @default "src/gqlkit/__generated__/schema.graphql"
|
|
30
38
|
*/
|
|
31
39
|
readonly schemaPath?: string | null;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* File extension to use in generated import statements.
|
|
43
|
+
* @see ImportExtension
|
|
44
|
+
* @default "js"
|
|
45
|
+
*/
|
|
46
|
+
readonly importExtension?: ImportExtension;
|
|
32
47
|
}
|
|
33
48
|
|
|
34
49
|
/**
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { createJiti } from "jiti";
|
|
4
|
+
import type { ImportExtension } from "../config/types.js";
|
|
4
5
|
import type { Diagnostic } from "../type-extractor/types/index.js";
|
|
5
6
|
import { validateConfig } from "./validator.js";
|
|
6
7
|
|
|
@@ -27,6 +28,8 @@ export interface ResolvedOutputConfig {
|
|
|
27
28
|
readonly typeDefsPath: string | null;
|
|
28
29
|
/** Schema SDL output path. Null suppresses output */
|
|
29
30
|
readonly schemaPath: string | null;
|
|
31
|
+
/** File extension for imports. Default: "js" */
|
|
32
|
+
readonly importExtension: ImportExtension;
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
/**
|
|
@@ -64,6 +67,7 @@ const DEFAULT_OUTPUT_CONFIG: ResolvedOutputConfig = {
|
|
|
64
67
|
resolversPath: DEFAULT_RESOLVERS_PATH,
|
|
65
68
|
typeDefsPath: DEFAULT_TYPEDEFS_PATH,
|
|
66
69
|
schemaPath: DEFAULT_SCHEMA_PATH,
|
|
70
|
+
importExtension: "js",
|
|
67
71
|
};
|
|
68
72
|
|
|
69
73
|
const DEFAULT_HOOKS_CONFIG: ResolvedHooksConfig = {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ImportExtension } from "../config/types.js";
|
|
1
2
|
import type { Diagnostic } from "../type-extractor/types/index.js";
|
|
2
3
|
import {
|
|
3
4
|
DEFAULT_RESOLVERS_PATH,
|
|
@@ -186,6 +187,31 @@ function validateTsconfigPath(
|
|
|
186
187
|
return { resolved: value, diagnostics: [] };
|
|
187
188
|
}
|
|
188
189
|
|
|
190
|
+
function validateImportExtension(
|
|
191
|
+
value: unknown,
|
|
192
|
+
configPath: string,
|
|
193
|
+
): { resolved: ImportExtension; diagnostics: Diagnostic[] } {
|
|
194
|
+
if (value === undefined) {
|
|
195
|
+
return { resolved: "js", diagnostics: [] };
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (value !== "js" && value !== "none" && value !== "ts") {
|
|
199
|
+
return {
|
|
200
|
+
resolved: "js",
|
|
201
|
+
diagnostics: [
|
|
202
|
+
{
|
|
203
|
+
code: "CONFIG_INVALID_IMPORT_EXTENSION",
|
|
204
|
+
message: 'output.importExtension must be "js", "none", or "ts"',
|
|
205
|
+
severity: "error",
|
|
206
|
+
location: { file: configPath, line: 1, column: 1 },
|
|
207
|
+
},
|
|
208
|
+
],
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return { resolved: value, diagnostics: [] };
|
|
213
|
+
}
|
|
214
|
+
|
|
189
215
|
function validateOutputConfig(
|
|
190
216
|
output: unknown,
|
|
191
217
|
configPath: string,
|
|
@@ -198,6 +224,7 @@ function validateOutputConfig(
|
|
|
198
224
|
resolversPath: DEFAULT_RESOLVERS_PATH,
|
|
199
225
|
typeDefsPath: DEFAULT_TYPEDEFS_PATH,
|
|
200
226
|
schemaPath: DEFAULT_SCHEMA_PATH,
|
|
227
|
+
importExtension: "js",
|
|
201
228
|
},
|
|
202
229
|
diagnostics: [],
|
|
203
230
|
};
|
|
@@ -228,10 +255,15 @@ function validateOutputConfig(
|
|
|
228
255
|
"output.schemaPath",
|
|
229
256
|
configPath,
|
|
230
257
|
);
|
|
258
|
+
const importExtensionResult = validateImportExtension(
|
|
259
|
+
output["importExtension"],
|
|
260
|
+
configPath,
|
|
261
|
+
);
|
|
231
262
|
|
|
232
263
|
diagnostics.push(...resolversPathResult.diagnostics);
|
|
233
264
|
diagnostics.push(...typeDefsPathResult.diagnostics);
|
|
234
265
|
diagnostics.push(...schemaPathResult.diagnostics);
|
|
266
|
+
diagnostics.push(...importExtensionResult.diagnostics);
|
|
235
267
|
|
|
236
268
|
if (diagnostics.length > 0) {
|
|
237
269
|
return { resolved: undefined, diagnostics };
|
|
@@ -242,6 +274,7 @@ function validateOutputConfig(
|
|
|
242
274
|
resolversPath: resolversPathResult.resolved,
|
|
243
275
|
typeDefsPath: typeDefsPathResult.resolved,
|
|
244
276
|
schemaPath: schemaPathResult.resolved,
|
|
277
|
+
importExtension: importExtensionResult.resolved,
|
|
245
278
|
},
|
|
246
279
|
diagnostics: [],
|
|
247
280
|
};
|
|
@@ -91,6 +91,12 @@ interface ResolversResult {
|
|
|
91
91
|
diagnostics: Diagnostics;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
interface ScalarConfig {
|
|
95
|
+
readonly customScalarNames: string[];
|
|
96
|
+
readonly globalTypeMappings: GlobalTypeMapping[];
|
|
97
|
+
readonly configScalars: ConfigScalarMapping[];
|
|
98
|
+
}
|
|
99
|
+
|
|
94
100
|
interface PipelineContext {
|
|
95
101
|
readonly config: GenerationConfig;
|
|
96
102
|
readonly sourceFiles: ReadonlyArray<string>;
|
|
@@ -101,6 +107,7 @@ interface PipelineContext {
|
|
|
101
107
|
readonly typesResult: TypesResult | null;
|
|
102
108
|
readonly resolversResult: ResolversResult | null;
|
|
103
109
|
readonly directiveDefinitions: DirectiveDefinitionInfo[] | null;
|
|
110
|
+
readonly scalarConfig: ScalarConfig | null;
|
|
104
111
|
readonly diagnostics: Diagnostic[];
|
|
105
112
|
readonly aborted: boolean;
|
|
106
113
|
}
|
|
@@ -449,6 +456,7 @@ function createInitialContext(config: GenerationConfig): PipelineContext {
|
|
|
449
456
|
typesResult: null,
|
|
450
457
|
resolversResult: null,
|
|
451
458
|
directiveDefinitions: null,
|
|
459
|
+
scalarConfig: null,
|
|
452
460
|
diagnostics: [],
|
|
453
461
|
aborted: false,
|
|
454
462
|
};
|
|
@@ -514,11 +522,7 @@ function collectTypeNamesStep(ctx: PipelineContext): PipelineContext {
|
|
|
514
522
|
};
|
|
515
523
|
}
|
|
516
524
|
|
|
517
|
-
function prepareScalarConfig(config: GenerationConfig): {
|
|
518
|
-
customScalarNames: string[];
|
|
519
|
-
globalTypeMappings: GlobalTypeMapping[];
|
|
520
|
-
configScalars: ConfigScalarMapping[];
|
|
521
|
-
} {
|
|
525
|
+
function prepareScalarConfig(config: GenerationConfig): ScalarConfig {
|
|
522
526
|
const customScalarNames =
|
|
523
527
|
config.customScalars?.map((s) => s.graphqlName) ?? [];
|
|
524
528
|
|
|
@@ -556,18 +560,25 @@ function prepareScalarConfig(config: GenerationConfig): {
|
|
|
556
560
|
return { customScalarNames, globalTypeMappings, configScalars };
|
|
557
561
|
}
|
|
558
562
|
|
|
563
|
+
function prepareScalarConfigStep(ctx: PipelineContext): PipelineContext {
|
|
564
|
+
if (ctx.aborted) return ctx;
|
|
565
|
+
|
|
566
|
+
return { ...ctx, scalarConfig: prepareScalarConfig(ctx.config) };
|
|
567
|
+
}
|
|
568
|
+
|
|
559
569
|
function extractTypesStep(ctx: PipelineContext): PipelineContext {
|
|
560
570
|
if (
|
|
561
571
|
ctx.aborted ||
|
|
562
572
|
!ctx.program ||
|
|
563
573
|
!ctx.knownTypeNames ||
|
|
564
574
|
!ctx.knownTypeSymbols ||
|
|
565
|
-
!ctx.underlyingSymbolToTypeName
|
|
575
|
+
!ctx.underlyingSymbolToTypeName ||
|
|
576
|
+
!ctx.scalarConfig
|
|
566
577
|
)
|
|
567
578
|
return ctx;
|
|
568
579
|
|
|
569
580
|
const { customScalarNames, globalTypeMappings, configScalars } =
|
|
570
|
-
|
|
581
|
+
ctx.scalarConfig;
|
|
571
582
|
|
|
572
583
|
const typesResult = extractTypesCore({
|
|
573
584
|
program: ctx.program,
|
|
@@ -591,11 +602,12 @@ function extractResolversStep(ctx: PipelineContext): PipelineContext {
|
|
|
591
602
|
!ctx.knownTypeNames ||
|
|
592
603
|
!ctx.knownTypeSymbols ||
|
|
593
604
|
!ctx.underlyingSymbolToTypeName ||
|
|
594
|
-
!ctx.typesResult
|
|
605
|
+
!ctx.typesResult ||
|
|
606
|
+
!ctx.scalarConfig
|
|
595
607
|
)
|
|
596
608
|
return ctx;
|
|
597
609
|
|
|
598
|
-
const { globalTypeMappings } =
|
|
610
|
+
const { globalTypeMappings } = ctx.scalarConfig;
|
|
599
611
|
|
|
600
612
|
const resolversResult = extractResolversCore({
|
|
601
613
|
program: ctx.program,
|
|
@@ -663,11 +675,16 @@ function generateSchemaStep(ctx: PipelineContext): {
|
|
|
663
675
|
ctx: PipelineContext;
|
|
664
676
|
schemaResult: ReturnType<typeof generateSchema> | null;
|
|
665
677
|
} {
|
|
666
|
-
if (
|
|
678
|
+
if (
|
|
679
|
+
ctx.aborted ||
|
|
680
|
+
!ctx.typesResult ||
|
|
681
|
+
!ctx.resolversResult ||
|
|
682
|
+
!ctx.scalarConfig
|
|
683
|
+
) {
|
|
667
684
|
return { ctx, schemaResult: null };
|
|
668
685
|
}
|
|
669
686
|
|
|
670
|
-
const { customScalarNames } =
|
|
687
|
+
const { customScalarNames } = ctx.scalarConfig;
|
|
671
688
|
const allCustomScalarNames = [
|
|
672
689
|
...customScalarNames,
|
|
673
690
|
...ctx.typesResult.detectedScalarNames,
|
|
@@ -687,6 +704,7 @@ function generateSchemaStep(ctx: PipelineContext): {
|
|
|
687
704
|
enablePruning: null,
|
|
688
705
|
sourceRoot: ctx.config.cwd,
|
|
689
706
|
knownTypeNames: ctx.knownTypeNames,
|
|
707
|
+
importExtension: ctx.config.output.importExtension,
|
|
690
708
|
});
|
|
691
709
|
|
|
692
710
|
const newDiagnostics = [...ctx.diagnostics, ...schemaResult.diagnostics];
|
|
@@ -739,6 +757,7 @@ export async function executeGeneration(
|
|
|
739
757
|
ctx = await scanSourceFilesStep(ctx);
|
|
740
758
|
ctx = createProgramStep(ctx);
|
|
741
759
|
ctx = collectTypeNamesStep(ctx);
|
|
760
|
+
ctx = prepareScalarConfigStep(ctx);
|
|
742
761
|
ctx = extractTypesStep(ctx);
|
|
743
762
|
ctx = extractResolversStep(ctx);
|
|
744
763
|
ctx = extractDirectivesStep(ctx);
|
|
@@ -200,23 +200,23 @@ function extractTypeNameFromType(
|
|
|
200
200
|
function detectResolverFromMetadataType(
|
|
201
201
|
callExpr: ts.CallExpression,
|
|
202
202
|
checker: ts.TypeChecker,
|
|
203
|
-
): DefineApiResolverType |
|
|
203
|
+
): DefineApiResolverType | null {
|
|
204
204
|
const returnType = checker.getTypeAtLocation(callExpr);
|
|
205
205
|
|
|
206
206
|
const metadataProp = returnType.getProperty(RESOLVER_METADATA_PROPERTY);
|
|
207
207
|
if (!metadataProp) {
|
|
208
|
-
return
|
|
208
|
+
return null;
|
|
209
209
|
}
|
|
210
210
|
|
|
211
211
|
const metadataType = checker.getTypeOfSymbol(metadataProp);
|
|
212
212
|
const actualType = getActualMetadataType(metadataType);
|
|
213
213
|
if (!actualType) {
|
|
214
|
-
return
|
|
214
|
+
return null;
|
|
215
215
|
}
|
|
216
216
|
|
|
217
217
|
const kindProp = actualType.getProperty("kind");
|
|
218
218
|
if (!kindProp) {
|
|
219
|
-
return
|
|
219
|
+
return null;
|
|
220
220
|
}
|
|
221
221
|
|
|
222
222
|
const kindType = checker.getTypeOfSymbol(kindProp);
|
|
@@ -227,7 +227,7 @@ function detectResolverFromMetadataType(
|
|
|
227
227
|
}
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
-
return
|
|
230
|
+
return null;
|
|
231
231
|
}
|
|
232
232
|
|
|
233
233
|
function isInlineTypeLiteralDeclaration(declaration: ts.Declaration): boolean {
|