nitro-graphql 1.2.3 → 1.3.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.
Files changed (152) hide show
  1. package/README.md +161 -3
  2. package/dist/graphql/index.js +1 -0
  3. package/dist/graphql/server.js +1 -0
  4. package/dist/index.d.ts +4 -4
  5. package/dist/index.js +12 -3
  6. package/dist/rollup.js +32 -0
  7. package/dist/routes/apollo-server.d.ts +2 -2
  8. package/dist/routes/apollo-server.js +56 -10
  9. package/dist/routes/graphql-yoga.js +46 -6
  10. package/dist/routes/health.d.ts +2 -2
  11. package/dist/types/index.d.ts +15 -2
  12. package/dist/utils/client-codegen.js +1 -1
  13. package/dist/utils/define.d.ts +52 -1
  14. package/dist/utils/define.js +33 -1
  15. package/dist/utils/directive-parser.d.ts +80 -0
  16. package/dist/utils/directive-parser.js +235 -0
  17. package/dist/utils/index.d.ts +3 -2
  18. package/dist/utils/index.js +42 -4
  19. package/dist/utils/server-codegen.d.ts +2 -2
  20. package/dist/utils/server-codegen.js +3 -2
  21. package/dist/utils/type-generation.js +127 -7
  22. package/package.json +34 -18
  23. package/dist/_virtual/rolldown_runtime.js +0 -37
  24. package/dist/node_modules/.pnpm/@graphql-codegen_add@3.2.3_graphql@16.11.0/node_modules/@graphql-codegen/add/esm/config.js +0 -9
  25. package/dist/node_modules/.pnpm/@graphql-codegen_add@3.2.3_graphql@16.11.0/node_modules/@graphql-codegen/add/esm/index.js +0 -17
  26. package/dist/node_modules/.pnpm/@graphql-codegen_import-types-preset@3.0.1_graphql@16.11.0/node_modules/@graphql-codegen/import-types-preset/esm/index.js +0 -38
  27. package/dist/node_modules/.pnpm/@graphql-codegen_plugin-helpers@3.1.2_graphql@16.11.0/node_modules/@graphql-codegen/plugin-helpers/esm/federation.js +0 -22
  28. package/dist/node_modules/.pnpm/@graphql-codegen_plugin-helpers@3.1.2_graphql@16.11.0/node_modules/@graphql-codegen/plugin-helpers/esm/getCachedDocumentNodeFromSchema.js +0 -6
  29. package/dist/node_modules/.pnpm/@graphql-codegen_plugin-helpers@3.1.2_graphql@16.11.0/node_modules/@graphql-codegen/plugin-helpers/esm/helpers.js +0 -79
  30. package/dist/node_modules/.pnpm/@graphql-codegen_plugin-helpers@3.1.2_graphql@16.11.0/node_modules/@graphql-codegen/plugin-helpers/esm/index.js +0 -6
  31. package/dist/node_modules/.pnpm/@graphql-codegen_plugin-helpers@3.1.2_graphql@16.11.0/node_modules/@graphql-codegen/plugin-helpers/esm/oldVisit.js +0 -1
  32. package/dist/node_modules/.pnpm/@graphql-codegen_plugin-helpers@3.1.2_graphql@16.11.0/node_modules/@graphql-codegen/plugin-helpers/esm/resolve-external-module-and-fn.js +0 -7
  33. package/dist/node_modules/.pnpm/@graphql-codegen_plugin-helpers@3.1.2_graphql@16.11.0/node_modules/@graphql-codegen/plugin-helpers/esm/utils.js +0 -13
  34. package/dist/node_modules/.pnpm/camel-case@4.1.2/node_modules/camel-case/dist/index.js +0 -33
  35. package/dist/node_modules/.pnpm/capital-case@1.0.4/node_modules/capital-case/dist/index.js +0 -32
  36. package/dist/node_modules/.pnpm/change-case-all@1.0.15/node_modules/change-case-all/dist/index.js +0 -56
  37. package/dist/node_modules/.pnpm/change-case@4.1.2/node_modules/change-case/dist/index.js +0 -37
  38. package/dist/node_modules/.pnpm/constant-case@3.0.4/node_modules/constant-case/dist/index.js +0 -28
  39. package/dist/node_modules/.pnpm/dot-case@3.0.4/node_modules/dot-case/dist/index.js +0 -23
  40. package/dist/node_modules/.pnpm/header-case@2.0.4/node_modules/header-case/dist/index.js +0 -23
  41. package/dist/node_modules/.pnpm/is-lower-case@2.0.2/node_modules/is-lower-case/dist/index.js +0 -21
  42. package/dist/node_modules/.pnpm/is-upper-case@2.0.2/node_modules/is-upper-case/dist/index.js +0 -21
  43. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_Hash.js +0 -37
  44. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_ListCache.js +0 -37
  45. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_Map.js +0 -15
  46. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_MapCache.js +0 -37
  47. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_Stack.js +0 -34
  48. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_Symbol.js +0 -15
  49. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_Uint8Array.js +0 -15
  50. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_apply.js +0 -30
  51. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_arrayLikeKeys.js +0 -35
  52. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_assignMergeValue.js +0 -26
  53. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_assignValue.js +0 -32
  54. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_assocIndexOf.js +0 -26
  55. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_baseAssignValue.js +0 -31
  56. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_baseCreate.js +0 -34
  57. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_baseFor.js +0 -25
  58. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_baseGetTag.js +0 -30
  59. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_baseIsArguments.js +0 -26
  60. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_baseIsNative.js +0 -44
  61. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_baseIsTypedArray.js +0 -32
  62. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_baseKeysIn.js +0 -32
  63. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_baseMerge.js +0 -42
  64. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_baseMergeDeep.js +0 -75
  65. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_baseRest.js +0 -26
  66. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_baseSetToString.js +0 -31
  67. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_baseTimes.js +0 -25
  68. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_baseUnary.js +0 -23
  69. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_cloneArrayBuffer.js +0 -25
  70. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_cloneBuffer.js +0 -35
  71. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_cloneTypedArray.js +0 -25
  72. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_copyArray.js +0 -25
  73. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_copyObject.js +0 -37
  74. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_coreJsData.js +0 -15
  75. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_createAssigner.js +0 -37
  76. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_createBaseFor.js +0 -28
  77. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_defineProperty.js +0 -20
  78. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_freeGlobal.js +0 -13
  79. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_getMapData.js +0 -25
  80. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_getNative.js +0 -26
  81. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_getPrototype.js +0 -15
  82. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_getRawTag.js +0 -43
  83. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_getValue.js +0 -22
  84. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_hashClear.js +0 -24
  85. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_hashDelete.js +0 -26
  86. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_hashGet.js +0 -36
  87. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_hashHas.js +0 -30
  88. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_hashSet.js +0 -31
  89. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_initCloneObject.js +0 -25
  90. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_isIndex.js +0 -28
  91. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_isIterateeCall.js +0 -32
  92. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_isKeyable.js +0 -22
  93. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_isMasked.js +0 -28
  94. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_isPrototype.js +0 -24
  95. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_listCacheClear.js +0 -22
  96. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_listCacheDelete.js +0 -35
  97. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_listCacheGet.js +0 -26
  98. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_listCacheHas.js +0 -25
  99. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_listCacheSet.js +0 -31
  100. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_mapCacheClear.js +0 -30
  101. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_mapCacheDelete.js +0 -27
  102. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_mapCacheGet.js +0 -25
  103. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_mapCacheHas.js +0 -25
  104. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_mapCacheSet.js +0 -29
  105. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_nativeCreate.js +0 -14
  106. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_nativeKeysIn.js +0 -25
  107. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_nodeUtil.js +0 -29
  108. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_objectToString.js +0 -29
  109. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_overArg.js +0 -24
  110. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_overRest.js +0 -35
  111. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_root.js +0 -17
  112. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_safeGet.js +0 -24
  113. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_setToString.js +0 -23
  114. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_shortOut.js +0 -34
  115. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_stackClear.js +0 -24
  116. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_stackDelete.js +0 -25
  117. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_stackGet.js +0 -23
  118. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_stackHas.js +0 -23
  119. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_stackSet.js +0 -42
  120. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/_toSource.js +0 -33
  121. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/constant.js +0 -35
  122. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/eq.js +0 -46
  123. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/identity.js +0 -30
  124. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/isArguments.js +0 -43
  125. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/isArray.js +0 -35
  126. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/isArrayLike.js +0 -42
  127. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/isArrayLikeObject.js +0 -42
  128. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/isBuffer.js +0 -41
  129. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/isFunction.js +0 -38
  130. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/isLength.js +0 -42
  131. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/isObject.js +0 -40
  132. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/isObjectLike.js +0 -38
  133. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/isPlainObject.js +0 -60
  134. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/isTypedArray.js +0 -34
  135. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/keysIn.js +0 -41
  136. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/merge.js +0 -48
  137. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/stubFalse.js +0 -27
  138. package/dist/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/toPlainObject.js +0 -41
  139. package/dist/node_modules/.pnpm/lower-case-first@2.0.2/node_modules/lower-case-first/dist/index.js +0 -21
  140. package/dist/node_modules/.pnpm/lower-case@2.0.2/node_modules/lower-case/dist/index.js +0 -64
  141. package/dist/node_modules/.pnpm/no-case@3.0.4/node_modules/no-case/dist/index.js +0 -41
  142. package/dist/node_modules/.pnpm/param-case@3.0.4/node_modules/param-case/dist/index.js +0 -23
  143. package/dist/node_modules/.pnpm/pascal-case@3.1.2/node_modules/pascal-case/dist/index.js +0 -37
  144. package/dist/node_modules/.pnpm/path-case@3.0.4/node_modules/path-case/dist/index.js +0 -23
  145. package/dist/node_modules/.pnpm/sentence-case@3.0.4/node_modules/sentence-case/dist/index.js +0 -34
  146. package/dist/node_modules/.pnpm/snake-case@3.0.4/node_modules/snake-case/dist/index.js +0 -23
  147. package/dist/node_modules/.pnpm/sponge-case@1.0.1/node_modules/sponge-case/dist/index.js +0 -20
  148. package/dist/node_modules/.pnpm/swap-case@2.0.2/node_modules/swap-case/dist/index.js +0 -23
  149. package/dist/node_modules/.pnpm/title-case@3.0.3/node_modules/title-case/dist/index.js +0 -35
  150. package/dist/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib/tslib.es6.js +0 -547
  151. package/dist/node_modules/.pnpm/upper-case-first@2.0.2/node_modules/upper-case-first/dist/index.js +0 -21
  152. package/dist/node_modules/.pnpm/upper-case@2.0.2/node_modules/upper-case/dist/index.js +0 -56
