@cedarjs/internal 8.0.0-canary.3587 → 8.0.0-canary.3589

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.
@@ -1 +1 @@
1
- {"version":3,"file":"graphqlCodeGen.d.ts","sourceRoot":"","sources":["../../src/generate/graphqlCodeGen.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAoB9D,KAAK,aAAa,GAAG;IACnB,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,EAAE,CAAA;CAC9C,CAAA;AAED,eAAO,MAAM,yBAAyB,QAAa,OAAO,CAAC,aAAa,CAiFvE,CAAA;AAED,eAAO,MAAM,yBAAyB,QAAa,OAAO,CAAC,aAAa,CA2DvE,CAAA;AAyFD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM;SACD,MAAM;GAQ5D;AAmQD,eAAO,MAAM,iBAAiB,4RAe7B,CAAA"}
1
+ {"version":3,"file":"graphqlCodeGen.d.ts","sourceRoot":"","sources":["../../src/generate/graphqlCodeGen.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAqB9D,KAAK,aAAa,GAAG;IACnB,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,EAAE,CAAA;CAC9C,CAAA;AAED,eAAO,MAAM,yBAAyB,QAAa,OAAO,CAAC,aAAa,CAiFvE,CAAA;AAED,eAAO,MAAM,yBAAyB,QAAa,OAAO,CAAC,aAAa,CA2DvE,CAAA;AAyFD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM;SACD,MAAM;GAQ5D;AAgRD,eAAO,MAAM,iBAAiB,4RAe7B,CAAA"}
@@ -20,6 +20,7 @@ import {
20
20
  import { getPackageManager } from "@cedarjs/project-config/packageManager";
21
21
  import { getTsConfigs } from "../project.js";
22
22
  import * as rwTypescriptResolvers from "./plugins/rw-typescript-resolvers/index.js";
23
+ import { getServiceFieldResolvers } from "./serviceFieldResolvers.js";
23
24
  var CodegenSide = /* @__PURE__ */ ((CodegenSide2) => {
24
25
  CodegenSide2[CodegenSide2["API"] = 0] = "API";
25
26
  CodegenSide2[CodegenSide2["WEB"] = 1] = "WEB";
@@ -297,8 +298,11 @@ async function getPrismaModels() {
297
298
  }
298
299
  async function getPluginConfig(side) {
299
300
  const prismaModels = await getPrismaModels();
301
+ const fieldResolvers = side === 0 /* API */ ? getServiceFieldResolvers() : {};
300
302
  Object.keys(prismaModels).forEach((key) => {
301
- prismaModels[key] = `MergePrismaWithSdlTypes<Prisma${key}, MakeRelationsOptional<${key}, AllMappedModels>, AllMappedModels>`;
303
+ const resolvedFields = fieldResolvers[key] ?? [];
304
+ const resolvedFieldsArg = resolvedFields.length ? `, ${resolvedFields.map((field) => JSON.stringify(field)).join(" | ")}` : "";
305
+ prismaModels[key] = `MergePrismaWithSdlTypes<Prisma${key}, MakeRelationsOptional<${key}, AllMappedModels>, AllMappedModels${resolvedFieldsArg}>`;
302
306
  });
303
307
  const scalars = {
304
308
  // We need these, otherwise these scalars are mapped to any
@@ -0,0 +1,33 @@
1
+ import type { types } from '@babel/core';
2
+ /**
3
+ * Field names, per GraphQL type, that services provide field resolvers for.
4
+ *
5
+ * Services provide field resolvers for a type by exporting an object named
6
+ * after the type, e.g. `export const Post = { author: (_args, { root }) => … }`.
7
+ * GraphQL server merges these exports from all services, so the field names
8
+ * here are merged the same way.
9
+ */
10
+ export type ServiceFieldResolvers = Record<string, string[]>;
11
+ /**
12
+ * Whether GraphQL server loads this file as a service. This matches the
13
+ * filters of the `src/services/**\/*.{js,ts}` glob import, in both
14
+ * vite-plugin-cedar-import-dir and babel-plugin-redwood-import-dir, so field
15
+ * resolvers in files that aren't loaded don't affect the generated types.
16
+ */
17
+ export declare const isLoadedServiceFile: (filePath: string) => boolean;
18
+ /**
19
+ * Finds the field resolvers in a single service file.
20
+ *
21
+ * Only object literals exported directly (`export const Post = { … }`) are
22
+ * recognized. Keys that can't be determined statically, like spread or
23
+ * computed keys, are skipped. A skipped field stays required on resolver
24
+ * results, which is the safe side to err on.
25
+ */
26
+ export declare const getFieldResolversFromAst: (ast: types.File) => ServiceFieldResolvers;
27
+ /**
28
+ * Finds the field resolvers that all the project's services provide, keyed by
29
+ * GraphQL type name. Field names are sorted and de-duplicated so the result
30
+ * is stable across runs.
31
+ */
32
+ export declare const getServiceFieldResolvers: (serviceFiles?: string[]) => ServiceFieldResolvers;
33
+ //# sourceMappingURL=serviceFieldResolvers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serviceFieldResolvers.d.ts","sourceRoot":"","sources":["../../src/generate/serviceFieldResolvers.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAMxC;;;;;;;GAOG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;AAI5D;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAAI,UAAU,MAAM,YAOnD,CAAA;AAyCD;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,GACnC,KAAK,KAAK,CAAC,IAAI,KACd,qBAwCF,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,GACnC,eAAc,MAAM,EAAuB,KAC1C,qBAkCF,CAAA"}
@@ -0,0 +1,85 @@
1
+ import fs from "node:fs";
2
+ import { parse } from "@babel/parser";
3
+ import fg from "fast-glob";
4
+ import { getPaths } from "@cedarjs/project-config";
5
+ const ROOT_TYPES = ["Query", "Mutation", "Subscription"];
6
+ const isLoadedServiceFile = (filePath) => {
7
+ return /\.(js|ts)$/.test(filePath) && !filePath.includes(".test.") && !filePath.includes(".scenarios.") && !filePath.includes(".d.ts");
8
+ };
9
+ const findServiceFiles = (cwd = getPaths().api.services) => {
10
+ return fg.sync("**/*.{js,ts}", { cwd, absolute: true }).filter(isLoadedServiceFile);
11
+ };
12
+ const unwrapExpression = (node) => {
13
+ if (node.type === "TSSatisfiesExpression" || node.type === "TSAsExpression" || node.type === "TSNonNullExpression" || node.type === "ParenthesizedExpression") {
14
+ return unwrapExpression(node.expression);
15
+ }
16
+ return node;
17
+ };
18
+ const getPropertyName = (property) => {
19
+ if (property.type === "SpreadElement" || property.computed) {
20
+ return void 0;
21
+ }
22
+ if (property.key.type === "Identifier") {
23
+ return property.key.name;
24
+ }
25
+ if (property.key.type === "StringLiteral") {
26
+ return property.key.value;
27
+ }
28
+ return void 0;
29
+ };
30
+ const getFieldResolversFromAst = (ast) => {
31
+ const fieldResolvers = {};
32
+ for (const statement of ast.program.body) {
33
+ if (statement.type !== "ExportNamedDeclaration" || statement.declaration?.type !== "VariableDeclaration") {
34
+ continue;
35
+ }
36
+ for (const declarator of statement.declaration.declarations) {
37
+ if (declarator.id.type !== "Identifier" || !declarator.init) {
38
+ continue;
39
+ }
40
+ const typeName = declarator.id.name;
41
+ if (ROOT_TYPES.includes(typeName)) {
42
+ continue;
43
+ }
44
+ const init = unwrapExpression(declarator.init);
45
+ if (init.type !== "ObjectExpression") {
46
+ continue;
47
+ }
48
+ const fieldNames = init.properties.map(getPropertyName).filter((name) => name !== void 0);
49
+ fieldResolvers[typeName] = [
50
+ ...fieldResolvers[typeName] ?? [],
51
+ ...fieldNames
52
+ ];
53
+ }
54
+ }
55
+ return fieldResolvers;
56
+ };
57
+ const getServiceFieldResolvers = (serviceFiles = findServiceFiles()) => {
58
+ const merged = {};
59
+ for (const file of serviceFiles) {
60
+ let ast;
61
+ try {
62
+ ast = parse(fs.readFileSync(file, "utf-8"), {
63
+ sourceType: "module",
64
+ plugins: ["typescript"]
65
+ });
66
+ } catch {
67
+ continue;
68
+ }
69
+ const fieldResolvers = getFieldResolversFromAst(ast);
70
+ for (const [typeName, fieldNames] of Object.entries(fieldResolvers)) {
71
+ merged[typeName] ??= /* @__PURE__ */ new Set();
72
+ for (const fieldName of fieldNames) {
73
+ merged[typeName].add(fieldName);
74
+ }
75
+ }
76
+ }
77
+ return Object.fromEntries(
78
+ Object.keys(merged).sort().map((typeName) => [typeName, [...merged[typeName]].sort()])
79
+ );
80
+ };
81
+ export {
82
+ getFieldResolversFromAst,
83
+ getServiceFieldResolvers,
84
+ isLoadedServiceFile
85
+ };
@@ -20,6 +20,10 @@ import {
20
20
  generateTypeDefGraphQLWeb
21
21
  } from "./graphqlCodeGen.js";
22
22
  import { generateGraphQLSchema } from "./graphqlSchema.js";
23
+ import {
24
+ getServiceFieldResolvers,
25
+ isLoadedServiceFile
26
+ } from "./serviceFieldResolvers.js";
23
27
  import {
24
28
  generateMirrorCell,
25
29
  generateMirrorDirectoryNamedModule,
@@ -46,6 +50,10 @@ const action = {
46
50
  change: "Modified"
47
51
  };
48
52
  let routesWarningMessage = "";
53
+ let serviceFieldResolvers = JSON.stringify(getServiceFieldResolvers());
54
+ const isServiceFile = (p) => {
55
+ return p.startsWith(rwjsPaths.api.services + path.sep) && isLoadedServiceFile(p);
56
+ };
49
57
  process.stdin.on("data", async (data) => {
50
58
  const str = data.toString().trim().toLowerCase();
51
59
  if (str === "g" || str === "rs") {
@@ -118,6 +126,24 @@ Created ${files.length} in ${Date.now() - start} ms`);
118
126
  await generateGqlormArtifacts();
119
127
  finished("Prisma Schema");
120
128
  }
129
+ if (isServiceFile(absPath)) {
130
+ const nextServiceFieldResolvers = JSON.stringify(
131
+ getServiceFieldResolvers()
132
+ );
133
+ if (nextServiceFieldResolvers !== serviceFieldResolvers) {
134
+ const { errors } = await generateTypeDefGraphQLApi();
135
+ if (errors.length > 0) {
136
+ for (const { message, error } of errors) {
137
+ console.error(message);
138
+ console.error(error);
139
+ console.log();
140
+ }
141
+ } else {
142
+ serviceFieldResolvers = nextServiceFieldResolvers;
143
+ finished("Service field resolvers");
144
+ }
145
+ }
146
+ }
121
147
  if (routesWarningMessage) {
122
148
  console.warn(routesWarningMessage);
123
149
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cedarjs/internal",
3
- "version": "8.0.0-canary.3587",
3
+ "version": "8.0.0-canary.3589",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/cedarjs/cedar.git",
@@ -126,14 +126,14 @@
126
126
  "@babel/core": "^7.26.10",
127
127
  "@babel/parser": "7.29.12",
128
128
  "@babel/traverse": "7.29.12",
129
- "@cedarjs/api": "8.0.0-canary.3587",
130
- "@cedarjs/babel-config": "8.0.0-canary.3587",
131
- "@cedarjs/cli-helpers": "8.0.0-canary.3587",
132
- "@cedarjs/graphql-server": "8.0.0-canary.3587",
133
- "@cedarjs/project-config": "8.0.0-canary.3587",
134
- "@cedarjs/router": "8.0.0-canary.3587",
135
- "@cedarjs/structure": "8.0.0-canary.3587",
136
- "@cedarjs/utils": "8.0.0-canary.3587",
129
+ "@cedarjs/api": "8.0.0-canary.3589",
130
+ "@cedarjs/babel-config": "8.0.0-canary.3589",
131
+ "@cedarjs/cli-helpers": "8.0.0-canary.3589",
132
+ "@cedarjs/graphql-server": "8.0.0-canary.3589",
133
+ "@cedarjs/project-config": "8.0.0-canary.3589",
134
+ "@cedarjs/router": "8.0.0-canary.3589",
135
+ "@cedarjs/structure": "8.0.0-canary.3589",
136
+ "@cedarjs/utils": "8.0.0-canary.3589",
137
137
  "@graphql-codegen/add": "6.0.1",
138
138
  "@graphql-codegen/cli": "6.3.1",
139
139
  "@graphql-codegen/client-preset": "5.3.0",
@@ -171,7 +171,7 @@
171
171
  "vite-tsconfig-paths": "6.1.1"
172
172
  },
173
173
  "devDependencies": {
174
- "@cedarjs/framework-tools": "8.0.0-canary.3587",
174
+ "@cedarjs/framework-tools": "8.0.0-canary.3589",
175
175
  "@jridgewell/trace-mapping": "0.3.31",
176
176
  "@oxc-project/types": "^0.155.0",
177
177
  "concurrently": "9.2.5",