eddev 2.0.0-beta.9 → 2.0.0-beta.91

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 (210) hide show
  1. package/dist/app/entry/HydrationOverlay.d.ts +1 -0
  2. package/dist/app/entry/HydrationOverlay.js +2 -0
  3. package/dist/app/entry/MetaTags.d.ts +7 -0
  4. package/dist/app/entry/MetaTags.js +17 -0
  5. package/dist/app/entry/boot-admin.js +11 -6
  6. package/dist/app/entry/hydration-script.d.ts +1 -0
  7. package/dist/app/entry/hydration-script.js +18 -0
  8. package/dist/app/entry/spa-root.js +4 -5
  9. package/dist/app/entry/ssr-root-client.d.ts +3 -1
  10. package/dist/app/entry/ssr-root-client.js +24 -8
  11. package/dist/app/entry/ssr-root.d.ts +5 -4
  12. package/dist/app/entry/ssr-root.js +21 -20
  13. package/dist/app/lib/admin/index.d.ts +2 -2
  14. package/dist/app/lib/admin/index.js +2 -2
  15. package/dist/app/lib/admin/installFieldTypes.js +1 -1
  16. package/dist/app/lib/admin/runWidgets.js +1 -1
  17. package/dist/app/lib/blocks/ContentBlocks.d.ts +1 -1
  18. package/dist/app/lib/blocks/ContentBlocks.js +5 -5
  19. package/dist/app/lib/blocks/EditableText.d.ts +1 -1
  20. package/dist/app/lib/blocks/EditableText.js +3 -3
  21. package/dist/app/lib/blocks/InnerBlocks.d.ts +13 -3
  22. package/dist/app/lib/blocks/InnerBlocks.js +13 -5
  23. package/dist/app/lib/blocks/block-utils.d.ts +2 -2
  24. package/dist/app/lib/blocks/block-utils.js +2 -2
  25. package/dist/app/lib/blocks/editor/EditorHighlights.d.ts +7 -0
  26. package/dist/app/lib/blocks/editor/EditorHighlights.js +130 -0
  27. package/dist/app/lib/blocks/editor/EditorSupport.js +4 -5
  28. package/dist/app/lib/blocks/editor/ErrorBoundaryEditor.d.ts +1 -1
  29. package/dist/app/lib/blocks/editor/editor-config.d.ts +17 -4
  30. package/dist/app/lib/blocks/editor/editor-config.js +21 -9
  31. package/dist/app/lib/blocks/editor/installGutenbergHooks.js +20 -14
  32. package/dist/app/lib/blocks/editor/root-blocks.d.ts +6 -0
  33. package/dist/app/lib/blocks/editor/root-blocks.js +30 -0
  34. package/dist/app/lib/blocks/editor/usePostEditor.d.ts +1 -1
  35. package/dist/app/lib/blocks/index.d.ts +9 -9
  36. package/dist/app/lib/blocks/index.js +9 -9
  37. package/dist/app/lib/blocks/inline-editing.d.ts +1 -1
  38. package/dist/app/lib/blocks/inline-editing.js +7 -5
  39. package/dist/app/lib/devtools/components/BreakpointIndicator.js +1 -1
  40. package/dist/app/lib/devtools/components/DevUI.js +4 -3
  41. package/dist/app/lib/devtools/components/GridIndicator.d.ts +1 -0
  42. package/dist/app/lib/devtools/components/GridIndicator.js +29 -0
  43. package/dist/app/lib/devtools/hooks/usePersistState.d.ts +1 -1
  44. package/dist/app/lib/devtools/hooks/usePersistState.js +11 -2
  45. package/dist/app/lib/devtools/hooks/useTailwind.d.ts +1014 -1014
  46. package/dist/app/lib/devtools/hooks/useTailwind.js +1 -1
  47. package/dist/app/lib/devtools/index.d.ts +1 -1
  48. package/dist/app/lib/devtools/index.js +1 -1
  49. package/dist/app/lib/devtools/loader.js +8 -7
  50. package/dist/app/lib/devtools/useQueryDebug.d.ts +7 -1
  51. package/dist/app/lib/devtools/useQueryDebug.js +5 -8
  52. package/dist/app/lib/dynamic/dynamic.d.ts +1 -1
  53. package/dist/app/lib/dynamic/dynamic.js +5 -1
  54. package/dist/app/lib/dynamic/index.d.ts +1 -1
  55. package/dist/app/lib/dynamic/index.js +1 -1
  56. package/dist/app/lib/hooks/index.d.ts +4 -5
  57. package/dist/app/lib/hooks/index.js +4 -5
  58. package/dist/app/lib/hooks/queryUtils.d.ts +37 -3
  59. package/dist/app/lib/hooks/queryUtils.js +66 -26
  60. package/dist/app/lib/hooks/useAppData.js +1 -1
  61. package/dist/app/lib/hooks/useRPC.d.ts +0 -4
  62. package/dist/app/lib/hooks/useRPC.js +1 -8
  63. package/dist/app/lib/internal/finalize-rpc.d.ts +17 -0
  64. package/dist/app/lib/internal/finalize-rpc.js +3 -0
  65. package/dist/app/lib/internal/index.d.ts +5 -4
  66. package/dist/app/lib/internal/index.js +5 -4
  67. package/dist/app/lib/internal/read-admin-manifest.d.ts +1 -1
  68. package/dist/app/lib/legacy-stitches/createStitches.d.ts +21 -21
  69. package/dist/app/lib/legacy-stitches/createStitches.js +1 -1
  70. package/dist/app/lib/legacy-stitches/index.d.ts +1 -1
  71. package/dist/app/lib/legacy-stitches/index.js +1 -1
  72. package/dist/app/lib/routing/components/BackButton.d.ts +49 -0
  73. package/dist/app/lib/routing/components/BackButton.js +47 -0
  74. package/dist/app/lib/routing/components/BrowserRouter.d.ts +4 -1
  75. package/dist/app/lib/routing/components/BrowserRouter.js +95 -19
  76. package/dist/app/lib/routing/components/ClientOnly.d.ts +1 -1
  77. package/dist/app/lib/routing/components/ClientOnly.js +1 -1
  78. package/dist/app/lib/routing/components/Link.d.ts +1 -0
  79. package/dist/app/lib/routing/components/Link.js +11 -12
  80. package/dist/app/lib/routing/components/RouteRenderer.d.ts +1 -1
  81. package/dist/app/lib/routing/components/RouteRenderer.js +7 -6
  82. package/dist/app/lib/routing/components/SSRRouter.d.ts +2 -2
  83. package/dist/app/lib/routing/components/SSRRouter.js +5 -6
  84. package/dist/app/lib/routing/components/ScrollRestoration.js +5 -2
  85. package/dist/app/lib/routing/context.d.ts +8 -5
  86. package/dist/app/lib/routing/context.js +13 -96
  87. package/dist/app/lib/routing/hooks/useRestorableState.d.ts +2 -1
  88. package/dist/app/lib/routing/hooks/useRestorableState.js +2 -1
  89. package/dist/app/lib/routing/hooks/useRoute.d.ts +16 -1
  90. package/dist/app/lib/routing/hooks/useRoute.js +22 -1
  91. package/dist/app/lib/routing/hooks/useRouteMeta.d.ts +5 -0
  92. package/dist/app/lib/routing/hooks/useRouteMeta.js +9 -0
  93. package/dist/app/lib/routing/hooks/useRouteTransition.d.ts +1 -1
  94. package/dist/app/lib/routing/hooks/useRouteTransition.js +1 -1
  95. package/dist/app/lib/routing/hooks/useRouter.d.ts +1 -1
  96. package/dist/app/lib/routing/hooks/useRouter.js +1 -1
  97. package/dist/app/lib/routing/hooks/useRouterEvents.d.ts +1 -1
  98. package/dist/app/lib/routing/hooks/useRouterEvents.js +1 -1
  99. package/dist/app/lib/routing/hooks/useRouterState.d.ts +1 -1
  100. package/dist/app/lib/routing/hooks/useRouterState.js +1 -1
  101. package/dist/app/lib/routing/hooks/useSearchParams.js +2 -2
  102. package/dist/app/lib/routing/index.d.ts +14 -13
  103. package/dist/app/lib/routing/index.js +14 -13
  104. package/dist/app/lib/routing/loader.d.ts +2 -2
  105. package/dist/app/lib/routing/loader.js +20 -11
  106. package/dist/app/lib/routing/types.d.ts +36 -10
  107. package/dist/app/lib/routing/utils.d.ts +5 -2
  108. package/dist/app/lib/routing/utils.js +37 -4
  109. package/dist/app/lib/{hooks → runtime}/apiConfig.d.ts +6 -2
  110. package/dist/app/lib/runtime/apiConfig.js +6 -0
  111. package/dist/app/lib/runtime/errorHandling.d.ts +39 -0
  112. package/dist/app/lib/runtime/errorHandling.js +6 -0
  113. package/dist/app/lib/runtime/index.d.ts +2 -0
  114. package/dist/app/lib/runtime/index.js +2 -0
  115. package/dist/app/lib/views/index.d.ts +1 -1
  116. package/dist/app/lib/views/index.js +1 -1
  117. package/dist/app/server/defineRouter.d.ts +2 -0
  118. package/dist/app/server/defineRouter.js +4 -0
  119. package/dist/app/server/index.d.ts +5 -3
  120. package/dist/app/server/index.js +5 -3
  121. package/dist/app/server/proxy-wp-admin.d.ts +1 -2
  122. package/dist/app/server/proxy-wp-admin.js +32 -14
  123. package/dist/app/server/render-ssr-page.d.ts +21 -2
  124. package/dist/app/server/render-ssr-page.js +143 -11
  125. package/dist/app/server/rpc.d.ts +56 -0
  126. package/dist/app/server/rpc.js +18 -0
  127. package/dist/app/server/server-context.d.ts +42 -4
  128. package/dist/app/server/server-context.js +196 -30
  129. package/dist/app/server/utils/replace-host.d.ts +1 -1
  130. package/dist/app/server/utils/replace-host.js +10 -2
  131. package/dist/app/server/utils/swr-cache.d.ts +4 -0
  132. package/dist/app/server/utils/swr-cache.js +31 -0
  133. package/dist/app/utils/APIProvider.d.ts +2 -0
  134. package/dist/app/utils/APIProvider.js +5 -0
  135. package/dist/app/utils/BlockErrorBoundary.d.ts +19 -0
  136. package/dist/app/utils/BlockErrorBoundary.js +38 -0
  137. package/dist/app/utils/ErrorMessage.d.ts +5 -0
  138. package/dist/app/utils/ErrorMessage.js +14 -0
  139. package/dist/app/utils/RouteErrorBoundary.d.ts +18 -0
  140. package/dist/app/utils/RouteErrorBoundary.js +38 -0
  141. package/dist/app/utils/asset-capture.d.ts +2 -0
  142. package/dist/app/utils/asset-capture.js +5 -0
  143. package/dist/app/utils/hydration-debugger.d.ts +13 -0
  144. package/dist/app/utils/hydration-debugger.js +11 -0
  145. package/dist/app/utils/query-client.d.ts +2 -0
  146. package/dist/app/utils/query-client.js +5 -1
  147. package/dist/app/utils/trpc-client.d.ts +2 -0
  148. package/dist/app/utils/trpc-client.js +39 -0
  149. package/dist/node/cli/cli-worker.js +10 -5
  150. package/dist/node/cli/cli.js +79 -11
  151. package/dist/node/cli/display/CLIApp.js +3 -6
  152. package/dist/node/cli/display/boot-cli-app.js +1 -1
  153. package/dist/node/cli/display/tools/CreateBlock.d.ts +1 -1
  154. package/dist/node/cli/display/tools/cli-tools.d.ts +1 -11
  155. package/dist/node/cli/display/tools/cli-tools.js +9 -9
  156. package/dist/node/cli/version.d.ts +1 -1
  157. package/dist/node/cli/version.js +1 -1
  158. package/dist/node/compiler/build-vinxi.js +3 -1
  159. package/dist/node/compiler/bundler.admin.d.ts +1 -1
  160. package/dist/node/compiler/bundler.admin.js +1 -1
  161. package/dist/node/compiler/bundler.frontend.js +1 -1
  162. package/dist/node/compiler/dev-server.js +10 -0
  163. package/dist/node/compiler/get-vite-config.d.ts +1 -0
  164. package/dist/node/compiler/get-vite-config.js +34 -11
  165. package/dist/node/compiler/vinxi-app.d.ts +12 -0
  166. package/dist/node/compiler/vinxi-app.js +139 -32
  167. package/dist/node/compiler/vinxi-codegen.js +321 -108
  168. package/dist/node/graphql/graphql-codegen.d.ts +11 -1
  169. package/dist/node/graphql/graphql-codegen.js +210 -33
  170. package/dist/node/graphql/graphql-schema-loader.d.ts +2 -1
  171. package/dist/node/graphql/graphql-schema-loader.js +5 -16
  172. package/dist/node/graphql/plugins/gql-plugin-queries.js +1 -1
  173. package/dist/node/graphql/query-files-loader.d.ts +3 -0
  174. package/dist/node/graphql/query-files-loader.js +5 -0
  175. package/dist/node/project/config.d.ts +159 -73
  176. package/dist/node/project/config.js +69 -20
  177. package/dist/node/project/env.d.ts +4 -0
  178. package/dist/node/project/env.js +1 -0
  179. package/dist/node/project/manifest/block-manifest.js +1 -0
  180. package/dist/node/project/manifest/manifest.d.ts +1 -0
  181. package/dist/node/project/manifest/manifest.js +14 -10
  182. package/dist/node/project/manifest/routes-manifest.d.ts +20 -0
  183. package/dist/node/project/manifest/routes-manifest.js +74 -0
  184. package/dist/node/project/manifest/view-manifest.js +1 -1
  185. package/dist/node/project/project.d.ts +9 -1
  186. package/dist/node/project/project.js +37 -6
  187. package/dist/node/project/wp-info.d.ts +1 -0
  188. package/dist/node/project/wp-info.js +13 -1
  189. package/dist/node/types/block-type.d.ts +25 -20
  190. package/dist/node/types/block-type.js +1 -0
  191. package/dist/node/types/view-type.d.ts +7 -7
  192. package/dist/node/utils/fetch-wp.d.ts +1 -0
  193. package/dist/node/utils/fetch-wp.js +27 -0
  194. package/dist/node/utils/fs-codegen.d.ts +2 -0
  195. package/dist/node/utils/fs-codegen.js +2 -1
  196. package/dist/node/utils/is-deploying.js +1 -1
  197. package/dist/node/utils/stateful-log.js +2 -0
  198. package/dist/node/utils/watch-file-tree.d.ts +17 -3
  199. package/dist/node/utils/watch-file-tree.js +12 -5
  200. package/package.json +17 -13
  201. package/types.app.d.ts +4 -2
  202. package/types.app.internal.d.ts +2 -2
  203. package/types.node.d.ts +3 -3
  204. package/dist/app/lib/blocks/ErrorBoundaryFrontend.d.ts +0 -15
  205. package/dist/app/lib/blocks/ErrorBoundaryFrontend.js +0 -35
  206. package/dist/app/lib/hooks/apiConfig.js +0 -4
  207. package/dist/app/lib/hooks/usePageLoad.d.ts +0 -6
  208. package/dist/app/lib/hooks/usePageLoad.js +0 -5
  209. package/dist/app/server/utils/index.html.d.ts +0 -2
  210. package/dist/app/server/utils/index.html.js +0 -14