@@ -20,6 +20,38 @@ function defineType(resolvers) {
20
20
  function defineGraphQLConfig(config) {
21
21
  return config;
22
22
  }
23
+ /**
24
+ * Helper function to create directive arguments with proper type inference
25
+ * @example
26
+ * args: {
27
+ * myArg: arg('String!', { defaultValue: 'hello' })
28
+ * }
29
+ */
30
+ function arg(type, options) {
31
+ return {
32
+ type,
33
+ ...options
34
+ };
35
+ }
36
+ function defineDirective(config) {
37
+ const args = config.args ? Object.entries(config.args).map(([name, arg$1]) => {
38
+ const defaultValue = arg$1.defaultValue !== void 0 ? ` = ${JSON.stringify(arg$1.defaultValue)}` : "";
39
+ return `${name}: ${arg$1.type}${defaultValue}`;
40
+ }).join(", ") : "";
41
+ const argsString = args ? `(${args})` : "";
42
+ const locations = config.locations.join(" | ");
43
+ const schemaDefinition = `directive @${config.name}${argsString} on ${locations}`;
44
+ Object.defineProperty(config, "__schema", {
45
+ value: schemaDefinition,
46
+ enumerable: false,
47
+ configurable: false,
48
+ writable: false
49
+ });
50
+ return {
51
+ ...config,
52
+ locations: [...config.locations]
53
+ };
54
+ }
23
55
 
24
56
  //#endregion
25
- export { defineGraphQLConfig, defineMutation, defineQuery, defineResolver, defineSchema, defineSubscription, defineType };
57
+ export { arg, defineDirective, defineGraphQLConfig, defineMutation, defineQuery, defineResolver, defineSchema, defineSubscription, defineType };
@@ -0,0 +1,80 @@
1
+ //#region src/utils/directive-parser.d.ts
2
+ interface ParsedDirective {
3
+ name: string;
4
+ locations: string[];
5
+ args?: Record<string, {
6
+ type: string;
7
+ defaultValue?: any;
8
+ }>;
9
+ description?: string;
10
+ isRepeatable?: boolean;
11
+ }
12
+ /**
13
+ * Clean AST-based directive parser using oxc-parser
14
+ */
15
+ declare class DirectiveParser {
16
+ private oxc;
17
+ init(): Promise<void>;
18
+ /**
19
+ * Parse directives from a TypeScript/JavaScript file
20
+ */
21
+ parseDirectives(fileContent: string, filePath: string): Promise<ParsedDirective[]>;
22
+ /**
23
+ * Extract directive definitions from AST
24
+ */
25
+ private extractDirectiveDefinitions;
26
+ /**
27
+ * Traverse AST nodes recursively
28
+ */
29
+ private traverse;
30
+ /**
31
+ * Check if node is a defineDirective call
32
+ */
33
+ private isDefineDirectiveCall;
34
+ /**
35
+ * Extract directive configuration from defineDirective call
36
+ */
37
+ private extractDirectiveFromCall;
38
+ /**
39
+ * Extract directive properties from object expression
40
+ */
41
+ private extractDirectiveFromObject;
42
+ /**
43
+ * Extract string literal value
44
+ */
45
+ private extractStringLiteral;
46
+ /**
47
+ * Extract boolean literal value
48
+ */
49
+ private extractBooleanLiteral;
50
+ /**
51
+ * Extract array of strings
52
+ */
53
+ private extractStringArray;
54
+ /**
55
+ * Extract arguments object
56
+ */
57
+ private extractArgsObject;
58
+ /**
59
+ * Extract argument configuration
60
+ */
61
+ private extractArgConfig;
62
+ /**
63
+ * Extract literal value (string, number, boolean)
64
+ */
65
+ private extractLiteralValue;
66
+ }
67
+ /**
68
+ * Generate GraphQL directive schema from parsed directive
69
+ */
70
+ declare function generateDirectiveSchema(directive: ParsedDirective): string;
71
+ /**
72
+ * Generate directive schemas file from scanned directives
73
+ */
74
+ declare function generateDirectiveSchemas(nitro: any, directives: any[]): Promise<void>;
75
+ /**
76
+ * Singleton instance for reuse
77
+ */
78
+ declare const directiveParser: DirectiveParser;
79
+ //#endregion
80
+ export { DirectiveParser, ParsedDirective, directiveParser, generateDirectiveSchema, generateDirectiveSchemas };
@@ -0,0 +1,235 @@
1
+ //#region src/utils/directive-parser.ts
2
+ /**
3
+ * Clean AST-based directive parser using oxc-parser
4
+ */
5
+ var DirectiveParser = class {
6
+ oxc;
7
+ async init() {
8
+ if (!this.oxc) this.oxc = await import("oxc-parser");
9
+ }
10
+ /**
11
+ * Parse directives from a TypeScript/JavaScript file
12
+ */
13
+ async parseDirectives(fileContent, filePath) {
14
+ await this.init();
15
+ try {
16
+ const result = this.oxc.parseSync(filePath, fileContent, {
17
+ lang: filePath.endsWith(".ts") ? "ts" : "js",
18
+ sourceType: "module",
19
+ astType: "ts"
20
+ });
21
+ if (result.errors.length > 0) {
22
+ console.warn(`Parse errors in ${filePath}:`, result.errors.map((e) => e.message));
23
+ return [];
24
+ }
25
+ return this.extractDirectiveDefinitions(result.program);
26
+ } catch (error) {
27
+ console.warn(`Failed to parse ${filePath} with oxc:`, error);
28
+ return [];
29
+ }
30
+ }
31
+ /**
32
+ * Extract directive definitions from AST
33
+ */
34
+ extractDirectiveDefinitions(program) {
35
+ const directives = [];
36
+ this.traverse(program, (node) => {
37
+ if (this.isDefineDirectiveCall(node)) {
38
+ const directive = this.extractDirectiveFromCall(node);
39
+ if (directive) directives.push(directive);
40
+ }
41
+ });
42
+ return directives;
43
+ }
44
+ /**
45
+ * Traverse AST nodes recursively
46
+ */
47
+ traverse(node, visitor) {
48
+ if (!node || typeof node !== "object") return;
49
+ visitor(node);
50
+ for (const key in node) {
51
+ const child = node[key];
52
+ if (Array.isArray(child)) child.forEach((item) => this.traverse(item, visitor));
53
+ else if (child && typeof child === "object") this.traverse(child, visitor);
54
+ }
55
+ }
56
+ /**
57
+ * Check if node is a defineDirective call
58
+ */
59
+ isDefineDirectiveCall(node) {
60
+ return node.type === "CallExpression" && node.callee?.type === "Identifier" && node.callee.name === "defineDirective" && node.arguments?.length > 0;
61
+ }
62
+ /**
63
+ * Extract directive configuration from defineDirective call
64
+ */
65
+ extractDirectiveFromCall(node) {
66
+ const arg = node.arguments[0];
67
+ if (arg?.type !== "ObjectExpression") return null;
68
+ return this.extractDirectiveFromObject(arg);
69
+ }
70
+ /**
71
+ * Extract directive properties from object expression
72
+ */
73
+ extractDirectiveFromObject(objNode) {
74
+ let name = "";
75
+ let locations = [];
76
+ let args = {};
77
+ let description;
78
+ let isRepeatable;
79
+ for (const prop of objNode.properties || []) {
80
+ if (prop.type !== "Property" || prop.key?.type !== "Identifier") continue;
81
+ switch (prop.key.name) {
82
+ case "name":
83
+ name = this.extractStringLiteral(prop.value) || "";
84
+ break;
85
+ case "locations":
86
+ locations = this.extractStringArray(prop.value);
87
+ break;
88
+ case "args":
89
+ args = this.extractArgsObject(prop.value);
90
+ break;
91
+ case "description":
92
+ description = this.extractStringLiteral(prop.value);
93
+ break;
94
+ case "isRepeatable":
95
+ isRepeatable = this.extractBooleanLiteral(prop.value);
96
+ break;
97
+ }
98
+ }
99
+ return name && locations.length > 0 ? {
100
+ name,
101
+ locations,
102
+ args,
103
+ description,
104
+ isRepeatable
105
+ } : null;
106
+ }
107
+ /**
108
+ * Extract string literal value
109
+ */
110
+ extractStringLiteral(node) {
111
+ if (node?.type === "Literal" && typeof node.value === "string") return node.value;
112
+ return void 0;
113
+ }
114
+ /**
115
+ * Extract boolean literal value
116
+ */
117
+ extractBooleanLiteral(node) {
118
+ if (node?.type === "Literal" && typeof node.value === "boolean") return node.value;
119
+ return void 0;
120
+ }
121
+ /**
122
+ * Extract array of strings
123
+ */
124
+ extractStringArray(node) {
125
+ if (node?.type !== "ArrayExpression") return [];
126
+ return (node.elements || []).filter((el) => el?.type === "Literal" && typeof el.value === "string").map((el) => el.value);
127
+ }
128
+ /**
129
+ * Extract arguments object
130
+ */
131
+ extractArgsObject(node) {
132
+ if (node?.type !== "ObjectExpression") return {};
133
+ const args = {};
134
+ for (const prop of node.properties || []) {
135
+ if (prop.type !== "Property" || prop.key?.type !== "Identifier") continue;
136
+ const argName = prop.key.name;
137
+ const argConfig = this.extractArgConfig(prop.value);
138
+ if (argConfig) args[argName] = argConfig;
139
+ }
140
+ return args;
141
+ }
142
+ /**
143
+ * Extract argument configuration
144
+ */
145
+ extractArgConfig(node) {
146
+ if (node?.type !== "ObjectExpression") return null;
147
+ let type = "String";
148
+ let defaultValue;
149
+ for (const prop of node.properties || []) {
150
+ if (prop.type !== "Property" || prop.key?.type !== "Identifier") continue;
151
+ switch (prop.key.name) {
152
+ case "type": {
153
+ const typeValue = this.extractStringLiteral(prop.value);
154
+ if (typeValue) type = typeValue;
155
+ break;
156
+ }
157
+ case "defaultValue":
158
+ defaultValue = this.extractLiteralValue(prop.value);
159
+ break;
160
+ }
161
+ }
162
+ return {
163
+ type,
164
+ ...defaultValue !== void 0 && { defaultValue }
165
+ };
166
+ }
167
+ /**
168
+ * Extract literal value (string, number, boolean)
169
+ */
170
+ extractLiteralValue(node) {
171
+ if (node?.type === "Literal") return node.value;
172
+ return void 0;
173
+ }
174
+ };
175
+ /**
176
+ * Generate GraphQL directive schema from parsed directive
177
+ */
178
+ function generateDirectiveSchema(directive) {
179
+ let args = "";
180
+ if (directive.args && Object.keys(directive.args).length > 0) {
181
+ const argDefs = Object.entries(directive.args).map(([name, arg]) => {
182
+ let defaultValue = "";
183
+ if (arg.defaultValue !== void 0) if (typeof arg.defaultValue === "string") defaultValue = ` = "${arg.defaultValue}"`;
184
+ else defaultValue = ` = ${arg.defaultValue}`;
185
+ return `${name}: ${arg.type}${defaultValue}`;
186
+ });
187
+ args = `(${argDefs.join(", ")})`;
188
+ }
189
+ const locations = directive.locations.join(" | ");
190
+ return `directive @${directive.name}${args} on ${locations}`;
191
+ }
192
+ /**
193
+ * Generate directive schemas file from scanned directives
194
+ */
195
+ async function generateDirectiveSchemas(nitro, directives) {
196
+ if (directives.length === 0) return;
197
+ const { existsSync, readFileSync, writeFileSync } = await import("node:fs");
198
+ const { readFile } = await import("node:fs/promises");
199
+ const { resolve } = await import("pathe");
200
+ const directiveSchemas = [];
201
+ const seenDirectives = /* @__PURE__ */ new Set();
202
+ const parser = new DirectiveParser();
203
+ for (const dir of directives) for (const _imp of dir.imports) {
204
+ const fileContent = await readFile(dir.specifier, "utf-8");
205
+ const directiveDefs = await parser.parseDirectives(fileContent, dir.specifier);
206
+ for (const def of directiveDefs) {
207
+ if (seenDirectives.has(def.name)) continue;
208
+ seenDirectives.add(def.name);
209
+ const schema = generateDirectiveSchema(def);
210
+ directiveSchemas.push(schema);
211
+ }
212
+ }
213
+ if (directiveSchemas.length > 0) {
214
+ const directivesPath = resolve(nitro.graphql.serverDir, "_directives.graphql");
215
+ const content = `# WARNING: This file is auto-generated by nitro-graphql
216
+ # Do not modify this file directly. It will be overwritten.
217
+ # To define custom directives, create .directive.ts files using defineDirective()
218
+
219
+ ${directiveSchemas.join("\n\n")}`;
220
+ let shouldWrite = true;
221
+ if (existsSync(directivesPath)) {
222
+ const existingContent = readFileSync(directivesPath, "utf-8");
223
+ shouldWrite = existingContent !== content;
224
+ }
225
+ if (shouldWrite) writeFileSync(directivesPath, content, "utf-8");
226
+ if (!nitro.scanSchemas.includes(directivesPath)) nitro.scanSchemas.push(directivesPath);
227
+ }
228
+ }
229
+ /**
230
+ * Singleton instance for reuse
231
+ */
232
+ const directiveParser = new DirectiveParser();
233
+
234
+ //#endregion
235
+ export { DirectiveParser, directiveParser, generateDirectiveSchema, generateDirectiveSchemas };
@@ -1,4 +1,5 @@
1
1
  import { GenImport } from "../types/index.js";
2
+ import { directiveParser, generateDirectiveSchema, generateDirectiveSchemas } from "./directive-parser.js";
2
3
  import { Nitro } from "nitropack";
3
4
 
4
5
  //#region src/utils/index.d.ts
@@ -7,7 +8,7 @@ declare function getImportId(p: string, lazy?: boolean): string;
7
8
  declare function relativeWithDot(from: string, to: string): string;
8
9
  declare function scanGraphql(nitro: Nitro): Promise<string[]>;
9
10
  declare function scanResolvers(nitro: Nitro): Promise<GenImport[]>;
10
- declare function scanDirectives(nitro: Nitro): Promise<string[]>;
11
+ declare function scanDirectives(nitro: Nitro): Promise<GenImport[]>;
11
12
  declare function scanTypeDefs(nitro: Nitro): Promise<string[]>;
12
13
  declare function scanSchemas(nitro: Nitro): Promise<string[]>;
13
14
  declare function scanDocs(nitro: Nitro): Promise<string[]>;
@@ -20,4 +21,4 @@ declare function scanExternalServiceDocs(nitro: Nitro, serviceName: string, patt
20
21
  */
21
22
  declare function validateExternalServices(services: any[]): string[];
22
23
  //#endregion
23
- export { GLOB_SCAN_PATTERN, getImportId, relativeWithDot, scanDirectives, scanDocs, scanExternalServiceDocs, scanGraphql, scanResolvers, scanSchemas, scanTypeDefs, validateExternalServices };
24
+ export { GLOB_SCAN_PATTERN, directiveParser, generateDirectiveSchema, generateDirectiveSchemas, getImportId, relativeWithDot, scanDirectives, scanDocs, scanExternalServiceDocs, scanGraphql, scanResolvers, scanSchemas, scanTypeDefs, validateExternalServices };
@@ -1,3 +1,4 @@
1
+ import { directiveParser, generateDirectiveSchema, generateDirectiveSchemas } from "./directive-parser.js";
1
2
  import { join, relative } from "pathe";
2
3
  import { readFile } from "node:fs/promises";
3
4
  import { hash } from "ohash";
@@ -56,6 +57,11 @@ async function scanResolvers(nitro) {
56
57
  type: "subscription",
57
58
  as: `_${hash(decl.id.name + file.path).replace(/-/g, "").slice(0, 6)}`
58
59
  });
60
+ if (decl.init.callee.type === "Identifier" && decl.init.callee.name === "defineDirective") exports.imports.push({
61
+ name: decl.id.name,
62
+ type: "directive",
63
+ as: `_${hash(decl.id.name + file.path).replace(/-/g, "").slice(0, 6)}`
64
+ });
59
65
  }
