@cedarjs/cli 5.0.4-next.167 → 5.0.4-rc.3

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/dist/cfw.js CHANGED
@@ -40,8 +40,6 @@ try {
40
40
  // CEDAR_DISABLE_TELEMETRY
41
41
  env: { CEDAR_CWD: projectPath }
42
42
  });
43
- } catch (e) {
43
+ } catch {
44
44
  console.log();
45
- const exitCode = e && typeof e === "object" && "exitCode" in e && typeof e.exitCode === "number" ? e.exitCode : 1;
46
- process.exit(exitCode);
47
45
  }
@@ -181,14 +181,10 @@ Run ` + c.info(formatCedarCommand(["build"])) + " (without specifying a workspac
181
181
  "@cedarjs/vite/bins/cedar-vite-build.mjs"
182
182
  );
183
183
  await execa(
184
- "node",
185
- [
186
- buildBinPath,
187
- `--webDir=${cedarPaths.web.base}`,
188
- `--verbose=${verbose}`
189
- ],
184
+ `node ${buildBinPath} --webDir="${cedarPaths.web.base}" --verbose=${verbose}`,
190
185
  {
191
186
  stdio: verbose ? "inherit" : "pipe",
187
+ shell: true,
192
188
  cwd: cedarPaths.web.base
193
189
  }
194
190
  );
@@ -227,16 +223,12 @@ Run ` + c.info(formatCedarCommand(["build"])) + " (without specifying a workspac
227
223
  "@cedarjs/vite/bins/cedar-vite-build.mjs"
228
224
  );