@@ -1,5 +1,5 @@
1
1
  import { codegen } from "@graphql-codegen/core";
2
- import { Kind } from "graphql";
2
+ import { Kind, visit, print, } from "graphql";
3
3
  import { NoUnusedFragmentsRule, specifiedRules, validate } from "graphql/validation/index.js";
4
4
  import { join, relative, resolve } from "path";
5
5
  import { ProjectEnvUtils } from "../project/env.js";
@@ -9,13 +9,15 @@ import { createGraphQLFileLoader } from "./query-files-loader.js";
9
9
  import * as typescriptPlugin from "@graphql-codegen/typescript";
10
10
  import * as typescriptOperationsPlugin from "@graphql-codegen/typescript-operations";
11
11
  import chalk from "chalk";
12
- import { code } from "ts-poet";
12
+ import { code, imp } from "ts-poet";
13
13
  import { highlightCode } from "../utils/highlight-code.js";
14
14
  import { createConsole } from "../utils/stateful-log.js";
15
15
  import { watchFileTreeForChanges } from "../utils/watch-file-tree.js";
16
16
  import pluginFiles from "./plugins/gql-plugin-files.js";
17
17
  import pluginNoDuplicates from "./plugins/gql-plugin-no-duplicates.js";
18
18
  import pluginQueries from "./plugins/gql-plugin-queries.js";