60
66
  }
61
67
  }
@@ -65,7 +71,28 @@ async function scanResolvers(nitro) {
65
71
  }
66
72
  async function scanDirectives(nitro) {
67
73
  const files = await scanFiles(nitro, "graphql", "**/*.directive.{ts,js}");
68
- return files.map((f) => f.fullPath);
74
+ const exportName = [];
75
+ for (const file of files) {
76
+ const fileContent = await readFile(file.fullPath, "utf-8");
77
+ const parsed = await parseAsync(file.fullPath, fileContent);
78
+ const exports = {
79
+ imports: [],
80
+ specifier: file.fullPath
81
+ };
82
+ for (const node of parsed.program.body) if (node.type === "ExportNamedDeclaration" && node.declaration && node.declaration.type === "VariableDeclaration") {
83
+ for (const decl of node.declaration.declarations) if (decl.type === "VariableDeclarator" && decl.init && decl.id.type === "Identifier") {
84
+ if (decl.init && decl.init.type === "CallExpression") {
85
+ if (decl.init.callee.type === "Identifier" && decl.init.callee.name === "defineDirective") exports.imports.push({
86
+ name: decl.id.name,
87
+ type: "directive",
88
+ as: `_${hash(decl.id.name + file.path).replace(/-/g, "").slice(0, 6)}`
89
+ });
90
+ }
91
+ }
92
+ }
93
+ if (exports.imports.length > 0) exportName.push(exports);
94
+ }
95
+ return exportName;
69
96
  }
