nitro-graphql 2.0.0-beta.4 → 2.0.0-beta.41
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 +438 -27
- package/dist/cli/commands/generate.d.mts +26 -0
- package/dist/cli/commands/generate.mjs +196 -0
- package/dist/cli/commands/index.d.mts +4 -0
- package/dist/cli/commands/index.mjs +5 -0
- package/dist/cli/commands/init.d.mts +46 -0
- package/dist/cli/commands/init.mjs +195 -0
- package/dist/cli/commands/validate.d.mts +10 -0
- package/dist/cli/commands/validate.mjs +69 -0
- package/dist/cli/completions.d.mts +7 -0
- package/dist/cli/completions.mjs +34 -0
- package/dist/cli/config.d.mts +75 -0
- package/dist/cli/config.mjs +20 -0
- package/dist/cli/index.d.mts +24 -0
- package/dist/cli/index.mjs +253 -0
- package/dist/config.d.mts +2 -0
- package/dist/config.mjs +3 -0
- package/dist/core/codegen/client.d.mts +23 -0
- package/dist/core/codegen/client.mjs +150 -0
- package/dist/core/codegen/document-loader.d.mts +10 -0
- package/dist/core/codegen/document-loader.mjs +18 -0
- package/dist/core/codegen/index.d.mts +8 -0
- package/dist/core/codegen/index.mjs +9 -0
- package/dist/core/codegen/plugin.d.mts +20 -0
- package/dist/core/codegen/plugin.mjs +30 -0
- package/dist/core/codegen/runtime.d.mts +20 -0
- package/dist/core/codegen/runtime.mjs +60 -0
- package/dist/core/codegen/schema-loader.d.mts +28 -0
- package/dist/core/codegen/schema-loader.mjs +128 -0
- package/dist/core/codegen/server.d.mts +28 -0
- package/dist/core/codegen/server.mjs +143 -0
- package/dist/core/codegen/validation.d.mts +13 -0
- package/dist/core/codegen/validation.mjs +96 -0
- package/dist/core/config.d.mts +50 -0
- package/dist/core/config.mjs +82 -0
- package/dist/core/constants.d.mts +188 -0
- package/dist/core/constants.mjs +210 -0
- package/dist/core/index.d.mts +33 -0
- package/dist/core/index.mjs +27 -0
- package/dist/core/manifest.d.mts +46 -0
- package/dist/core/manifest.mjs +76 -0
- package/dist/core/scanning/ast-scanner.d.mts +28 -0
- package/dist/core/scanning/ast-scanner.mjs +122 -0
- package/dist/core/scanning/common.d.mts +37 -0
- package/dist/core/scanning/common.mjs +60 -0
- package/dist/core/scanning/directives.d.mts +10 -0
- package/dist/core/scanning/directives.mjs +29 -0
- package/dist/core/scanning/documents.d.mts +21 -0
- package/dist/core/scanning/documents.mjs +43 -0
- package/dist/core/scanning/index.d.mts +7 -0
- package/dist/core/scanning/index.mjs +8 -0
- package/dist/core/scanning/resolvers.d.mts +15 -0
- package/dist/core/scanning/resolvers.mjs +59 -0
- package/dist/core/scanning/schemas.d.mts +14 -0
- package/dist/core/scanning/schemas.mjs +64 -0
- package/dist/core/schema/builder.d.mts +53 -0
- package/dist/core/schema/builder.mjs +70 -0
- package/dist/core/schema/federation.d.mts +34 -0
- package/dist/core/schema/federation.mjs +40 -0
- package/dist/core/schema/index.d.mts +3 -0
- package/dist/core/schema/index.mjs +4 -0
- package/dist/core/types/adapter.d.mts +58 -0
- package/dist/core/types/codegen.d.mts +133 -0
- package/dist/core/types/config.d.mts +210 -0
- package/dist/core/types/config.mjs +1 -0
- package/dist/{utils/define.d.ts → core/types/define.d.mts} +3 -30
- package/dist/core/types/define.mjs +1 -0
- package/dist/core/types/index.d.mts +5 -0
- package/dist/core/types/index.mjs +1 -0
- package/dist/core/types/scanning.d.mts +69 -0
- package/dist/core/types/scanning.mjs +1 -0
- package/dist/{utils/directive-parser.d.ts → core/utils/directive-parser.d.mts} +21 -4
- package/dist/{utils/directive-parser.js → core/utils/directive-parser.mjs} +25 -34
- package/dist/core/utils/errors.d.mts +77 -0
- package/dist/core/utils/errors.mjs +93 -0
- package/dist/core/utils/file-io.d.mts +24 -0
- package/dist/core/utils/file-io.mjs +47 -0
- package/dist/core/utils/imports.d.mts +15 -0
- package/dist/core/utils/imports.mjs +25 -0
- package/dist/core/utils/index.d.mts +7 -0
- package/dist/core/utils/index.mjs +8 -0
- package/dist/core/utils/logger.d.mts +19 -0
- package/dist/core/utils/logger.mjs +38 -0
- package/dist/core/utils/ofetch-templates.d.mts +30 -0
- package/dist/core/utils/ofetch-templates.mjs +135 -0
- package/dist/core/validation/external-services.d.mts +11 -0
- package/dist/core/validation/external-services.mjs +34 -0
- package/dist/core/validation/index.d.mts +2 -0
- package/dist/core/validation/index.mjs +3 -0
- package/dist/define.d.mts +294 -0
- package/dist/define.mjs +323 -0
- package/dist/index.d.mts +6 -0
- package/dist/index.mjs +6 -0
- package/dist/nitro/adapter.d.mts +30 -0
- package/dist/nitro/adapter.mjs +97 -0
- package/dist/{utils/apollo.d.ts → nitro/apollo.d.mts} +3 -3
- package/dist/nitro/apollo.mjs +59 -0
- package/dist/nitro/codegen.d.mts +19 -0
- package/dist/nitro/codegen.mjs +141 -0
- package/dist/nitro/config.d.mts +51 -0
- package/dist/nitro/config.mjs +57 -0
- package/dist/nitro/index.d.mts +46 -0
- package/dist/nitro/index.mjs +65 -0
- package/dist/nitro/paths.d.mts +54 -0
- package/dist/nitro/paths.mjs +92 -0
- package/dist/nitro/rollup.d.mts +6 -0
- package/dist/nitro/rollup.mjs +95 -0
- package/dist/nitro/routes/apollo-server.d.mts +6 -0
- package/dist/nitro/routes/apollo-server.mjs +71 -0
- package/dist/nitro/routes/debug-template.d.mts +15 -0
- package/dist/nitro/routes/debug-template.mjs +385 -0
- package/dist/nitro/routes/debug.d.mts +55 -0
- package/dist/nitro/routes/debug.mjs +102 -0
- package/dist/nitro/routes/graphql-yoga.d.mts +6 -0
- package/dist/nitro/routes/graphql-yoga.mjs +62 -0
- package/dist/nitro/routes/health.d.mts +10 -0
- package/dist/{routes/health.js → nitro/routes/health.mjs} +4 -3
- package/dist/nitro/setup/extend-loader.d.mts +19 -0
- package/dist/nitro/setup/extend-loader.mjs +129 -0
- package/dist/nitro/setup/file-watcher.d.mts +16 -0
- package/dist/nitro/setup/file-watcher.mjs +98 -0
- package/dist/nitro/setup/logging.d.mts +17 -0
- package/dist/nitro/setup/logging.mjs +66 -0
- package/dist/nitro/setup/rollup-integration.d.mts +16 -0
- package/dist/nitro/setup/rollup-integration.mjs +90 -0
- package/dist/nitro/setup/routes.d.mts +10 -0
- package/dist/nitro/setup/routes.mjs +35 -0
- package/dist/nitro/setup/ts-config.d.mts +11 -0
- package/dist/nitro/setup/ts-config.mjs +69 -0
- package/dist/nitro/setup.d.mts +12 -0
- package/dist/nitro/setup.mjs +234 -0
- package/dist/nitro/types.d.mts +374 -0
- package/dist/nitro/types.mjs +1 -0
- package/dist/nitro/virtual/generators.d.mts +31 -0
- package/dist/nitro/virtual/generators.mjs +113 -0
- package/dist/nitro/virtual/stubs.d.mts +20 -0
- package/dist/nitro/virtual/stubs.mjs +31 -0
- package/dist/{ecosystem/nuxt.d.ts → nuxt.d.mts} +1 -1
- package/dist/nuxt.mjs +109 -0
- package/dist/{graphql/server.d.ts → stubs/index.d.mts} +5 -1
- package/dist/stubs/index.mjs +1 -0
- package/package.json +102 -77
- package/dist/ecosystem/nuxt.js +0 -67
- package/dist/graphql/index.d.ts +0 -5
- package/dist/index.d.ts +0 -8
- package/dist/index.js +0 -264
- package/dist/rollup.js +0 -119
- package/dist/routes/apollo-server.d.ts +0 -6
- package/dist/routes/apollo-server.js +0 -89
- package/dist/routes/graphql-yoga.d.ts +0 -6
- package/dist/routes/graphql-yoga.js +0 -91
- package/dist/routes/health.d.ts +0 -6
- package/dist/types/index.d.ts +0 -128
- package/dist/types/standard-schema.d.ts +0 -59
- package/dist/utils/apollo.js +0 -61
- package/dist/utils/client-codegen.d.ts +0 -38
- package/dist/utils/client-codegen.js +0 -290
- package/dist/utils/define.js +0 -57
- package/dist/utils/index.d.ts +0 -39
- package/dist/utils/index.js +0 -250
- package/dist/utils/server-codegen.d.ts +0 -7
- package/dist/utils/server-codegen.js +0 -136
- package/dist/utils/type-generation.d.ts +0 -7
- package/dist/utils/type-generation.js +0 -287
- package/dist/vite.d.ts +0 -25
- package/dist/vite.js +0 -40
- /package/dist/{graphql/index.js → core/types/adapter.mjs} +0 -0
- /package/dist/{graphql/server.js → core/types/codegen.mjs} +0 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { scanWithLayers } from "./common.mjs";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { basename, relative } from "pathe";
|
|
4
|
+
import { parseSync } from "oxc-parser";
|
|
5
|
+
|
|
6
|
+
//#region src/core/scanning/ast-scanner.ts
|
|
7
|
+
/**
|
|
8
|
+
* Scan files matching a pattern and parse their exports using AST
|
|
9
|
+
*/
|
|
10
|
+
async function scanWithAST(ctx, config) {
|
|
11
|
+
const warnings = [];
|
|
12
|
+
const errors = [];
|
|
13
|
+
try {
|
|
14
|
+
const serverDirRelative = relative(ctx.rootDir, ctx.serverDir);
|
|
15
|
+
const files = await scanWithLayers(ctx, {
|
|
16
|
+
mainDir: ctx.rootDir,
|
|
17
|
+
mainSubDir: serverDirRelative,
|
|
18
|
+
layerDirs: ctx.layerServerDirs,
|
|
19
|
+
layerSubDir: "graphql",
|
|
20
|
+
pattern: config.pattern
|
|
21
|
+
});
|
|
22
|
+
const results = [];
|
|
23
|
+
for (const file of files) try {
|
|
24
|
+
const fileContent = await readFile(file.fullPath, "utf-8");
|
|
25
|
+
const parsed = parseSync(file.fullPath, fileContent);
|
|
26
|
+
if (parsed.errors && parsed.errors.length > 0) {
|
|
27
|
+
if (ctx.isDev) {
|
|
28
|
+
const fileName = basename(file.fullPath);
|
|
29
|
+
const firstError = parsed.errors[0];
|
|
30
|
+
const location = firstError?.labels?.[0];
|
|
31
|
+
const lineInfo = location ? `:${location.start}` : "";
|
|
32
|
+
const message = firstError?.message.split(",")[0] || "Syntax error";
|
|
33
|
+
errors.push(`${fileName}${lineInfo} - ${message}`);
|
|
34
|
+
}
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
const result = parseExports(file.fullPath, parsed.program, config);
|
|
38
|
+
if (ctx.isDev && config.emitWarnings && result.warnings.length > 0) {
|
|
39
|
+
const relPath = relative(ctx.rootDir, file.fullPath);
|
|
40
|
+
for (const warning of result.warnings) warnings.push(`${relPath}: ${warning}`);
|
|
41
|
+
}
|
|
42
|
+
if (result.resolver.imports.length > 0) results.push(result.resolver);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
const relPath = relative(ctx.rootDir, file.fullPath);
|
|
45
|
+
errors.push(`Failed to parse file ${relPath}: ${error}`);
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
items: results,
|
|
49
|
+
warnings,
|
|
50
|
+
errors
|
|
51
|
+
};
|
|
52
|
+
} catch (error) {
|
|
53
|
+
errors.push(`Scanning error: ${error}`);
|
|
54
|
+
return {
|
|
55
|
+
items: [],
|
|
56
|
+
warnings,
|
|
57
|
+
errors
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Parse a single file and extract exports using AST
|
|
63
|
+
* Used for manifest resolver files
|
|
64
|
+
*/
|
|
65
|
+
async function parseSingleFile(filePath, parseCall) {
|
|
66
|
+
try {
|
|
67
|
+
const parsed = parseSync(filePath, await readFile(filePath, "utf-8"));
|
|
68
|
+
if (parsed.errors && parsed.errors.length > 0) return null;
|
|
69
|
+
const result = parseExports(filePath, parsed.program, {
|
|
70
|
+
pattern: "",
|
|
71
|
+
parseCall,
|
|
72
|
+
emitWarnings: false
|
|
73
|
+
});
|
|
74
|
+
if (result.resolver.imports.length > 0) return result.resolver;
|
|
75
|
+
return null;
|
|
76
|
+
} catch {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Parse exports from AST program
|
|
82
|
+
*/
|
|
83
|
+
function parseExports(filePath, program, config) {
|
|
84
|
+
const warnings = [];
|
|
85
|
+
const resolver = {
|
|
86
|
+
specifier: filePath,
|
|
87
|
+
imports: []
|
|
88
|
+
};
|
|
89
|
+
let hasDefaultExport = false;
|
|
90
|
+
let hasNamedExport = false;
|
|
91
|
+
const namedExports = [];
|
|
92
|
+
for (const node of program.body) {
|
|
93
|
+
if (node.type === "ExportDefaultDeclaration") hasDefaultExport = true;
|
|
94
|
+
if (node.type === "ExportNamedDeclaration" && node.declaration && node.declaration.type === "VariableDeclaration") {
|
|
95
|
+
for (const decl of node.declaration.declarations) if (decl.type === "VariableDeclarator" && decl.init && decl.id.type === "Identifier") {
|
|
96
|
+
hasNamedExport = true;
|
|
97
|
+
namedExports.push(decl.id.name);
|
|
98
|
+
if (decl.init && decl.init.type === "CallExpression") {
|
|
99
|
+
if (decl.init.callee.type === "Identifier") {
|
|
100
|
+
const imp = config.parseCall(decl.init.callee.name, decl.id.name, filePath);
|
|
101
|
+
if (imp) resolver.imports.push(imp);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (config.emitWarnings) {
|
|
108
|
+
if (hasDefaultExport && !hasNamedExport) warnings.push("Using default export instead of named export. Must use named exports like \"export const myResolver = defineQuery(...)\". Default exports are not detected.");
|
|
109
|
+
if (resolver.imports.length === 0 && hasNamedExport) {
|
|
110
|
+
const validFunctions = config.validFunctions?.join(", ") || "define* functions";
|
|
111
|
+
warnings.push(`File has named exports [${namedExports.join(", ")}] but none use the required define functions (${validFunctions}). Exports will not be registered.`);
|
|
112
|
+
}
|
|
113
|
+
if (!hasDefaultExport && !hasNamedExport) warnings.push("No exports found. Files must export using define* functions.");
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
resolver,
|
|
117
|
+
warnings
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
//#endregion
|
|
122
|
+
export { parseSingleFile, scanWithAST };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ScanContext, ScannedFile } from "../types/scanning.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/core/scanning/common.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Scan a directory for files matching a glob pattern
|
|
7
|
+
*/
|
|
8
|
+
declare function scanDirectory(ctx: ScanContext, baseDir: string, subDir: string, globPattern?: string): Promise<ScannedFile[]>;
|
|
9
|
+
/**
|
|
10
|
+
* Deduplicate files by fullPath
|
|
11
|
+
*/
|
|
12
|
+
declare function deduplicateFiles<T extends {
|
|
13
|
+
fullPath: string;
|
|
14
|
+
}>(files: T[]): T[];
|
|
15
|
+
/**
|
|
16
|
+
* Filter files by extension
|
|
17
|
+
*/
|
|
18
|
+
declare function filterByExtension<T extends {
|
|
19
|
+
fullPath: string;
|
|
20
|
+
}>(files: T[], extensions: readonly string[]): T[];
|
|
21
|
+
/**
|
|
22
|
+
* Extract file paths from scanned files
|
|
23
|
+
*/
|
|
24
|
+
declare function extractPaths(files: ScannedFile[]): string[];
|
|
25
|
+
/**
|
|
26
|
+
* Scan directory with layer support
|
|
27
|
+
* Encapsulates the common pattern of scanning main directory + layer directories
|
|
28
|
+
*/
|
|
29
|
+
declare function scanWithLayers(ctx: ScanContext, options: {
|
|
30
|
+
mainDir: string;
|
|
31
|
+
mainSubDir: string;
|
|
32
|
+
layerDirs: string[] | undefined;
|
|
33
|
+
layerSubDir: string;
|
|
34
|
+
pattern: string;
|
|
35
|
+
}): Promise<ScannedFile[]>;
|
|
36
|
+
//#endregion
|
|
37
|
+
export { deduplicateFiles, extractPaths, filterByExtension, scanDirectory, scanWithLayers };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { GLOB_SCAN_PATTERN } from "../constants.mjs";
|
|
2
|
+
import { join, relative } from "pathe";
|
|
3
|
+
import { glob } from "tinyglobby";
|
|
4
|
+
|
|
5
|
+
//#region src/core/scanning/common.ts
|
|
6
|
+
/**
|
|
7
|
+
* Scan a directory for files matching a glob pattern
|
|
8
|
+
*/
|
|
9
|
+
async function scanDirectory(ctx, baseDir, subDir, globPattern = GLOB_SCAN_PATTERN) {
|
|
10
|
+
return (await glob(join(subDir, globPattern), {
|
|
11
|
+
cwd: baseDir,
|
|
12
|
+
dot: true,
|
|
13
|
+
ignore: ctx.ignorePatterns,
|
|
14
|
+
absolute: true
|
|
15
|
+
}).catch((error) => {
|
|
16
|
+
if (error?.code === "ENOTDIR") {
|
|
17
|
+
ctx.logger.warn(`Ignoring \`${join(baseDir, subDir)}\`. It must be a directory.`);
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
throw error;
|
|
21
|
+
})).map((fullPath) => ({
|
|
22
|
+
fullPath,
|
|
23
|
+
path: relative(join(baseDir, subDir), fullPath)
|
|
24
|
+
})).sort((a, b) => a.path.localeCompare(b.path));
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Deduplicate files by fullPath
|
|
28
|
+
*/
|
|
29
|
+
function deduplicateFiles(files) {
|
|
30
|
+
const seenPaths = /* @__PURE__ */ new Set();
|
|
31
|
+
return files.filter((file) => {
|
|
32
|
+
if (seenPaths.has(file.fullPath)) return false;
|
|
33
|
+
seenPaths.add(file.fullPath);
|
|
34
|
+
return true;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Filter files by extension
|
|
39
|
+
*/
|
|
40
|
+
function filterByExtension(files, extensions) {
|
|
41
|
+
return files.filter((file) => extensions.some((ext) => file.fullPath.endsWith(ext)));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Extract file paths from scanned files
|
|
45
|
+
*/
|
|
46
|
+
function extractPaths(files) {
|
|
47
|
+
return files.map((f) => f.fullPath);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Scan directory with layer support
|
|
51
|
+
* Encapsulates the common pattern of scanning main directory + layer directories
|
|
52
|
+
*/
|
|
53
|
+
async function scanWithLayers(ctx, options) {
|
|
54
|
+
const mainFiles = await scanDirectory(ctx, options.mainDir, options.mainSubDir, options.pattern);
|
|
55
|
+
const layerFiles = await Promise.all((options.layerDirs || []).map((layerDir) => scanDirectory(ctx, layerDir, options.layerSubDir, options.pattern))).then((r) => r.flat());
|
|
56
|
+
return deduplicateFiles([...mainFiles, ...layerFiles]);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
//#endregion
|
|
60
|
+
export { deduplicateFiles, extractPaths, filterByExtension, scanDirectory, scanWithLayers };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ScanContext, ScanResult, ScannedResolver } from "../types/scanning.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/core/scanning/directives.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Scan for directive files (.directive.ts/.js)
|
|
7
|
+
*/
|
|
8
|
+
declare function scanDirectivesCore(ctx: ScanContext): Promise<ScanResult<ScannedResolver>>;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { scanDirectivesCore };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { DIRECTIVE_GLOB_PATTERN } from "../constants.mjs";
|
|
2
|
+
import { scanWithAST } from "./ast-scanner.mjs";
|
|
3
|
+
import { hash } from "ohash";
|
|
4
|
+
|
|
5
|
+
//#region src/core/scanning/directives.ts
|
|
6
|
+
/**
|
|
7
|
+
* Parse a defineDirective call and return the import info
|
|
8
|
+
*/
|
|
9
|
+
function parseDirectiveCall(calleeName, exportName, filePath) {
|
|
10
|
+
if (calleeName !== "defineDirective") return null;
|
|
11
|
+
return {
|
|
12
|
+
name: exportName,
|
|
13
|
+
type: "directive",
|
|
14
|
+
as: `_${hash(exportName + filePath).replace(/-/g, "").slice(0, 6)}`
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Scan for directive files (.directive.ts/.js)
|
|
19
|
+
*/
|
|
20
|
+
function scanDirectivesCore(ctx) {
|
|
21
|
+
return scanWithAST(ctx, {
|
|
22
|
+
pattern: DIRECTIVE_GLOB_PATTERN,
|
|
23
|
+
parseCall: parseDirectiveCall,
|
|
24
|
+
emitWarnings: false
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
export { scanDirectivesCore };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { CoreExternalService } from "../types/config.mjs";
|
|
2
|
+
import { ScanContext, ScanResult } from "../types/scanning.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/core/scanning/documents.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Options for scanning documents
|
|
8
|
+
*/
|
|
9
|
+
interface ScanDocumentsOptions {
|
|
10
|
+
/** External services to exclude from main scan */
|
|
11
|
+
externalServices?: CoreExternalService[];
|
|
12
|
+
/** Client directory relative path */
|
|
13
|
+
clientDirRelative?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Scan for GraphQL client documents (.graphql) in client directory
|
|
17
|
+
* Excludes files from external service directories
|
|
18
|
+
*/
|
|
19
|
+
declare function scanDocumentsCore(ctx: ScanContext, options?: ScanDocumentsOptions): Promise<ScanResult<string>>;
|
|
20
|
+
//#endregion
|
|
21
|
+
export { ScanDocumentsOptions, scanDocumentsCore };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { GRAPHQL_GLOB_PATTERN } from "../constants.mjs";
|
|
2
|
+
import { scanWithLayers } from "./common.mjs";
|
|
3
|
+
import { relative } from "pathe";
|
|
4
|
+
|
|
5
|
+
//#region src/core/scanning/documents.ts
|
|
6
|
+
/**
|
|
7
|
+
* Scan for GraphQL client documents (.graphql) in client directory
|
|
8
|
+
* Excludes files from external service directories
|
|
9
|
+
*/
|
|
10
|
+
async function scanDocumentsCore(ctx, options = {}) {
|
|
11
|
+
const warnings = [];
|
|
12
|
+
const errors = [];
|
|
13
|
+
try {
|
|
14
|
+
const clientDirRelative = options.clientDirRelative || relative(ctx.rootDir, ctx.clientDir);
|
|
15
|
+
const allFiles = await scanWithLayers(ctx, {
|
|
16
|
+
mainDir: ctx.rootDir,
|
|
17
|
+
mainSubDir: clientDirRelative,
|
|
18
|
+
layerDirs: ctx.layerAppDirs,
|
|
19
|
+
layerSubDir: "graphql",
|
|
20
|
+
pattern: GRAPHQL_GLOB_PATTERN
|
|
21
|
+
});
|
|
22
|
+
const externalPatterns = (options.externalServices || []).flatMap((service) => service.documents || []);
|
|
23
|
+
return {
|
|
24
|
+
items: allFiles.filter((f) => !f.path.startsWith("external/")).filter((f) => {
|
|
25
|
+
const relativePath = f.path;
|
|
26
|
+
for (const pattern of externalPatterns) if (pattern.replace(/* @__PURE__ */ new RegExp(`^${clientDirRelative.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}/`), "").split("/")[0] === relativePath.split("/")[0]) return false;
|
|
27
|
+
return true;
|
|
28
|
+
}).map((f) => f.fullPath),
|
|
29
|
+
warnings,
|
|
30
|
+
errors
|
|
31
|
+
};
|
|
32
|
+
} catch (error) {
|
|
33
|
+
errors.push(`Document scanning error: ${error}`);
|
|
34
|
+
return {
|
|
35
|
+
items: [],
|
|
36
|
+
warnings,
|
|
37
|
+
errors
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
//#endregion
|
|
43
|
+
export { scanDocumentsCore };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ASTScanConfig, parseSingleFile, scanWithAST } from "./ast-scanner.mjs";
|
|
2
|
+
import { deduplicateFiles, extractPaths, filterByExtension, scanDirectory } from "./common.mjs";
|
|
3
|
+
import { scanDirectivesCore } from "./directives.mjs";
|
|
4
|
+
import { ScanDocumentsOptions, scanDocumentsCore } from "./documents.mjs";
|
|
5
|
+
import { parseResolverCall, scanResolversCore } from "./resolvers.mjs";
|
|
6
|
+
import { scanGraphqlCore, scanSchemasCore } from "./schemas.mjs";
|
|
7
|
+
export { type ASTScanConfig, type ScanDocumentsOptions, deduplicateFiles, extractPaths, filterByExtension, parseResolverCall, parseSingleFile, scanDirectivesCore, scanDirectory, scanDocumentsCore, scanGraphqlCore, scanResolversCore, scanSchemasCore, scanWithAST };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { deduplicateFiles, extractPaths, filterByExtension, scanDirectory } from "./common.mjs";
|
|
2
|
+
import { parseSingleFile, scanWithAST } from "./ast-scanner.mjs";
|
|
3
|
+
import { scanDirectivesCore } from "./directives.mjs";
|
|
4
|
+
import { scanDocumentsCore } from "./documents.mjs";
|
|
5
|
+
import { parseResolverCall, scanResolversCore } from "./resolvers.mjs";
|
|
6
|
+
import { scanGraphqlCore, scanSchemasCore } from "./schemas.mjs";
|
|
7
|
+
|
|
8
|
+
export { deduplicateFiles, extractPaths, filterByExtension, parseResolverCall, parseSingleFile, scanDirectivesCore, scanDirectory, scanDocumentsCore, scanGraphqlCore, scanResolversCore, scanSchemasCore, scanWithAST };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ResolverImport, ScanContext, ScanResult, ScannedResolver } from "../types/scanning.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/core/scanning/resolvers.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Parse a define* function call and return the import info
|
|
7
|
+
* Exported for use by manifest loader
|
|
8
|
+
*/
|
|
9
|
+
declare function parseResolverCall(calleeName: string, exportName: string, filePath: string): ResolverImport | null;
|
|
10
|
+
/**
|
|
11
|
+
* Scan for resolver files and parse their exports
|
|
12
|
+
*/
|
|
13
|
+
declare function scanResolversCore(ctx: ScanContext): Promise<ScanResult<ScannedResolver>>;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { parseResolverCall, scanResolversCore };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { DEFINE_FUNCTIONS, RESOLVER_GLOB_PATTERN } from "../constants.mjs";
|
|
2
|
+
import { scanWithAST } from "./ast-scanner.mjs";
|
|
3
|
+
import { hash } from "ohash";
|
|
4
|
+
|
|
5
|
+
//#region src/core/scanning/resolvers.ts
|
|
6
|
+
/**
|
|
7
|
+
* Parse a define* function call and return the import info
|
|
8
|
+
* Exported for use by manifest loader
|
|
9
|
+
*/
|
|
10
|
+
function parseResolverCall(calleeName, exportName, filePath) {
|
|
11
|
+
const aliasHash = `_${hash(exportName + filePath).replace(/-/g, "").slice(0, 6)}`;
|
|
12
|
+
switch (calleeName) {
|
|
13
|
+
case "defineResolver": return {
|
|
14
|
+
name: exportName,
|
|
15
|
+
type: "resolver",
|
|
16
|
+
as: aliasHash
|
|
17
|
+
};
|
|
18
|
+
case "defineQuery": return {
|
|
19
|
+
name: exportName,
|
|
20
|
+
type: "query",
|
|
21
|
+
as: aliasHash
|
|
22
|
+
};
|
|
23
|
+
case "defineMutation": return {
|
|
24
|
+
name: exportName,
|
|
25
|
+
type: "mutation",
|
|
26
|
+
as: aliasHash
|
|
27
|
+
};
|
|
28
|
+
case "defineField": return {
|
|
29
|
+
name: exportName,
|
|
30
|
+
type: "type",
|
|
31
|
+
as: aliasHash
|
|
32
|
+
};
|
|
33
|
+
case "defineSubscription": return {
|
|
34
|
+
name: exportName,
|
|
35
|
+
type: "subscription",
|
|
36
|
+
as: aliasHash
|
|
37
|
+
};
|
|
38
|
+
case "defineDirective": return {
|
|
39
|
+
name: exportName,
|
|
40
|
+
type: "directive",
|
|
41
|
+
as: aliasHash
|
|
42
|
+
};
|
|
43
|
+
default: return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Scan for resolver files and parse their exports
|
|
48
|
+
*/
|
|
49
|
+
function scanResolversCore(ctx) {
|
|
50
|
+
return scanWithAST(ctx, {
|
|
51
|
+
pattern: RESOLVER_GLOB_PATTERN,
|
|
52
|
+
parseCall: parseResolverCall,
|
|
53
|
+
emitWarnings: true,
|
|
54
|
+
validFunctions: DEFINE_FUNCTIONS
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
//#endregion
|
|
59
|
+
export { parseResolverCall, scanResolversCore };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ScanContext, ScanResult } from "../types/scanning.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/core/scanning/schemas.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Scan for GraphQL schema files (.graphql) in server directory
|
|
7
|
+
*/
|
|
8
|
+
declare function scanSchemasCore(ctx: ScanContext): Promise<ScanResult<string>>;
|
|
9
|
+
/**
|
|
10
|
+
* Scan for GraphQL files (.graphql, .gql) in server directory
|
|
11
|
+
*/
|
|
12
|
+
declare function scanGraphqlCore(ctx: ScanContext): Promise<ScanResult<string>>;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { scanGraphqlCore, scanSchemasCore };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { GRAPHQL_GLOB_PATTERN } from "../constants.mjs";
|
|
2
|
+
import { extractPaths, scanWithLayers } from "./common.mjs";
|
|
3
|
+
import { relative } from "pathe";
|
|
4
|
+
|
|
5
|
+
//#region src/core/scanning/schemas.ts
|
|
6
|
+
/**
|
|
7
|
+
* Scan for GraphQL schema files (.graphql) in server directory
|
|
8
|
+
*/
|
|
9
|
+
async function scanSchemasCore(ctx) {
|
|
10
|
+
const warnings = [];
|
|
11
|
+
const errors = [];
|
|
12
|
+
try {
|
|
13
|
+
const serverDirRelative = relative(ctx.rootDir, ctx.serverDir);
|
|
14
|
+
return {
|
|
15
|
+
items: extractPaths(await scanWithLayers(ctx, {
|
|
16
|
+
mainDir: ctx.rootDir,
|
|
17
|
+
mainSubDir: serverDirRelative,
|
|
18
|
+
layerDirs: ctx.layerServerDirs,
|
|
19
|
+
layerSubDir: "graphql",
|
|
20
|
+
pattern: GRAPHQL_GLOB_PATTERN
|
|
21
|
+
})),
|
|
22
|
+
warnings,
|
|
23
|
+
errors
|
|
24
|
+
};
|
|
25
|
+
} catch (error) {
|
|
26
|
+
errors.push(`Schema scanning error: ${error}`);
|
|
27
|
+
return {
|
|
28
|
+
items: [],
|
|
29
|
+
warnings,
|
|
30
|
+
errors
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Scan for GraphQL files (.graphql, .gql) in server directory
|
|
36
|
+
*/
|
|
37
|
+
async function scanGraphqlCore(ctx) {
|
|
38
|
+
const warnings = [];
|
|
39
|
+
const errors = [];
|
|
40
|
+
try {
|
|
41
|
+
const serverDirRelative = relative(ctx.rootDir, ctx.serverDir);
|
|
42
|
+
return {
|
|
43
|
+
items: extractPaths(await scanWithLayers(ctx, {
|
|
44
|
+
mainDir: ctx.rootDir,
|
|
45
|
+
mainSubDir: serverDirRelative,
|
|
46
|
+
layerDirs: ctx.layerServerDirs,
|
|
47
|
+
layerSubDir: "graphql",
|
|
48
|
+
pattern: "**/*.{graphql,gql}"
|
|
49
|
+
})),
|
|
50
|
+
warnings,
|
|
51
|
+
errors
|
|
52
|
+
};
|
|
53
|
+
} catch (error) {
|
|
54
|
+
errors.push(`GraphQL scanning error: ${error}`);
|
|
55
|
+
return {
|
|
56
|
+
items: [],
|
|
57
|
+
warnings,
|
|
58
|
+
errors
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
//#endregion
|
|
64
|
+
export { scanGraphqlCore, scanSchemasCore };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { DirectiveDefinition } from "../types/define.mjs";
|
|
2
|
+
import { GraphQLSchema } from "graphql";
|
|
3
|
+
|
|
4
|
+
//#region src/core/schema/builder.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Schema definition from virtual module
|
|
8
|
+
*/
|
|
9
|
+
interface SchemaDefinition {
|
|
10
|
+
def: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Resolver definition from virtual module
|
|
14
|
+
*/
|
|
15
|
+
interface ResolverDefinition {
|
|
16
|
+
resolver: Record<string, unknown>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Directive wrapper from virtual module
|
|
20
|
+
*/
|
|
21
|
+
interface DirectiveWrapper {
|
|
22
|
+
directive: DirectiveDefinition;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Module configuration for federation
|
|
26
|
+
*/
|
|
27
|
+
interface ModuleConfig {
|
|
28
|
+
federation?: {
|
|
29
|
+
enabled?: boolean;
|
|
30
|
+
serviceName?: string;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Options for creating a merged schema
|
|
35
|
+
*/
|
|
36
|
+
interface CreateMergedSchemaOptions {
|
|
37
|
+
schemas: SchemaDefinition[];
|
|
38
|
+
resolvers: ResolverDefinition[];
|
|
39
|
+
directives?: DirectiveWrapper[];
|
|
40
|
+
moduleConfig: ModuleConfig;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Create a merged GraphQL schema from schemas, resolvers, and directives
|
|
44
|
+
* Supports Apollo Federation when enabled
|
|
45
|
+
*/
|
|
46
|
+
declare function createMergedSchema(options: CreateMergedSchemaOptions): Promise<GraphQLSchema>;
|
|
47
|
+
/**
|
|
48
|
+
* Build a GraphQL schema from file paths (CLI usage)
|
|
49
|
+
* Reads schema files, merges them, and builds an executable schema
|
|
50
|
+
*/
|
|
51
|
+
declare function buildGraphQLSchema(schemaPaths: string[]): Promise<GraphQLSchema | null>;
|
|
52
|
+
//#endregion
|
|
53
|
+
export { CreateMergedSchemaOptions, DirectiveWrapper, ModuleConfig, ResolverDefinition, SchemaDefinition, buildGraphQLSchema, createMergedSchema };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { loadFederationSupport, warnFederationUnavailable } from "./federation.mjs";
|
|
2
|
+
import { consola as consola$1 } from "consola";
|
|
3
|
+
import { buildSchema, parse, print } from "graphql";
|
|
4
|
+
import { readFileSync } from "node:fs";
|
|
5
|
+
import { mergeResolvers, mergeTypeDefs } from "@graphql-tools/merge";
|
|
6
|
+
import { makeExecutableSchema } from "@graphql-tools/schema";
|
|
7
|
+
|
|
8
|
+
//#region src/core/schema/builder.ts
|
|
9
|
+
/**
|
|
10
|
+
* Create a merged GraphQL schema from schemas, resolvers, and directives
|
|
11
|
+
* Supports Apollo Federation when enabled
|
|
12
|
+
*/
|
|
13
|
+
async function createMergedSchema(options) {
|
|
14
|
+
const { schemas, resolvers, directives, moduleConfig } = options;
|
|
15
|
+
try {
|
|
16
|
+
const typeDefs = mergeTypeDefs([schemas.map((schema$1) => schema$1.def).join("\n\n")], {
|
|
17
|
+
throwOnConflict: true,
|
|
18
|
+
commentDescriptions: true,
|
|
19
|
+
sort: true
|
|
20
|
+
});
|
|
21
|
+
const mergedResolvers = mergeResolvers(resolvers.map((r) => r.resolver));
|
|
22
|
+
const federationEnabled = moduleConfig.federation?.enabled;
|
|
23
|
+
let schema;
|
|
24
|
+
if (federationEnabled) {
|
|
25
|
+
const buildSubgraph = await loadFederationSupport();
|
|
26
|
+
if (buildSubgraph) schema = buildSubgraph({
|
|
27
|
+
typeDefs: typeof typeDefs === "string" ? parse(typeDefs) : typeDefs,
|
|
28
|
+
resolvers: mergedResolvers
|
|
29
|
+
});
|
|
30
|
+
else {
|
|
31
|
+
warnFederationUnavailable();
|
|
32
|
+
schema = makeExecutableSchema({
|
|
33
|
+
typeDefs,
|
|
34
|
+
resolvers: mergedResolvers
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
} else schema = makeExecutableSchema({
|
|
38
|
+
typeDefs,
|
|
39
|
+
resolvers: mergedResolvers
|
|
40
|
+
});
|
|
41
|
+
if (directives && directives.length > 0) {
|
|
42
|
+
for (const { directive } of directives) if (directive.transformer) schema = directive.transformer(schema);
|
|
43
|
+
}
|
|
44
|
+
return schema;
|
|
45
|
+
} catch (error) {
|
|
46
|
+
consola$1.error("Schema merge error:", error);
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Build a GraphQL schema from file paths (CLI usage)
|
|
52
|
+
* Reads schema files, merges them, and builds an executable schema
|
|
53
|
+
*/
|
|
54
|
+
async function buildGraphQLSchema(schemaPaths) {
|
|
55
|
+
if (schemaPaths.length === 0) return null;
|
|
56
|
+
try {
|
|
57
|
+
const mergedTypeDefs = mergeTypeDefs(schemaPaths.map((path) => readFileSync(path, "utf-8")), {
|
|
58
|
+
throwOnConflict: true,
|
|
59
|
+
commentDescriptions: true,
|
|
60
|
+
sort: true
|
|
61
|
+
});
|
|
62
|
+
return buildSchema(typeof mergedTypeDefs === "string" ? mergedTypeDefs : print(mergedTypeDefs));
|
|
63
|
+
} catch (error) {
|
|
64
|
+
consola$1.error("Failed to build GraphQL schema:", error);
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
//#endregion
|
|
70
|
+
export { buildGraphQLSchema, createMergedSchema };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { DocumentNode, GraphQLSchema } from "graphql";
|
|
2
|
+
|
|
3
|
+
//#region src/core/schema/federation.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Module type for buildSubgraphSchema
|
|
7
|
+
*/
|
|
8
|
+
interface SubgraphModule {
|
|
9
|
+
typeDefs: DocumentNode;
|
|
10
|
+
resolvers?: Record<string, unknown>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Type for buildSubgraphSchema function from @apollo/subgraph
|
|
14
|
+
* Accepts either an array of modules or a single options object
|
|
15
|
+
*/
|
|
16
|
+
type BuildSubgraphSchemaFn = (modulesOrOptions: SubgraphModule[] | SubgraphModule) => GraphQLSchema;
|
|
17
|
+
/**
|
|
18
|
+
* Dynamically load @apollo/subgraph for federation support.
|
|
19
|
+
* Returns the buildSubgraphSchema function if available, or false if the package is not installed.
|
|
20
|
+
* Result is cached for subsequent calls.
|
|
21
|
+
*/
|
|
22
|
+
declare function loadFederationSupport(): Promise<BuildSubgraphSchemaFn | false>;
|
|
23
|
+
/**
|
|
24
|
+
* Log a warning when federation is enabled but @apollo/subgraph is not available.
|
|
25
|
+
* Uses consola logger instead of console.warn for consistent logging.
|
|
26
|
+
*/
|
|
27
|
+
declare function warnFederationUnavailable(): void;
|
|
28
|
+
/**
|
|
29
|
+
* Reset the federation support cache.
|
|
30
|
+
* Useful for testing or when the module needs to be reloaded.
|
|
31
|
+
*/
|
|
32
|
+
declare function resetFederationCache(): void;
|
|
33
|
+
//#endregion
|
|
34
|
+
export { loadFederationSupport, resetFederationCache, warnFederationUnavailable };
|