19
+ import { FSCodegen } from "../utils/fs-codegen.js";
20
+ import { camelCase } from "change-case-all";
19
21
  export const graphqlLog = createConsole("GraphQL Codegen", "graphql");
20
22
  const console = graphqlLog;
21
23
  class GraphQLValidationError {
@@ -49,6 +51,7 @@ class GraphQLValidationError {
49
51
  }
50
52
  export class GraphQLGenerator {
51
53
  project;
54
+ opts;
52
55
  needsRegenerate = false;
53
56
  needsReload = true;
54
57
  regenerateReason = "";
@@ -56,12 +59,19 @@ export class GraphQLGenerator {
56
59
  isGenerating = false;
57
60
  schemaLoader;
58
61
  fileLoader;
62
+ optimizeWriter;
59
63
  debouncer;
60
64
  retryTimer;
61
- constructor(project) {
65
+ constructor(project, opts) {
62
66
  this.project = project;
63
- this.schemaLoader = new GraphQLSchemaLoader(ProjectEnvUtils.get("DEBUG_GRAPHQL_URL"));
67
+ this.opts = opts;
68
+ this.schemaLoader = new GraphQLSchemaLoader(ProjectEnvUtils.getSafe("DEBUG_GRAPHQL_URL"), ProjectEnvUtils.getSafe("SITE_API_KEY"));
64
69
  this.fileLoader = createGraphQLFileLoader(this.project, [
70
+ {
71
+ baseFolder: "queries/fragments",
72
+ pattern: "**/*.graphql",
73
+ key: "fragments",
74
+ },
65
75
  {
66
76
  baseFolder: "blocks",
67
77
  pattern: "**/*.graphql",
@@ -72,17 +82,44 @@ export class GraphQLGenerator {
72
82
  pattern: "**/*.graphql",
73
83
  key: "views",
74
84
  },
75
- {
76
- baseFolder: "queries/fragments",
77
- pattern: "**/*.graphql",
78
- key: "fragments",
79
- },
80
85
  {
81
86
  baseFolder: "queries",
82
87
  pattern: "**/*.graphql",
83
88
  key: "queries",
84
89
  },
85
90
  ]);
91
+ this.optimizeWriter = new FSCodegen(project, {
92
+ outDir: "./.eddev/queries",
93
+ });
94
+ this.optimizeWriter.register({
95
+ getFiles: async () => {
96
+ const files = await this.fileLoader.get();
97
+ const { queries, fragments } = this.getOptimizedQueries(files, true);
98
+ const optimizedQueries = Object.entries(queries).flatMap(([_, group]) => {
99
+ return Object.entries(group).flatMap(([name, ast]) => {
100
+ let content = [
101
+ ast.leadingComments ? ast.leadingComments + "\n" : "",
102
+ print(ast),
103
+ ast.trailingComments ? "\n" + ast.trailingComments : "",
104
+ ].join("");
105
+ return {
106
+ name,
107
+ content,
108
+ };
109
+ });
110
+ });
111
+ return [
112
+ ...optimizedQueries,
113
+ {
114
+ name: "fragments.json",
115
+ content: JSON.stringify(Object.values(fragments).map(print), null, 2),
116
+ },
117
+ ];
118
+ },
119
+ susbcribe: (callback) => {
120
+ return this.fileLoader.subscribe(callback);
121
+ },
122
+ });
86
123
  }
87
124
  async queueRegenerate(full, reason, info) {
88
125
  this.needsRegenerate = true;
@@ -107,14 +144,29 @@ export class GraphQLGenerator {
107
144
  // Do initial load of blocks
108
145
  await this.project.blocks.get();
109
146
  await this.project.views.get();
110
- try {
111
- await this.generate();
147
+ if (this.opts.generate) {
148
+ try {
149
+ await this.generate();
150
+ }
151
+ catch (err) { }
152
+ }
153
+ if (this.opts.watch) {
154
+ this.project.blocks.subscribeFuture(() => {
155
+ this.generateUtilTypes();
156
+ });
157
+ this.project.serverRoutes.subscribeFuture(() => {
158
+ this.generateAPITypes();
159
+ });
160
+ this.listen();
161
+ }
162
+ if (this.opts.optimize) {
163
+ if (this.opts.watch) {
164
+ await this.optimizeWriter.runAndWatch();
165
+ }
166
+ else {
167
+ await this.optimizeWriter.run();
168
+ }
112
169
  }
113
- catch (err) { }
114
- this.project.blocks.subscribeFuture(() => {
115
- this.generateUtilTypes();
116
- });
117
- this.listen();
118
170
  }
119
171
  async listen() {
120
172
  // Subscribe to changes in block names
@@ -138,14 +190,23 @@ export class GraphQLGenerator {
138
190
  this.queueRegenerate(false, "GraphQL file(s) modifed", events?.map(stringifyFileEvent));
139
191
  });
140
192
  // Look out for PHP and acf-json file changes
141
- watchFileTreeForChanges(["backend/**/*.php"], (event) => {
142
- this.queueRegenerate(true, "PHP file change detected", stringifyFileEvent(event));
193
+ watchFileTreeForChanges({
194
+ pattern: ["backend/**/*.php"],
195
+ callback: (event) => {
196
+ this.queueRegenerate(true, "PHP file change detected", stringifyFileEvent(event));
197
+ },
143
198
  });
144
- watchFileTreeForChanges(["vendor/**/*.php"], (change) => {
145
- this.queueRegenerate(true, "PHP Vendor folder change detected", stringifyFileEvent(change));
199
+ watchFileTreeForChanges({
200
+ pattern: ["vendor/**/*.php"],
201
+ callback: (change) => {
202
+ this.queueRegenerate(true, "PHP Vendor folder change detected", stringifyFileEvent(change));
203
+ },
146
204
  });
147
- watchFileTreeForChanges(["acf-json/**/*.json"], (change) => {
148
- this.queueRegenerate(true, "ACF Field change detected", stringifyFileEvent(change));
205
+ watchFileTreeForChanges({
206
+ pattern: ["acf-json/**/*.json"],
207
+ callback: (change) => {
208
+ this.queueRegenerate(true, "ACF Field change detected", stringifyFileEvent(change));
209
+ },
149
210
  });
150
211
  }
151
212
  scheduleRetry() {
@@ -223,10 +284,14 @@ export class GraphQLGenerator {
223
284
  };
224
285
  const errors = (await Promise.all([
225
286
  this.generateUtilTypes(),
287
+ this.generateAPITypes(),
226
288
  this.generateTS("types.graphql.ts", schemaResult.rawSchema, {
227
289
  documents: getDocuments(["queries", "views", "blocks", "fragments"]),
228
290
  hasDocuments: true,
229
291
  banner: `import { ContentBlock } from "eddev/blocks"`,
292
+ footer: Object.keys(wp.scalarTypes)
293
+ .map((name) => `export type ${name.endsWith("Option") ? name : name + "Scalar"} = Scalars["${name}"]["output"]`)
294
+ .join("\n"),
230
295
  plugins: {
231
296
  typescript: [typescriptPlugin, {}],
232
297
  typescriptOperations: [typescriptOperationsPlugin, {}],
@@ -334,6 +399,69 @@ export class GraphQLGenerator {
334
399
  this.generate();
335
400
  }
336
401
  }
402
+ getOptimizedQueries(graphQLFiles, rewrite = false) {
403
+ const result = {};
404
+ const allFragments = {};
405
+ /**
406
+ * Get all the base fragment definitions
407
+ */
408
+ const baseFragments = new Map();
409
+ Object.values(graphQLFiles.fragments)
410
+ .map((file) => file?.ast?.definitions ?? [])
411
+ .filter((def) => def.length > 0)
412
+ .flat()
413
+ .filter((n) => n.kind === Kind.FRAGMENT_DEFINITION)
414
+ .forEach((node) => baseFragments.set(node.name.value, node));
415
+ baseFragments.forEach((node) => {
416
+ allFragments[node.name.value] = node;
417
+ });
418
+ function findFragments(defs, map = new Map()) {
419
+ // console.log("findFragments", defs.length)
420
+ for (let def of defs) {
421
+ if (def.kind === Kind.FRAGMENT_DEFINITION) {
422
+ map.set(def.name.value, def);
423
+ }
424
+ }
425
+ for (let def of defs) {
426
+ visit(def, {
427
+ FragmentSpread: {
428
+ enter: (node) => {
429
+ const match = baseFragments.get(node.name.value);
430
+ if (match && !map.has(node.name.value)) {
431
+ map.set(node.name.value, match);
432
+ findFragments([match], map);
433
+ }
434
+ },
435
+ },
436
+ });
437
+ }
438
+ return {
439
+ fragments: [...map.values()],
440
+ definitions: defs.filter((n) => n.kind !== Kind.FRAGMENT_DEFINITION),
441
+ };
442
+ }
443
+ for (let [groupName, fileMap] of Object.entries(graphQLFiles)) {
444
+ result[groupName] = {};
445
+ for (let [path, file] of Object.entries(fileMap)) {
446
+ if (!file.parseError) {
447
+ // Find all fragments
448
+ const { fragments, definitions } = findFragments(file?.ast?.definitions ?? []);
449
+ const ast = {
450
+ kind: Kind.DOCUMENT,
451
+ definitions: [...definitions, ...fragments],
452
+ loc: file.ast.loc,
453
+ leadingComments: file.leadingComments,
454
+ trailingComments: file.trailingComments,
455
+ };
456
+ result[groupName][path] = ast;
457
+ }
458
+ }
459
+ }
460
+ return {
461
+ queries: result,
462
+ fragments: allFragments,
463
+ };
464
+ }
337
465
  /**
338
466
  * Validates a GraphQL manifest against a schema, ensuring there are no user errors.
339
467
  */
@@ -342,30 +470,43 @@ export class GraphQLGenerator {
342
470
  * Use all rules, except for No Unused Fragments — since we prepend those fragments to every test
343
471
  */
344
472
  const validationRules = specifiedRules.filter((rule) => rule !== NoUnusedFragmentsRule);
473
+ /**
474
+ * Get the optimized files — queries with all fragments included
475
+ */
476
+ const { queries } = this.getOptimizedQueries(graphQLFiles);
477
+ /**
478
+ * Only report the same error once (mostly for preventing repeats of the same fragment errors)
479
+ */
480
+ const errorsShown = new Map();
345
481
  /**
346
482
  * Validate everything
347
483
  */
348
484
  const report = [];
349
485
  for (let [groupName, fileMap] of Object.entries(graphQLFiles)) {
486
+ const group = queries[groupName];
350
487
  for (let [path, file] of Object.entries(fileMap)) {
351
488
  if (file.parseError) {
352
489
  report.push(new GraphQLValidationError(file.parseError.message, path, file.parseError.line, file.parseError.column, file.contents));
353
490
  }
354
491
  else {
355
492
  // Find all fragments
356
- const fragments = Object.values(graphQLFiles.fragments)
357
- .map((file) => file.ast.definitions)
358
- .filter((def) => def.length > 0)
359
- .filter((def) => def !== file.ast.definitions)
360
- .flat();
361
- const validationAST = {
362
- kind: Kind.DOCUMENT,
363
- definitions: [...fragments, ...file.ast.definitions],
364
- loc: file.ast.loc,
365
- };
493
+ const validationAST = group[path];
494
+ if (!validationAST) {
495
+ continue;
496
+ }
366
497
  const errors = validate(schema, validationAST, validationRules);
367
498
  if (errors.length > 0) {
368
499
  for (let error of errors) {
500
+ if (error.nodes && error.nodes[0]) {
501
+ const node = error.nodes[0];
502
+ if (errorsShown.has(node) && errorsShown.get(node)?.includes(error.message)) {
503
+ continue;
504
+ }
505
+ else {
506
+ errorsShown.set(node, [...(errorsShown.get(node) ?? []), error.message]);
507
+ }
508
+ }
509
+ // console.log(error.nodes?.map((n) => n.kind))
369
510
  report.push(new GraphQLValidationError(error.message, path, error.locations?.[0].line || 1, error.locations?.[0].column || 1, error.source?.body || ""));
370
511
  }
371
512
  }
@@ -400,7 +541,7 @@ export class GraphQLGenerator {
400
541
  errors.push(String(err));
401
542
  }
402
543
  if (args.banner) {
403
- output = args.banner + "\n\n" + output;
544
+ output = args.banner + "\n\n" + output + "\n" + (args.footer ?? "");
404
545
  }
405
546
  if (errors.length === 0) {
406
547
  const didWrite = await fs.writeIfUnchanged(config.filename, output);
@@ -488,6 +629,42 @@ export class GraphQLGenerator {
488
629
  }
489
630
  return [];
490
631
  }
632
+ async generateAPITypes() {
633
+ const filename = join(this.project.rootDir, "types.api.ts");
634
+ try {
635
+ const routeManifest = await this.project.serverRoutes.get();
636
+ const contents = code /*ts*/ `
637
+ import "eddev/types.app.public";
638
+ import { InferRPCServerContext, rpc } from "eddev/server"
639
+ import { finalizeRPCRouter } from "eddev/_internal"
640
+ ${routeManifest.contextFileName
641
+ ? code /*ts*/ `
642
+ import createContext from "./${routeManifest.contextFileName.replace(/\.tsx?$/, "")}"
643
+ `
644
+ : code /*ts*/ `
645
+ const createContext = () => ({})
646
+ `}
647
+
648
+ function createRouter() {
649
+ return finalizeRPCRouter({${Object.entries(routeManifest.routes).map(([name, route]) => {
650
+ const src = "./" + route.fileName;
651
+ const importStatement = imp(camelCase(name) + "=" + src.replace(/\.tsx?$/, ""));
652
+ return code `${JSON.stringify(route.prefix)}: ${importStatement},\n`;
653
+ })}})
654
+ }
655
+
656
+ declare global {
657
+ interface RPCContext extends InferRPCServerContext<typeof createContext> {}
658
+ interface RPCRouter extends ReturnType<typeof createRouter> {}
659
+ }
660
+ `;
661
+ await fs.writeIfUnchanged(filename, contents.toString());
662
+ }
663
+ catch (err) {
664
+ return [err];
665
+ }
666
+ return [];
667
+ }
491
668
  /**
492
669
  * Saves the schema to a file, for use by the VSCode GraphQL extension
493
670
  */
@@ -6,8 +6,9 @@ type LoadResult = {
6
6
  };
7
7
  export declare class GraphQLSchemaLoader {
8
8
  url: string;
9
+ apiKey?: string | undefined;
9
10
  lastHash: string;
10
- constructor(url: string);
11
+ constructor(url: string, apiKey?: string | undefined);
11
12
  private cachedResult;
12
13
  get(forceReload?: boolean): Promise<Error | LoadResult>;
13
14
  load(): Promise<Error | LoadResult>;
@@ -4,11 +4,14 @@ import { introspectionFromSchema } from "graphql";
4
4
  import { graphqlLog as console } from "./graphql-codegen.js";
5
5
  import chalk from "chalk";
6
6
  import { hash } from "object-code";
7
+ import { fetchWP } from "../utils/fetch-wp.js";
7
8
  export class GraphQLSchemaLoader {
8
9
  url;
10
+ apiKey;
9
11
  lastHash = "";
10
- constructor(url) {
12
+ constructor(url, apiKey) {
11
13
  this.url = url;
14
+ this.apiKey = apiKey;
12
15
  }
13
16
  cachedResult = null;
14
17
  async get(forceReload = false) {
@@ -21,21 +24,7 @@ export class GraphQLSchemaLoader {
21
24
  console.info(`${this.lastHash ? "Reloading" : "Loading"} GraphQL schema from ${chalk.yellowBright(this.url)}`);
22
25
  const rawSchema = await loadSchema(this.url, {
23
26
  loaders: [new UrlLoader()],
24
- // fetch: (url: string, opts: any) => {
25
- // const httpsAgent = new Agent({
26
- // rejectUnauthorized: false,
27
- // })
28
- // return fetch(url, {
29
- // ...opts,
30
- // agent: function (_parsedURL) {
31
- // if (_parsedURL.protocol == "http:") {
32
- // return undefined
33
- // } else {
34
- // return httpsAgent
35
- // }
36
- // },
37
- // })
38
- // },
27
+ fetch: fetchWP,
39
28
  }).catch((e) => {
40
29
  return e;
41
30
  });
@@ -67,7 +67,7 @@ export default {
67
67
  // Another convention, the query name and file name should be the same
68
68
  const baseName = basename(fileName);
69
69
  if (baseName.replace(".graphql", "") !== name) {
70
- throwErrorAtLocation(item.name.loc, `Expected your query name and file name to match, for conventions sake (eg. '${baseName}' should be '${name}.graphql')`);
70
+ throwErrorAtLocation(item.name.loc, `Expected GraphQL operation name to match the filename.\nYou should either:\na) rename the file to '${name}.graphql'\nb) rename the operation to '${baseName}'`);
71
71
  }
72
72
  // Only import variables if the operation has variables
73
73
  if (variablesTypeName) {
@@ -10,6 +10,8 @@ type Entry = {
10
10
  line?: number;
11
11
  column?: number;
12
12
  } | null;
13
+ leadingComments?: string;
14
+ trailingComments?: string;
13
15
  };
14
16
  export type GraphQLManifest<TKeys extends string> = {
15
17
  [K in TKeys]: {
@@ -21,6 +23,7 @@ type PatternMap<TKeys extends string> = {
21
23
  key: TKeys;
22
24
  baseFolder: string;
23
25
  pattern: string;
26
+ ignore?: string[];
24
27
  }[];
25
28
  export declare function createGraphQLFileLoader<TKeys extends string>(project: Project, patterns: PatternMap<TKeys>): import("../project/manifest/manifest.js").ManifestGenerator<Entry, GraphQLManifest<TKeys>>;
26
29
  export {};
@@ -7,6 +7,7 @@ export function createGraphQLFileLoader(project, patterns) {
7
7
  return createManifestGenerator({
8
8
  baseDir: project.rootDir,
9
9
  pattern: patterns.map((p) => join(p.baseFolder, p.pattern)),
10
+ ignore: patterns.flatMap((p) => p.ignore?.map((ignore) => join(p.baseFolder, ignore)) ?? []),
10
11
  watch: cliMode.watch,
11
12
  async generateManifest(entries) {
12
13
  let result = {};
@@ -32,6 +33,8 @@ export function createGraphQLFileLoader(project, patterns) {
32
33
  const contents = await fs.readFile(path, "utf8");
33
34
  let ast = null;
34
35
  let parseError = null;
36
+ const leadingComments = contents.match(/^(\n|#[^\n]*)+\n/)?.[0].trim();
37
+ const trailingComments = contents.match(/(\n|#[^\n]*)+$/)?.[0].trim();
35
38
  try {
36
39
  ast = parse(contents);
37
40
  }
@@ -48,6 +51,8 @@ export function createGraphQLFileLoader(project, patterns) {
48
51
  contents,
49
52
  ast,
50
53
  parseError,
54
+ leadingComments,
55
+ trailingComments,
51
56
  };
52
57
  },
53
58
  });