229
225
  await execa(
230
- "node",
231
- [
232
- buildBinPath,
233
- `--webDir=${cedarPaths.web.base}`,
234
- `--verbose=${verbose}`
235
- ],
226
+ `node ${buildBinPath} --webDir="${cedarPaths.web.base}" --verbose=${verbose}`,
236
227
  {
237
228
  stdio: verbose ? "inherit" : "pipe",
238
- // `cwd` makes postcss/tailwind config resolution work (see the
239
- // @NOTE above)
229
+ shell: true,
230
+ // `cwd` is needed for the package manager (e.g. yarn) to find the
231
+ // cedar-vite-build binary
240
232
  // It won't change process.cwd for anything else here, in this
241
233
  // process
242
234
  cwd: cedarPaths.web.base
@@ -1,11 +1,9 @@
1
1
  const command = "console";
2
2
  const aliases = ["c"];
3
- const description = "Launch an interactive Cedar shell";
3
+ const description = "Launch an interactive Redwood shell (experimental)";
4
4
  const handler = async () => {
5
- console.log(
6
- "`cedar console` has been removed from the Cedar CLI.\nRun it as a standalone tool instead:\n\n yarn dlx @cedarjs/console\n npx @cedarjs/console\n pnpm dlx @cedarjs/console\n"
7
- );
8
- process.exit(1);
5
+ const { handler: handler2 } = await import("./consoleHandler.js");
6
+ return handler2();
9
7
  };
10
8
  export {
11
9
  aliases,
@@ -0,0 +1,75 @@
1
+ import fs from "node:fs";
2
+ import { createRequire } from "node:module";
3
+ import path from "node:path";
4
+ import repl from "node:repl";
5
+ import { registerApiSideBabelHook } from "@cedarjs/babel-config";
6
+ import { recordTelemetryAttributes } from "@cedarjs/cli-helpers";
7
+ import { getPaths } from "../lib/index.js";
8
+ const paths = getPaths();
9
+ function isREPLServerWithHistory(replServer) {
10
+ return "history" in replServer && "lines" in replServer;
11
+ }
12
+ const loadPrismaClient = (replContext) => {
13
+ const createdRequire = createRequire(import.meta.url);
14
+ const { db } = createdRequire(path.join(paths.api.lib, "db"));
15
+ db[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")] = "PrismaClient";
16
+ replContext.db = db;
17
+ };
18
+ const consoleHistoryFile = path.join(paths.generated.base, "console_history");
19
+ const persistConsoleHistory = (r) => {
20
+ const lines = isREPLServerWithHistory(r) ? r.lines : [];
21
+ fs.appendFileSync(
22
+ consoleHistoryFile,
23
+ lines.filter((line) => line.trim()).join("\n") + "\n",
24
+ "utf8"
25
+ );
26
+ };
27
+ const loadConsoleHistory = async (r) => {
28
+ try {
29
+ const history = await fs.promises.readFile(consoleHistoryFile, "utf8");
30
+ if (isREPLServerWithHistory(r)) {
31
+ history.split("\n").reverse().map((line) => r.history.push(line));
32
+ }
33
+ } catch {
34
+ }
35
+ };
36
+ const handler = (_options) => {
37
+ recordTelemetryAttributes({
38
+ command: "console"
39
+ });
40
+ registerApiSideBabelHook({
41
+ plugins: [
42
+ [
43
+ "babel-plugin-module-resolver",
44
+ {
45
+ alias: {
46
+ src: paths.api.src
47
+ }
48
+ },
49
+ "rwjs-console-module-resolver"
50
+ ]
51
+ ]
52
+ });
53
+ const r = repl.start();
54
+ const defaultEval = r.eval;
55
+ const asyncEval = (cmd, context, filename, callback) => {
56
+ defaultEval.call(r, cmd, context, filename, async (err, result) => {
57
+ if (err) {
58
+ callback(err, null);
59
+ } else {
60
+ try {
61
+ callback(null, await Promise.resolve(result));
62
+ } catch (err2) {
63
+ callback(err2 instanceof Error ? err2 : new Error(String(err2)), null);
64
+ }
65
+ }
66
+ });
67
+ };
68
+ r.eval = asyncEval;
69
+ loadConsoleHistory(r);
70
+ r.addListener("close", () => persistConsoleHistory(r));
71
+ loadPrismaClient(r.context);
72
+ };
73
+ export {
74
+ handler
75
+ };
@@ -1,5 +1,4 @@
1
1
  import fs from "node:fs";
2
- import { createRequire } from "node:module";
3
2
  import path from "node:path";
4
3
  import { Writable } from "node:stream";
5
4
  import concurrently from "concurrently";
@@ -8,7 +7,6 @@ import { formatRunBinCommand } from "@cedarjs/cli-helpers/packageManager/display
8
7
  import { shutdownPort } from "@cedarjs/internal/dist/dev";
9
8
  import { generateGqlormArtifacts } from "@cedarjs/internal/dist/generate/gqlormSchema";
10
9
  import { getConfig, getConfigPath } from "@cedarjs/project-config";
11
- import { getPackageManager } from "@cedarjs/project-config/packageManager";
12
10
  import { errorTelemetry } from "@cedarjs/telemetry";
13
11
  import { exitWithError } from "../../lib/exit.js";
14
12
  import { generatePrismaClient } from "../../lib/generatePrismaClient.js";
@@ -17,38 +15,13 @@ import { getFreePort } from "../../lib/ports.js";
17
15
  import { serverFileExists } from "../../lib/project.js";
18
16
  import { getApiDebugFlag } from "./apiDebugFlag.js";
19
17
  import { getPackageWatchCommands } from "./packageWatchCommands.js";
20
- const createdRequire = createRequire(import.meta.url);
21
- function formatViteDevBinCommand(binName, extraNodeArgs = "") {
22
- let vitePackageJsonPath;
23
- let vitePackageJson;
24
- try {
25
- vitePackageJsonPath = createdRequire.resolve("@cedarjs/vite/package.json");
26
- vitePackageJson = createdRequire("@cedarjs/vite/package.json");
27
- } catch (e) {
28
- const message = e instanceof Error ? e.message : String(e);
29
- throw new Error(
30
- `Could not resolve @cedarjs/vite, which the dev server needs to run. Is it installed? (${message})`
31
- );
32
- }
33
- const binRelativePath = vitePackageJson.bin?.[binName];
34
- if (!binRelativePath) {
35
- throw new Error(
36
- `@cedarjs/vite does not declare a "${binName}" bin. This is a bug in CedarJS.`
37
- );
38
- }
39
- const binPath = path.join(path.dirname(vitePackageJsonPath), binRelativePath);
40
- const nodeLauncher = getPackageManager() === "yarn" ? "yarn node" : "node";
41
- const flags = extraNodeArgs ? `${extraNodeArgs} ` : "";
42
- return `${nodeLauncher} ${flags}"${binPath}"`;
43
- }
44
18
  const handler = async ({
45
19
  workspace = ["api", "web", "packages/*"],
46
20
  forward = "",
47
21
  generate = true,
48
22
  apiDebugPort,
49
23
  debugBrk,
50
- ud = false,
51
- nodeArgs = ""
24
+ ud = false
52
25
  }) => {
53
26
  recordTelemetryAttributes({
54
27
  command: "dev",
@@ -201,7 +174,7 @@ const handler = async ({
201
174
  return null;
202
175
  }
203
176
  return [
204
- formatViteDevBinCommand("cedar-unified-dev", nodeArgs),
177
+ `${formatRunBinCommand("cross-env", ["NODE_ENV=development", "cedar-unified-dev"])}`,
205
178
  ` --port ${webAvailablePort}`,
206
179
  ` --apiPort ${apiAvailablePort}`,
207
180
  getApiDebugFlag(apiDebugPort, apiAvailablePort),
@@ -257,16 +230,13 @@ const handler = async ({
257
230
  });
258
231
  }
259
232
  if (workspace.includes("web")) {
260
- let webCommand = `${formatViteDevBinCommand("cedar-vite-dev", nodeArgs)} ${forward}`;
233
+ let webCommand = `${formatRunBinCommand("cross-env", ["NODE_ENV=development", "cedar-vite-dev"])} ${forward}`;
261
234
  if (streamingSsrEnabled) {
262
- webCommand = `${formatViteDevBinCommand("cedar-dev-fe", nodeArgs)} ${forward}`;
235
+ webCommand = `${formatRunBinCommand("cross-env", ["NODE_ENV=development", "cedar-dev-fe"])} ${forward}`;
263
236
  }
264
237
  jobs.push({
265
238
  name: "web",
266
239
  command: webCommand,
267
- env: {
268
- NODE_ENV: "development"
269
- },
270
240
  prefixColor: "blue",
271
241
  cwd: cedarPaths.web.base,
272
242
  runWhen: () => fs.existsSync(cedarPaths.web.src)
@@ -31,9 +31,6 @@ const builder = (yargs) => {
31
31
  type: "boolean",
32
32
  default: false,
33
33
  description: "Use the unified Vite dev server that handles both web and API in a single process (experimental)."
34
- }).option("nodeArgs", {
35
- type: "string",
36
- description: 'CLI args to pass to the node process running the web dev server, for example: `--node-args="--inspect --max-old-space-size=8192"`.'
37
34
  }).middleware(() => {
38
35
  const check = checkNodeVersion();
39
36
  if (check.ok) {
@@ -97,11 +97,13 @@ const handler = async ({
97
97
  {
98
98
  title: "Cleaning up...",
99
99
  task: () => {
100
- runBinSync(
101
- "eslint",
102
- ["--fix", `${getPaths().api.jobsConfig}`, ...Object.keys(jobFiles)],
103
- { cwd: getPaths().base }
104
- );
100
+ runBinSync("eslint", [
101
+ "--fix",
102
+ "--config",
103
+ `${getPaths().base}/node_modules/@cedarjs/eslint-config/shared.js`,
104
+ `${getPaths().api.jobsConfig}`,
105
+ ...Object.keys(jobFiles)
106
+ ]);
105
107
  }
106
108
  }
107
109
  ],
@@ -407,9 +407,12 @@ const handler = async ({
407
407
  {
408
408
  title: "Cleaning up...",
409
409
  task: () => {
410
- runBinSync("eslint", ["--fix", ...Object.keys(packageFiles)], {
411
- cwd: getPaths().base
412
- });
410
+ runBinSync("eslint", [
411
+ "--fix",
412
+ "--config",
413
+ `${getPaths().base}/node_modules/@cedarjs/eslint-config/index.js`,
414
+ ...Object.keys(packageFiles)
415
+ ]);
413
416
  }
414
417
  }
415
418
  ],
@@ -46,8 +46,15 @@ const addFieldGraphQLComment = (field, str) => {
46
46
  const modelFieldToSDL = ({
47
47
  field,
48
48
  required = true,
49
+ types = {},
49
50
  docs = false
50
51
  }) => {
52
+ if (Object.entries(types).length && field.kind === "object") {
53
+ const resolvedType = idType(types[field.type]);
54
+ if (typeof resolvedType === "string") {
55
+ field.type = resolvedType;
56
+ }
57
+ }
51
58
  const prismaTypeToGraphqlType = {
52
59
  Json: "JSON",
53
60
  Decimal: "Float",
@@ -66,7 +73,7 @@ const modelFieldToSDL = ({
66
73
  const querySDL = (model, docs = false) => {
67
74
  return model.fields.map((field) => modelFieldToSDL({ field, docs }));
68
75
  };
69
- const inputSDL = (model, required, docs = false) => {
76
+ const inputSDL = (model, required, types = {}, docs = false) => {
70
77
  const ignoredFields = DEFAULT_IGNORE_FIELDS_FOR_INPUT;
71
78
  return model.fields.filter((field) => {
72
79
  const idField = model.fields.find((field2) => field2.isId);
@@ -74,19 +81,21 @@ const inputSDL = (model, required, docs = false) => {
74
81
  ignoredFields.push(idField.name);
75
82
  }
76
83
  return !ignoredFields.includes(field.name) && field.kind !== "object";
77
- }).map((field) => modelFieldToSDL({ field, required, docs }));
84
+ }).map((field) => modelFieldToSDL({ field, required, types, docs }));
78
85
  };
79
86
  function idInputSDL(idType2, docs) {
80
87
  if (!Array.isArray(idType2)) {
81
88
  return [];
82
89
  }
83
- return idType2.map((field) => modelFieldToSDL({ field, required: true, docs }));
90
+ return idType2.map(
91
+ (field) => modelFieldToSDL({ field, required: true, types: {}, docs })
92
+ );
84
93
  }
85
- const createInputSDL = (model, docs = false) => {
86
- return inputSDL(model, true, docs);
94
+ const createInputSDL = (model, types = {}, docs = false) => {
95
+ return inputSDL(model, true, types, docs);
87
96
  };
88
- const updateInputSDL = (model, docs = false) => {
89
- return inputSDL(model, false, docs);
97
+ const updateInputSDL = (model, types = {}, docs = false) => {
98
+ return inputSDL(model, false, types, docs);
90
99
  };
91
100
  function idType(model, crud) {
92
101
  if (!crud || !model) {
@@ -122,6 +131,21 @@ const sdlFromSchemaModel = async (name, crud, docs = false) => {
122
131
  );
123
132
  }
124
133
  const model = schemaResult;
134
+ const resolvedTypes = await Promise.all(
135
+ model.fields.filter((field) => field.kind === "object").map(async (field) => {
136
+ const fieldModel = await getSchema(field.type);
137
+ return fieldModel && "fields" in fieldModel ? fieldModel : void 0;
138
+ })
139
+ );
140
+ const types = resolvedTypes.reduce(
141
+ (acc, cur) => {
142
+ if (!cur) {
143
+ return acc;
144
+ }
145
+ return { ...acc, [cur.name]: cur };
146
+ },
147
+ {}
148
+ );
125
149
  const enums = (await Promise.all(
126
150
  model.fields.filter((field) => field.kind === "enum").map(async (field) => {
127
151
  const enumDef = await getEnum(field.type);
@@ -135,8 +159,8 @@ const sdlFromSchemaModel = async (name, crud, docs = false) => {
135
159
  modelName,
136
160
  modelDescription,
137
161
  query: querySDL(model, docs).join("\n "),
138
- createInput: createInputSDL(model, docs).join("\n "),
139
- updateInput: updateInputSDL(model, docs).join("\n "),
162
+ createInput: createInputSDL(model, types, docs).join("\n "),
163
+ updateInput: updateInputSDL(model, types, docs).join("\n "),
140
164
  idInput: idInputSDL(idTypeRes, docs).join("\n "),
141
165
  idType: idType(model, crud),
142
166
  idName: idName(model, crud),
@@ -30,8 +30,14 @@ const customOrDefaultTemplatePath = ({
30
30
  generator,
31
31
  templatePath
32
32
  );
33
+ const deprecatedCustomPath = getPaths()[side].generators ? path.join(getPaths()[side].generators, generator, templatePath) : void 0;
33
34
  if (fs.existsSync(customPath)) {
34
35
  return customPath;
36
+ } else if (deprecatedCustomPath && fs.existsSync(deprecatedCustomPath)) {
37
+ console.log(
38
+ `Having generator templates in ${getPaths()[side].generators} has been deprecated. Please move them to ${getPaths().generatorTemplates}.`
39
+ );
40
+ return deprecatedCustomPath;
35
41
  } else {
36
42
  return defaultPath;
37
43
  }
@@ -1,8 +1,63 @@
1
1
  import fs from "node:fs";
2
+ import path from "node:path";
2
3
  import { terminalLink } from "termi-link";
3
4
  import { recordTelemetryAttributes } from "@cedarjs/cli-helpers";
4
5
  import { runBin } from "@cedarjs/cli-helpers/packageManager/exec";
5
- import { getPaths } from "@cedarjs/project-config";
6
+ import { getPaths, getConfig } from "@cedarjs/project-config";
7
+ function detectLegacyEslintConfig() {
8
+ const projectRoot = getPaths().base;
9
+ const legacyConfigFiles = [
10
+ ".eslintrc.js",
11
+ ".eslintrc.cjs",
12
+ ".eslintrc.json",
13
+ ".eslintrc.yaml",
14
+ ".eslintrc.yml"
15
+ ];
16
+ const foundLegacyFiles = [];
17
+ for (const configFile of legacyConfigFiles) {
18
+ if (fs.existsSync(path.join(projectRoot, configFile))) {
19
+ foundLegacyFiles.push(configFile);
20
+ }
21
+ }
22
+ const packageJsonPath = path.join(projectRoot, "package.json");
23
+ if (fs.existsSync(packageJsonPath)) {
24
+ try {
25
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
26
+ if (packageJson.eslintConfig) {
27
+ foundLegacyFiles.push("package.json (eslintConfig field)");
28
+ }
29
+ if (packageJson.eslint) {
30
+ foundLegacyFiles.push("package.json (eslint field)");
31
+ }
32
+ } catch {
33
+ }
34
+ }
35
+ return foundLegacyFiles;
36
+ }
37
+ function showLegacyEslintDeprecationWarning(legacyFiles) {
38
+ console.warn("");
39
+ console.warn("\u26A0\uFE0F DEPRECATION WARNING: Legacy ESLint Configuration Detected");
40
+ console.warn("");
41
+ console.warn(" The following legacy ESLint configuration files were found:");
42
+ legacyFiles.forEach((file) => {
43
+ console.warn(` - ${file}`);
44
+ });
45
+ console.warn("");
46
+ console.warn(
47
+ " Cedar has migrated to ESLint flat config format. Legacy configurations"
48
+ );
49
+ console.warn(
50
+ " still work but are deprecated and will be removed in a future version."
51
+ );
52
+ console.warn("");
53
+ console.warn(" To migrate to the new format:");
54
+ console.warn(" 1. Remove the legacy config file(s) listed above");
55
+ console.warn(" 2. Create an eslint.config.mjs");
56
+ console.warn(" 3. Use the flat config format with @cedarjs/eslint-config");
57
+ console.warn("");
58
+ console.warn(" See more here: https://github.com/cedarjs/cedar/pull/629");
59
+ console.warn("");
60
+ }
6
61
  const command = "lint [paths..]";
7
62
  const description = "Lint your files";
8
63
  const builder = (yargs) => {
@@ -31,6 +86,11 @@ const handler = async ({
31
86
  format = "stylish"
32
87
  }) => {
33
88
  recordTelemetryAttributes({ command: "lint", fix, format });
89
+ const config = getConfig();
90
+ const legacyConfigFiles = detectLegacyEslintConfig();
91
+ if (legacyConfigFiles.length > 0 && config instanceof Object && "eslintLegacyConfigWarning" in config && config.eslintLegacyConfigWarning) {
92
+ showLegacyEslintDeprecationWarning(legacyConfigFiles);
93
+ }
34
94
  try {
35
95
  const sbPath = getPaths().web.storybook;
36
96
  const eslintArgs = [
@@ -49,15 +49,18 @@ const handler = async ({
49
49
  for (const [name, value] of Object.entries(options)) {
50
50
  args.push(name.length > 1 ? `--${name}` : `-${name}`);
51
51
  if (typeof value === "string") {
52
- args.push(value);
52
+ if (value.split(" ").length > 1) {
53
+ args.push(`"${value}"`);
54
+ } else {
55
+ args.push(value);
56
+ }
53
57
  } else if (typeof value === "number") {
54
58
  args.push(String(value));
55
59
  }
56
60
  }
57
- const displayCommand = args.map((arg) => arg.includes(" ") ? `"${arg}"` : arg).join(" ");
58
61
  console.log();
59
62
  console.log(c.note("Running Prisma CLI..."));
60
- console.log(c.underline(`$ <pm exec> prisma ${displayCommand}`));
63
+ console.log(c.underline(`$ <pm exec> prisma ${args.join(" ")}`));
61
64
  console.log();
62
65
  try {
63
66
  runTransitiveBinSync("prisma", args, {
@@ -6,6 +6,7 @@ import { terminalLink } from "termi-link";
6
6
  import * as apiServerCLIConfig from "@cedarjs/api-server/apiCliConfig";
7
7
  import * as bothServerCLIConfig from "@cedarjs/api-server/bothCliConfig";
8
8
  import { recordTelemetryAttributes, colors as c } from "@cedarjs/cli-helpers";
9
+ import { projectIsEsm } from "@cedarjs/project-config";
9
10
  import * as webServerCLIConfig from "@cedarjs/web-server";
10
11
  import { getPaths, getConfig } from "../lib/index.js";
11
12
  import { serverFileExists } from "../lib/project.js";
@@ -161,7 +162,12 @@ const builder = async (yargs) => {
161
162
  const serveBothHandlers = await import("./serveBothHandler.js");
162
163
  await serveBothHandlers.bothSsrRscServerHandler(argv, rscEnabled);
163
164
  } else {
164
- await bothServerCLIConfig.handler(argv);
165
+ if (!projectIsEsm()) {
166
+ const { handler } = await import("@cedarjs/api-server/cjs/bothCliConfigHandler");
167
+ await handler(argv);
168
+ } else {
169
+ await bothServerCLIConfig.handler(argv);
170
+ }
165
171
  }
166
172
  }
167
173
  }).command({
@@ -213,7 +219,12 @@ const builder = async (yargs) => {
213
219
  const { apiServerFileHandler } = await import("./serveApiHandler.js");
214
220
  await apiServerFileHandler(argv);
215
221
  } else {
216
- await apiServerCLIConfig.handler(argv);
222
+ if (!projectIsEsm()) {
223
+ const { handler } = await import("@cedarjs/api-server/cjs/apiCliConfigHandler");
224
+ await handler(argv);
225
+ } else {
226
+ await apiServerCLIConfig.handler(argv);
227
+ }
217
228
  }
218
229
  }
219
230
  }).command({
@@ -1,13 +1,13 @@
1
1
  import path from "path";
2
2
  import concurrently from "concurrently";
3
- import { handler as apiServerHandler } from "@cedarjs/api-server/apiCliConfigHandler";
3
+ import { handler as apiServerHandler } from "@cedarjs/api-server/cjs/apiCliConfigHandler";
4
4
  import {
5
5
  getAPIHost,
6
6
  getAPIPort,
7
7
  getAPIRootPath,
8
8
  getWebHost,
9
9
  getWebPort
10
- } from "@cedarjs/api-server/cliHelpers";
10
+ } from "@cedarjs/api-server/cjs/cliHelpers";
11
11
  import { formatRunBinCommand } from "@cedarjs/cli-helpers/packageManager/display";
12
12
  import { runBin } from "@cedarjs/cli-helpers/packageManager/exec";
13
13
  import { getConfig, getPaths } from "@cedarjs/project-config";
@@ -237,7 +237,7 @@ async function getAuthSetupHandler(module) {
237
237
  });
238
238
  }
239
239
  const setupModule = await import(module);
240
- return setupModule.handler;
240
+ return setupModule.default.handler;
241
241
  }
242
242
  function isInstalled(module) {
243
243
  const { dependencies, devDependencies } = JSON.parse(
@@ -4,6 +4,7 @@ import * as parser from "@babel/parser";
4
4
  import * as t from "@babel/types";
5
5
  import execa from "execa";
6
6
  import { Listr } from "listr2";
7
+ import * as recast from "recast";
7
8
  import { getConfigPath, getConfig } from "@cedarjs/project-config";
8
9
  import { getPaths, writeFilesTask } from "../../../../lib/index.js";
9
10
  const updateApiURLTask = (apiUrl) => {
@@ -87,6 +88,14 @@ const verifyUDSetupTask = () => {
87
88
  }
88
89
  };
89
90
  };
91
+ function posToIndex(str, line, column) {
92
+ const lines = str.split("\n");
93
+ let index = 0;
94
+ for (let i = 0; i < line - 1; i++) {
95
+ index += lines[i].length + 1;
96
+ }
97
+ return index + column;
98
+ }
90
99
  function resolveConfigObject(arg) {
91
100
  if (t.isObjectExpression(arg)) {
92
101
  return arg;
@@ -118,9 +127,15 @@ function insertPluginsBeforeCedar({
118
127
  content,
119
128
  pluginCodes
120
129
  }) {
121
- const ast = parser.parse(content, {
122
- sourceType: "module",
123
- plugins: ["typescript", "jsx"]
130
+ const ast = recast.parse(content, {
131
+ parser: {
132
+ parse(source) {
133
+ return parser.parse(source, {
134
+ sourceType: "module",
135
+ plugins: ["typescript", "jsx"]
136
+ });
137
+ }
138
+ }
124
139
  });
125
140
  const defaultExport = ast.program.body.find(t.isExportDefaultDeclaration);
126
141
  if (!defaultExport) {
@@ -148,18 +163,33 @@ function insertPluginsBeforeCedar({
148
163
  return null;
149
164
  }
150
165
  const cedarNode = cedarElement;
151
- if (!cedarNode.loc || !arrayExpr.loc || !pluginsProp.loc || cedarNode.start == null || arrayExpr.start == null || arrayExpr.end == null) {
166
+ if (!cedarNode.loc || !arrayExpr.loc || !pluginsProp.loc) {
152
167
  return null;
153
168
  }
154
169
  const isInline = cedarNode.loc.start.line === arrayExpr.loc.start.line;
155
170
  if (isInline) {
156
- const precedingText = content.slice(0, arrayExpr.start);
157
- const followingText = content.slice(arrayExpr.end);
171
+ const startPos = posToIndex(
172
+ content,
173
+ arrayExpr.loc.start.line,
174
+ arrayExpr.loc.start.column
175
+ );
176
+ const endPos = posToIndex(
177
+ content,
178
+ arrayExpr.loc.end.line,
179
+ arrayExpr.loc.end.column
180
+ );
181
+ const precedingText = content.slice(0, startPos);
182
+ const followingText = content.slice(endPos);
158
183
  const existingCodes = elements.flatMap((el) => {
159
- if (el?.start == null || el.end == null) {
184
+ if (!el?.loc) {
160
185
  return [];
161
186
  }
162
- return [content.slice(el.start, el.end)];
187
+ return [
188
+ content.slice(
189
+ posToIndex(content, el.loc.start.line, el.loc.start.column),
190
+ posToIndex(content, el.loc.end.line, el.loc.end.column)
191
+ )
192
+ ];
163
193
  });
164
194
  const lines2 = content.split("\n");
165
195
  const pluginsLine = pluginsProp.loc.start.line;
@@ -175,7 +205,7 @@ function insertPluginsBeforeCedar({
175
205
  return precedingText + multiline + followingText;
176
206
  }
177
207
  const cedarLine = cedarNode.loc.start.line;
178
- const insertPos = cedarNode.start - cedarNode.loc.start.column;
208
+ const insertPos = posToIndex(content, cedarLine, 0);
179
209
  const lines = content.split("\n");
180
210
  const indent = (lines[cedarLine - 1].match(/^\s*/) ?? [""])[0];
181
211
  const insertion = pluginCodes.map((code) => `${indent}${code},
@@ -16,10 +16,6 @@ import {
16
16
  mysqlDatabaseService
17
17
  } from "../templates/flightcontrol.js";
18
18
  const { getConfig } = prismaInternals;
19
- const APOLLO_PROVIDER_COMPONENT_NAMES = [
20
- "CedarApolloProvider",
21
- "RedwoodApolloProvider"
22
- ];
23
19
  const getFlightcontrolJson = async (database) => {
24
20
  const flightcontrolConfig = getFlightcontrolConfig();
25
21
  if (database === "none") {
@@ -209,26 +205,18 @@ const updateApp = () => {
209
205
  appContent[authLineIndex] = ` <AuthProvider type="dbAuth" config={{ fetchConfig: { credentials: 'include' } }}>
210
206
  `;
211
207
  }
212
- let gqlLineIndex = -1;
213
- let apolloProviderComponentName = "";
214
- for (const componentName of APOLLO_PROVIDER_COMPONENT_NAMES) {
215
- gqlLineIndex = appContent.findIndex(
216
- (line) => line.includes(`<${componentName}`)
217
- );
218
- if (gqlLineIndex !== -1) {
219
- apolloProviderComponentName = componentName;
220
- break;
221
- }
222
- }
208
+ const gqlLineIndex = appContent.findIndex(
209
+ (line) => line.includes("<RedwoodApolloProvider")
210
+ );
223
211
  if (gqlLineIndex === -1) {
224
212
  console.log(`
225
- Couldn't find <CedarApolloProvider in web/src/App.js
213
+ Couldn't find <RedwoodApolloProvider in web/src/App.js
226
214
  If (and when) you use *dbAuth*, you'll have to add the following fetch config manually:
227
215
 
228
216
  graphQLClientConfig={{ httpLinkConfig: { credentials: 'include' }}}
229
217
  `);
230
218
  } else if (appContent.toString().match(/dbAuth/)) {
231
- appContent[gqlLineIndex] = ` <${apolloProviderComponentName} graphQLClientConfig={{ httpLinkConfig: { credentials: 'include' }}} >
219
+ appContent[gqlLineIndex] = ` <RedwoodApolloProvider graphQLClientConfig={{ httpLinkConfig: { credentials: 'include' }}} >
232
220
  `;
233
221
  }
234
222
  fs.writeFileSync(appPath, appContent.join(EOL));
@@ -16,11 +16,8 @@ function isPropertyWithName(node, name) {
16
16
  function transform(file, api) {
17
17
  const j = api.jscodeshift;
18
18
  const root = j(file.source);
19
- let apolloProviderElements = root.findJSXElements("CedarApolloProvider");
20
- if (apolloProviderElements.length === 0) {
21
- apolloProviderElements = root.findJSXElements("RedwoodApolloProvider");
22
- }
23
- const graphQLClientConfigCollection = apolloProviderElements.find(
19
+ const redwoodApolloProvider = root.findJSXElements("RedwoodApolloProvider");
20
+ const graphQLClientConfigCollection = redwoodApolloProvider.find(
24
21
  j.JSXAttribute,
25
22
  {
26
23
  name: { name: "graphQLClientConfig" }
@@ -107,7 +104,7 @@ function transform(file, api) {
107
104
  cacheConfigValue.properties.push(property);
108
105
  }
109
106
  graphQLClientConfigCollection.remove();
110
- apolloProviderElements.get(0).node.openingElement.attributes.push(
107
+ redwoodApolloProvider.get(0).node.openingElement.attributes.push(
111
108
  j.jsxAttribute(
112
109
  j.jsxIdentifier("graphQLClientConfig"),
113
110
  j.jsxExpressionContainer(j.identifier(graphQLClientConfigVariableName))
@@ -24,35 +24,15 @@ function getPersistenceDirectory() {
24
24
  persistenceDirectory = path.join(getPaths().generated.base, "updateCheck");
25
25
  return persistenceDirectory;
26
26
  }
27
- function getLocalVersion() {
28
- let version;
27
+ async function check() {
29
28
  try {
29
+ console.time("Update Check");
30
30
  const packageJson = JSON.parse(
31
31
  fs.readFileSync(path.join(getPaths().base, "package.json"), "utf-8")
32
32
  );
33
- version = packageJson.devDependencies?.["@cedarjs/core"];
34
- } catch {
35
- return void 0;
36
- }
37
- if (typeof version === "string" && semver.valid(version)) {
38
- return version;
39
- }
40
- return void 0;
41
- }
42
- async function check() {
43
- try {
44
- console.time("Update Check");
45
- const localVersion = getLocalVersion();
46
- if (!localVersion) {
47
- console.log(
48
- "Skipping update check: no pinned @cedarjs/core version found"
49
- );
50
- updateUpdateDataFile({
51
- localVersion: "0.0.0",
52
- remoteVersions: /* @__PURE__ */ new Map(),
53
- checkedAt: (/* @__PURE__ */ new Date()).getTime()
54
- });
55
- return;
33
+ let localVersion = packageJson.devDependencies["@cedarjs/core"];
34
+ while (!/\d/.test(localVersion.charAt(0))) {
35
+ localVersion = localVersion.substring(1);
56
36
  }
57
37
  console.log(`Detected the current version of Cedar: '${localVersion}'`);
58
38
  const remoteVersions = /* @__PURE__ */ new Map();
@@ -89,24 +69,16 @@ function shouldCheck() {
89
69
  return false;
90
70
  }
91
71
  const data = readUpdateDataFile();
92
- const localVersion = getLocalVersion();
93
- if (localVersion && localVersion !== data.localVersion) {
94
- return true;
95
- }
96
72
  return data.checkedAt < (/* @__PURE__ */ new Date()).getTime() - CHECK_PERIOD;
97
73
  }
98
74
  function shouldShow() {
99
75
  if (isLockSet(SHOW_LOCK_IDENTIFIER)) {
100
76
  return false;
101
77
  }
102
- const localVersion = getLocalVersion();
103
- if (!localVersion) {
104
- return false;
105
- }
106
78
  const data = readUpdateDataFile();
107
79
  let newerVersion = false;
108
80
  data.remoteVersions.forEach((version) => {
109
- newerVersion ||= semver.gt(version, localVersion);
81
+ newerVersion ||= semver.gt(version, data.localVersion);
110
82
  });
111
83
  return data.shownAt < (/* @__PURE__ */ new Date()).getTime() - SHOW_PERIOD && newerVersion;
112
84
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cedarjs/cli",
3
- "version": "5.0.4-next.167",
3
+ "version": "5.0.4-rc.3",
4
4
  "description": "The CedarJS Command Line",
5
5
  "repository": {
6
6
  "type": "git",
@@ -33,18 +33,18 @@
33
33
  "dependencies": {
34
34
  "@babel/parser": "7.29.7",
35
35
  "@babel/preset-typescript": "7.29.7",
36
- "@cedarjs/api-server": "5.0.4-next.167",
37
- "@cedarjs/cli-helpers": "5.0.4-next.167",
38
- "@cedarjs/fastify-web": "5.0.4-next.167",
39
- "@cedarjs/internal": "5.0.4-next.167",
40
- "@cedarjs/prerender": "5.0.4-next.167",
41
- "@cedarjs/project-config": "5.0.4-next.167",
42
- "@cedarjs/structure": "5.0.4-next.167",
43
- "@cedarjs/telemetry": "5.0.4-next.167",
44
- "@cedarjs/utils": "5.0.4-next.167",
45
- "@cedarjs/vite": "5.0.4-next.167",
46
- "@cedarjs/web-server": "5.0.4-next.167",
47
- "@listr2/prompt-adapter-enquirer": "4.3.0",
36
+ "@cedarjs/api-server": "5.0.4-rc.3",
37
+ "@cedarjs/cli-helpers": "5.0.4-rc.3",
38
+ "@cedarjs/fastify-web": "5.0.4-rc.3",
39
+ "@cedarjs/internal": "5.0.4-rc.3",
40
+ "@cedarjs/prerender": "5.0.4-rc.3",
41
+ "@cedarjs/project-config": "5.0.4-rc.3",
42
+ "@cedarjs/structure": "5.0.4-rc.3",
43
+ "@cedarjs/telemetry": "5.0.4-rc.3",
44
+ "@cedarjs/utils": "5.0.4-rc.3",
45
+ "@cedarjs/vite": "5.0.4-rc.3",
46
+ "@cedarjs/web-server": "5.0.4-rc.3",
47
+ "@listr2/prompt-adapter-enquirer": "4.2.1",
48
48
  "@opentelemetry/api": "1.9.1",
49
49
  "@opentelemetry/core": "1.30.1",
50
50
  "@opentelemetry/exporter-trace-otlp-http": "0.57.2",
@@ -52,7 +52,7 @@
52
52
  "@opentelemetry/sdk-trace-node": "1.30.1",
53
53
  "@opentelemetry/semantic-conventions": "1.41.1",
54
54
  "@prisma/internals": "7.8.0",
55
- "ansis": "4.3.1",
55
+ "ansis": "4.2.0",
56
56
  "archiver": "7.0.1",
57
57
  "boxen": "5.1.2",
58
58
  "camel-case": "4.1.2",
@@ -69,7 +69,7 @@
69
69
  "execa": "5.1.1",
70
70
  "fast-glob": "3.3.3",
71
71
  "humanize-string": "2.1.0",
72
- "jscodeshift": "17.4.0",
72
+ "jscodeshift": "17.3.0",
73
73
  "jsonc-parser": "3.3.1",
74
74
  "latest-version": "9.0.0",
75
75
  "listr2": "10.2.2",
@@ -80,6 +80,7 @@
80
80
  "prettier": "3.8.4",
81
81
  "prisma": "7.8.0",
82
82
  "prompts": "2.4.2",
83
+ "recast": "0.23.11",
83
84
  "rimraf": "6.1.3",
84
85
  "semver": "7.7.4",
85
86
  "smol-toml": "1.6.1",
@@ -101,7 +102,7 @@
101
102
  "node-ssh": "13.2.1",
102
103
  "ts-dedent": "2.3.0",
103
104
  "typescript": "5.9.3",
104
- "vitest": "4.1.10"
105
+ "vitest": "3.2.6"
105
106
  },
106
107
  "engines": {
107
108
  "node": ">=24"