70
97
  async function scanTypeDefs(nitro) {
71
98
  const files = await scanFiles(nitro, "graphql", "**/*.typedef.{ts,js}");
@@ -77,7 +104,18 @@ async function scanSchemas(nitro) {
77
104
  }
78
105
  async function scanDocs(nitro) {
79
106
  const files = await scanDir(nitro, nitro.options.rootDir, nitro.graphql.dir.client, "**/*.graphql");
80
- return files.filter((f) => !f.path.startsWith("external/")).map((f) => f.fullPath);
107
+ const externalServices = nitro.options.graphql?.externalServices || [];
108
+ const externalPatterns = externalServices.flatMap((service) => service.documents || []);
109
+ return files.filter((f) => !f.path.startsWith("external/")).filter((f) => {
110
+ const relativePath = f.path;
111
+ for (const pattern of externalPatterns) {
112
+ const cleanPattern = pattern.replace(/^app\/graphql\//, "");
113
+ const patternDir = cleanPattern.split("/")[0];
114
+ const fileDir = relativePath.split("/")[0];
115
+ if (patternDir === fileDir) return false;
116
+ }
117
+ return true;
118
+ }).map((f) => f.fullPath);
81
119
  }
82
120
  /**
83
121
  * Scan documents for a specific external service
@@ -112,7 +150,7 @@ function validateExternalServices(services) {
112
150
  if (!service.schema) errors.push(`${prefix}.schema is required`);
113
151
  if (!service.endpoint || typeof service.endpoint !== "string") errors.push(`${prefix}.endpoint is required and must be a string`);
114
152
  else try {
115
- const url = new URL(service.endpoint);
153
+ new URL(service.endpoint);
116
154
  } catch {
117
155
  errors.push(`${prefix}.endpoint "${service.endpoint}" must be a valid URL`);
118
156
  }
@@ -146,4 +184,4 @@ async function scanDir(nitro, dir, name, globPattern = GLOB_SCAN_PATTERN) {
146
184
  }
147
185
 
148
186
  //#endregion
149
- export { GLOB_SCAN_PATTERN, getImportId, relativeWithDot, scanDirectives, scanDocs, scanExternalServiceDocs, scanGraphql, scanResolvers, scanSchemas, scanTypeDefs, validateExternalServices };
187
+ export { GLOB_SCAN_PATTERN, directiveParser, generateDirectiveSchema, generateDirectiveSchemas, getImportId, relativeWithDot, scanDirectives, scanDocs, scanExternalServiceDocs, scanGraphql, scanResolvers, scanSchemas, scanTypeDefs, validateExternalServices };
@@ -1,7 +1,7 @@
1
- import { CodegenServerConfig } from "../types/index.js";
1
+ import { NitroGraphQLOptions } from "../types/index.js";
2
2
  import { GraphQLSchema } from "graphql";
3
3
 
4
4
  //#region src/utils/server-codegen.d.ts
5
- declare function generateTypes(selectFremework: string, schema: GraphQLSchema, config?: CodegenServerConfig, outputPath?: string): Promise<string>;
5
+ declare function generateTypes(selectFremework: string, schema: GraphQLSchema, config?: Partial<NitroGraphQLOptions>, outputPath?: string): Promise<string>;
6
6
  //#endregion
7
7
  export { generateTypes };
@@ -41,9 +41,10 @@ async function generateTypes(selectFremework, schema, config = {}, outputPath) {
41
41
  maybeValue: "T | null | undefined",
42
42
  inputMaybeValue: "T | undefined",
43
43
  declarationKind: "interface",
44
- enumsAsTypes: true
44
+ enumsAsTypes: true,
45
+ ...config.federation?.enabled && { federation: true }
45
46
  };
46
- const mergedConfig = defu$1(defaultConfig, config);
47
+ const mergedConfig = defu$1(defaultConfig, config.codegen?.server);
47
48
  const output = await codegen({
48
49
  filename: outputPath || "types.generated.ts",
49
50
  schema: parse(printSchemaWithDirectives(schema)),
@@ -2,8 +2,8 @@ import { downloadAndSaveSchema, generateClientTypes, generateExternalClientTypes
2
2
  import { generateTypes } from "./server-codegen.js";
3
3
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
4
4
  import consola from "consola";
5
- import { dirname, join, resolve } from "pathe";
6
- import { buildASTSchema, buildSchema } from "graphql";
5
+ import { basename, dirname, join, resolve } from "pathe";
6
+ import { buildSchema, parse } from "graphql";
7
7
  import { loadFilesSync } from "@graphql-tools/load-files";
8
8
  import { mergeTypeDefs } from "@graphql-tools/merge";
9
9
  import { printSchemaWithDirectives } from "@graphql-tools/utils";
@@ -89,6 +89,98 @@ export const $${serviceName}Sdk: Sdk = getSdk(create${capitalizedServiceName}Gra
89
89
  writeFileSync(ofetchPath, ofetchContent, "utf-8");
90
90
  }
91
91
  }
92
+ /**
93
+ * Check for duplicate type definitions using a simpler approach
94
+ * Try to build each schema individually - if that succeeds but merging fails, we have duplicates
95
+ * @returns true if validation passes, false if duplicates found
96
+ */
97
+ function validateNoDuplicateTypes(schemas, schemaStrings) {
98
+ const individualSchemasByFile = /* @__PURE__ */ new Map();
99
+ schemaStrings.forEach((schemaContent, index) => {
100
+ const schemaPath = schemas[index];
101
+ const fileName = basename(schemaPath);
102
+ try {
103
+ parse(schemaContent);
104
+ individualSchemasByFile.set(fileName, schemaContent);
105
+ } catch (error) {
106
+ consola.warn(`Invalid GraphQL syntax in ${fileName}:`, error);
107
+ throw error;
108
+ }
109
+ });
110
+ try {
111
+ mergeTypeDefs([schemaStrings.join("\n\n")], {
112
+ throwOnConflict: false,
113
+ commentDescriptions: true,
114
+ sort: true
115
+ });
116
+ mergeTypeDefs([schemaStrings.join("\n\n")], {
117
+ throwOnConflict: true,
118
+ commentDescriptions: true,
119
+ sort: true
120
+ });
121
+ } catch (conflictError) {
122
+ if (conflictError?.message?.includes("already defined with a different type")) throw conflictError;
123
+ }
124
+ const typeNames = /* @__PURE__ */ new Set();
125
+ const duplicateTypes = [];
126
+ schemaStrings.forEach((schemaContent, index) => {
127
+ const fileName = basename(schemas[index]);
128
+ try {
129
+ const document = parse(schemaContent);
130
+ document.definitions.forEach((def) => {
131
+ if (def.kind === "ObjectTypeDefinition" || def.kind === "InterfaceTypeDefinition" || def.kind === "UnionTypeDefinition" || def.kind === "EnumTypeDefinition" || def.kind === "InputObjectTypeDefinition" || def.kind === "ScalarTypeDefinition") {
132
+ const typeName = def.name.value;
133
+ if ([
134
+ "String",
135
+ "Int",
136
+ "Float",
137
+ "Boolean",
138
+ "ID",
139
+ "DateTime",
140
+ "JSON"
141
+ ].includes(typeName)) return;
142
+ if (typeNames.has(typeName)) {
143
+ const existing = duplicateTypes.find((d) => d.type === typeName);
144
+ if (existing) existing.files.push(fileName);
145
+ else {
146
+ const firstFile = schemas.find((_, i) => {
147
+ const content = schemaStrings[i];
148
+ if (!content) return false;
149
+ try {
150
+ const doc = parse(content);
151
+ return doc.definitions.some((d) => (d.kind === "ObjectTypeDefinition" || d.kind === "InterfaceTypeDefinition" || d.kind === "UnionTypeDefinition" || d.kind === "EnumTypeDefinition" || d.kind === "InputObjectTypeDefinition" || d.kind === "ScalarTypeDefinition") && d.name.value === typeName);
152
+ } catch {
153
+ return false;
154
+ }
155
+ });
156
+ duplicateTypes.push({
157
+ type: typeName,
158
+ files: [basename(firstFile || ""), fileName]
159
+ });
160
+ }
161
+ } else typeNames.add(typeName);
162
+ }
163
+ });
164
+ } catch {}
165
+ });
166
+ if (duplicateTypes.length > 0) {
167
+ let errorMessage = "⚠️ DUPLICATE TYPE DEFINITIONS DETECTED!\n\n";
168
+ duplicateTypes.forEach(({ type, files }) => {
169
+ errorMessage += `❌ Type "${type}" is defined in multiple files:\n`;
170
+ files.forEach((fileName) => {
171
+ const fullPath = schemas.find((path) => basename(path) === fileName) || fileName;
172
+ errorMessage += ` • ${fullPath}\n`;
173
+ });
174
+ errorMessage += "\n";
175
+ });
176
+ errorMessage += "💡 Each GraphQL type should only be defined once.\n";
177
+ errorMessage += " Consider using \"extend type\" syntax instead of duplicate definitions.\n";
178
+ errorMessage += `\n🔍 Found ${duplicateTypes.length} duplicate type(s): ${duplicateTypes.map((d) => d.type).join(", ")}`;
179
+ consola.error(errorMessage);
180
+ return false;
181
+ }
182
+ return true;
183
+ }
92
184
  async function serverTypeGeneration(app) {
93
185
  try {
94
186
  const schemas = app.scanSchemas || [];
@@ -97,12 +189,40 @@ async function serverTypeGeneration(app) {
97
189
  return;
98
190
  }
99
191
  const loadSchemas = loadFilesSync(schemas);
100
- const mergedSchemas = mergeTypeDefs(loadSchemas);
101
- const schema = buildASTSchema(mergedSchemas, {
102
- assumeValidSDL: true,
103
- assumeValid: true
192
+ const schemaStrings = loadSchemas.map((schema$1) => typeof schema$1 === "string" ? schema$1 : schema$1.loc?.source?.body || "").filter(Boolean);
193
+ const isValid = validateNoDuplicateTypes(schemas, schemaStrings);
194
+ if (!isValid) return;
195
+ const mergedSchemasString = schemaStrings.join("\n\n");
196
+ const federationEnabled = app.options.graphql?.federation?.enabled === true;
197
+ let schemaWithDirectives = mergedSchemasString;
198
+ if (federationEnabled) {
199
+ const federationDirectives = `
200
+ directive @key(fields: String!) on OBJECT | INTERFACE
201
+ directive @requires(fields: String!) on FIELD_DEFINITION
202
+ directive @provides(fields: String!) on FIELD_DEFINITION
203
+ directive @external on FIELD_DEFINITION | OBJECT
204
+ directive @tag(name: String!) on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
205
+ directive @extends on OBJECT | INTERFACE
206
+ directive @shareable on FIELD_DEFINITION | OBJECT
207
+ directive @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
208
+ directive @override(from: String!) on FIELD_DEFINITION
209
+ directive @composeDirective(name: String!) on SCHEMA
210
+ directive @link(url: String!, as: String, for: Purpose, import: [String!]) on SCHEMA
211
+
212
+ enum Purpose {
213
+ SECURITY
214
+ EXECUTION
215
+ }
216
+ `;
217
+ schemaWithDirectives = `${federationDirectives}\n\n${mergedSchemasString}`;
218
+ }
219
+ const mergedSchemas = mergeTypeDefs([schemaWithDirectives], {
220
+ throwOnConflict: true,
221
+ commentDescriptions: true,
222
+ sort: true
104
223
  });
105
- const data = await generateTypes(app.options.graphql?.framework || "graphql-yoga", schema, app.options.graphql?.codegen?.server ?? {});
224
+ const schema = buildSchema(mergedSchemas);
225
+ const data = await generateTypes(app.options.graphql?.framework || "graphql-yoga", schema, app.options.graphql ?? {});
106
226
  const printSchema = printSchemaWithDirectives(schema);
107
227
  const schemaPath = resolve(app.graphql.buildDir, "schema.graphql");
108
228
  mkdirSync(dirname(schemaPath), { recursive: true });