@cedarjs/cli 2.3.0 → 2.3.1-next.79

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 (36) hide show
  1. package/dist/commands/{buildHandler.js → build/buildHandler.js} +42 -34
  2. package/dist/commands/build/buildPackagesTask.js +46 -0
  3. package/dist/commands/build.js +22 -8
  4. package/dist/commands/dev/apiDebugFlag.js +18 -0
  5. package/dist/commands/{devHandler.js → dev/devHandler.js} +60 -64
  6. package/dist/commands/dev/packageWatchCommands.js +54 -0
  7. package/dist/commands/dev.js +25 -7
  8. package/dist/commands/generate/cell/cellHandler.js +3 -1
  9. package/dist/commands/generate/component/templates/test.tsx.template +1 -1
  10. package/dist/commands/generate/function/functionHandler.js +1 -1
  11. package/dist/commands/generate/function/templates/function.ts.template +1 -1
  12. package/dist/commands/generate/function/templates/test.ts.template +11 -11
  13. package/dist/commands/generate/layout/templates/test.tsx.template +1 -1
  14. package/dist/commands/generate/package/packageHandler.js +23 -0
  15. package/dist/commands/generate/package/templates/README.md.template +1 -1
  16. package/dist/commands/generate/package/templates/package.json.template +7 -0
  17. package/dist/commands/generate/package/templates/tsconfig.json.template +1 -0
  18. package/dist/commands/generate/page/templates/test.tsx.template +1 -1
  19. package/dist/commands/setup/deploy/templates/netlify.js +7 -6
  20. package/dist/commands/setup/mailer/templates/mailer.ts.template +2 -1
  21. package/dist/commands/studio.js +1 -1
  22. package/dist/commands/studioHandler.js +1 -29
  23. package/dist/commands/test.js +2 -2
  24. package/dist/commands/testEsm.js +2 -2
  25. package/dist/commands/testHandler.js +3 -3
  26. package/dist/commands/testHandlerEsm.js +3 -3
  27. package/dist/commands/type-check.js +2 -2
  28. package/dist/index.js +39 -18
  29. package/dist/lib/generatePrismaClient.js +6 -2
  30. package/dist/lib/index.js +2 -3
  31. package/dist/lib/merge/algorithms.js +1 -1
  32. package/dist/lib/merge/index.js +3 -2
  33. package/dist/lib/merge/strategy.js +4 -4
  34. package/dist/lib/project.js +24 -10
  35. package/dist/lib/test.js +1 -1
  36. package/package.json +13 -12
@@ -10,28 +10,37 @@ import { generate } from "@cedarjs/internal/dist/generate/generate";
10
10
  import { loadAndValidateSdls } from "@cedarjs/internal/dist/validateSchema";
11
11
  import { detectPrerenderRoutes } from "@cedarjs/prerender/detection";
12
12
  import { timedTelemetry } from "@cedarjs/telemetry";
13
- import { generatePrismaCommand } from "../lib/generatePrismaClient.js";
14
- import { getPaths, getConfig } from "../lib/index.js";
13
+ import { generatePrismaCommand } from "../../lib/generatePrismaClient.js";
14
+ import { getPaths, getConfig } from "../../lib/index.js";
15
+ import { buildPackagesTask } from "./buildPackagesTask.js";
15
16
  const handler = async ({
16
- side = ["api", "web"],
17
+ workspace = ["api", "web", "packages/*"],
17
18
  verbose = false,
18
19
  prisma = true,
19
- prerender
20
+ prerender = true
20
21
  }) => {
21
22
  recordTelemetryAttributes({
22
23
  command: "build",
23
- side: JSON.stringify(side),
24
+ workspace: JSON.stringify(workspace),
24
25
  verbose,
25
26
  prisma,
26
27
  prerender
27
28
  });
28
- const rwjsPaths = getPaths();
29
- const rwjsConfig = getConfig();
30
- const useFragments = rwjsConfig.graphql?.fragments;
31
- const useTrustedDocuments = rwjsConfig.graphql?.trustedDocuments;
32
- const prismaSchemaExists = fs.existsSync(rwjsPaths.api.prismaConfig);
33
- const prerenderRoutes = prerender && side.includes("web") ? detectPrerenderRoutes() : [];
34
- const shouldGeneratePrismaClient = prisma && prismaSchemaExists && (side.includes("api") || prerenderRoutes.length > 0);
29
+ const cedarPaths = getPaths();
30
+ const cedarConfig = getConfig();
31
+ const useFragments = cedarConfig.graphql?.fragments;
32
+ const useTrustedDocuments = cedarConfig.graphql?.trustedDocuments;
33
+ const prismaSchemaExists = fs.existsSync(cedarPaths.api.prismaConfig);
34
+ const prerenderRoutes = prerender && workspace.includes("web") ? detectPrerenderRoutes() : [];
35
+ const shouldGeneratePrismaClient = prisma && prismaSchemaExists && (workspace.includes("api") || prerenderRoutes.length > 0);
36
+ const packageJsonPath = path.join(cedarPaths.base, "package.json");
37
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
38
+ const packageJsonWorkspaces = packageJson.workspaces;
39
+ const nonApiWebWorkspaces = Array.isArray(packageJsonWorkspaces) && packageJsonWorkspaces.length > 2 ? workspace.filter((w) => w !== "api" && w !== "web") : [];
40
+ const gqlFeaturesTaskTitle = `Generating types needed for ${[
41
+ useFragments && "GraphQL Fragments",
42
+ useTrustedDocuments && "Trusted Documents"
43
+ ].filter(Boolean).join(" and ")} support...`;
35
44
  const tasks = [
36
45
  shouldGeneratePrismaClient && {
37
46
  title: "Generating Prisma Client...",
@@ -39,28 +48,26 @@ const handler = async ({
39
48
  const { cmd, args } = await generatePrismaCommand();
40
49
  return execa(cmd, args, {
41
50
  stdio: verbose ? "inherit" : "pipe",
42
- shell: true,
43
- cwd: rwjsPaths.api.base
51
+ cwd: cedarPaths.api.base
44
52
  });
45
53
  }
46
54
  },
55
+ nonApiWebWorkspaces.length > 0 && {
56
+ title: "Building Packages...",
57
+ task: () => buildPackagesTask(nonApiWebWorkspaces)
58
+ },
47
59
  // If using GraphQL Fragments or Trusted Documents, then we need to use
48
- // codegen to generate the types needed for possible types and the
49
- // trusted document store hashes
60
+ // codegen to generate the types needed for possible types and the trusted
61
+ // document store hashes
50
62
  (useFragments || useTrustedDocuments) && {
51
- title: `Generating types needed for ${[
52
- useFragments && "GraphQL Fragments",
53
- useTrustedDocuments && "Trusted Documents"
54
- ].filter(Boolean).join(" and ")} support...`,
55
- task: async () => {
56
- await generate();
57
- }
63
+ title: gqlFeaturesTaskTitle,
64
+ task: generate
58
65
  },
59
- side.includes("api") && {
66
+ workspace.includes("api") && {
60
67
  title: "Verifying graphql schema...",
61
68
  task: loadAndValidateSdls
62
69
  },
63
- side.includes("api") && {
70
+ workspace.includes("api") && {
64
71
  title: "Building API...",
65
72
  task: async () => {
66
73
  await cleanApiBuild();
@@ -73,22 +80,23 @@ const handler = async ({
73
80
  }
74
81
  }
75
82
  },
76
- side.includes("web") && {
83
+ workspace.includes("web") && {
77
84
  title: "Building Web...",
78
85
  task: async () => {
79
86
  process.env.VITE_CJS_IGNORE_WARNING = "true";
80
87
  const createdRequire = createRequire(import.meta.url);
88
+ const buildBinPath = createdRequire.resolve(
89
+ "@cedarjs/vite/bins/rw-vite-build.mjs"
90
+ );
81
91
  await execa(
82
- `node ${createdRequire.resolve(
83
- "@cedarjs/vite/bins/rw-vite-build.mjs"
84
- )} --webDir="${rwjsPaths.web.base}" --verbose=${verbose}`,
92
+ `node ${buildBinPath} --webDir="${cedarPaths.web.base}" --verbose=${verbose}`,
85
93
  {
86
94
  stdio: verbose ? "inherit" : "pipe",
87
95
  shell: true,
88
96
  // `cwd` is needed for yarn to find the rw-vite-build binary
89
97
  // It won't change process.cwd for anything else here, in this
90
98
  // process
91
- cwd: rwjsPaths.web.base
99
+ cwd: cedarPaths.web.base
92
100
  }
93
101
  );
94
102
  if (!getConfig().experimental?.streamingSsr?.enabled) {
@@ -108,7 +116,7 @@ const handler = async ({
108
116
  console.log(
109
117
  `You have not marked any routes to "prerender" in your ${terminalLink(
110
118
  "Routes",
111
- "file://" + rwjsPaths.web.routes
119
+ "file://" + cedarPaths.web.routes
112
120
  )}.`
113
121
  );
114
122
  return;
@@ -116,15 +124,15 @@ const handler = async ({
116
124
  await execa("yarn cedar prerender", {
117
125
  stdio: "inherit",
118
126
  shell: true,
119
- cwd: rwjsPaths.web.base
127
+ cwd: cedarPaths.web.base
120
128
  });
121
129
  };
122
130
  const jobs = new Listr(tasks, {
123
- renderer: verbose && "verbose"
131
+ renderer: verbose ? "verbose" : void 0
124
132
  });
125
133
  await timedTelemetry(process.argv, { type: "build" }, async () => {
126
134
  await jobs.run();
127
- if (side.includes("web") && prerender && prismaSchemaExists) {
135
+ if (workspace.includes("web") && prerender && prismaSchemaExists) {
128
136
  await triggerPrerender();
129
137
  }
130
138
  });
@@ -0,0 +1,46 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import concurrently from "concurrently";
4
+ import { importStatementPath } from "@cedarjs/project-config";
5
+ import { errorTelemetry } from "@cedarjs/telemetry";
6
+ import { exitWithError } from "../../lib/exit.js";
7
+ import { getPaths } from "../../lib/index.js";
8
+ async function buildPackagesTask(nonApiWebWorkspaces) {
9
+ const cedarPaths = getPaths();
10
+ const globPattern = path.join(cedarPaths.packages, "*").replaceAll("\\", "/");
11
+ const workspacePaths = nonApiWebWorkspaces.some((w) => w === "packages/*") ? await Array.fromAsync(fs.promises.glob(globPattern)) : nonApiWebWorkspaces.map((w) => {
12
+ const workspacePath = path.join(
13
+ cedarPaths.packages,
14
+ w.split("/").at(-1)
15
+ );
16
+ if (!fs.existsSync(workspacePath)) {
17
+ throw new Error(`Workspace not found: ${workspacePath}`);
18
+ }
19
+ return importStatementPath(workspacePath);
20
+ });
21
+ const { result } = concurrently(
22
+ workspacePaths.map((workspacePath) => {
23
+ return {
24
+ command: `yarn build`,
25
+ name: workspacePath.split("/").at(-1),
26
+ cwd: workspacePath
27
+ };
28
+ }),
29
+ {
30
+ prefix: "{name} |",
31
+ timestampFormat: "HH:mm:ss"
32
+ }
33
+ );
34
+ await result.catch((e) => {
35
+ if (e?.message) {
36
+ errorTelemetry(
37
+ process.argv,
38
+ `Error concurrently building sides: ${e.message}`
39
+ );
40
+ exitWithError(e);
41
+ }
42
+ });
43
+ }
44
+ export {
45
+ buildPackagesTask
46
+ };
@@ -1,16 +1,14 @@
1
1
  import { terminalLink } from "termi-link";
2
2
  import c from "../lib/colors.js";
3
3
  import { exitWithError } from "../lib/exit.js";
4
- import { sides } from "../lib/project.js";
4
+ import { workspaces } from "../lib/project.js";
5
5
  import { checkNodeVersion } from "../middleware/checkNodeVersion.js";
6
- const command = "build [side..]";
6
+ const command = "build [workspace..]";
7
7
  const description = "Build for production";
8
8
  const builder = (yargs) => {
9
- const choices = sides();
10
- yargs.positional("side", {
11
- choices,
12
- default: choices,
13
- description: "Which side(s) to build",
9
+ yargs.positional("workspace", {
10
+ default: ["api", "web", "packages/*"],
11
+ description: "What workspace(s) to build. Valid values are: web, api, packages/*, <package-name>",
14
12
  type: "array"
15
13
  }).option("verbose", {
16
14
  alias: "v",
@@ -35,6 +33,22 @@ const builder = (yargs) => {
35
33
  message: `${c.error("Error")}: ${check.message}`,
36
34
  includeEpilogue: false
37
35
  });
36
+ }).check((argv) => {
37
+ const workspacesArg = argv.workspace;
38
+ if (!Array.isArray(workspacesArg)) {
39
+ return "Workspace must be an array";
40
+ }
41
+ const filtered = workspacesArg.filter(
42
+ (item) => item !== "api" && item !== "web" && item !== "packages/*"
43
+ );
44
+ if (filtered.length === 0) {
45
+ return true;
46
+ }
47
+ const workspaceNames = workspaces({ includePackages: true });
48
+ if (!workspacesArg.every((item) => workspaceNames.includes(item))) {
49
+ return c.error(`Unknown workspace(s) ${workspacesArg.join(" ")}`) + "\n\nValid values are: " + workspaceNames.join(", ");
50
+ }
51
+ return true;
38
52
  }).epilogue(
39
53
  `Also see the ${terminalLink(
40
54
  "CedarJS CLI Reference",
@@ -43,7 +57,7 @@ const builder = (yargs) => {
43
57
  );
44
58
  };
45
59
  const handler = async (options) => {
46
- const { handler: handler2 } = await import("./buildHandler.js");
60
+ const { handler: handler2 } = await import("./build/buildHandler.js");
47
61
  return handler2(options);
48
62
  };
49
63
  export {
@@ -0,0 +1,18 @@
1
+ import { argv } from "node:process";
2
+ import { getConfig } from "@cedarjs/project-config";
3
+ const defaultApiDebugPort = 18911;
4
+ function getApiDebugFlag(apiDebugPort) {
5
+ if (apiDebugPort) {
6
+ return `--debug-port ${apiDebugPort}`;
7
+ } else if (argv.includes("--apiDebugPort")) {
8
+ return `--debug-port ${defaultApiDebugPort}`;
9
+ }
10
+ const apiDebugPortInConfig = getConfig().api.debugPort;
11
+ if (apiDebugPortInConfig) {
12
+ return `--debug-port ${apiDebugPortInConfig}`;
13
+ }
14
+ return "";
15
+ }
16
+ export {
17
+ getApiDebugFlag
18
+ };
@@ -1,30 +1,30 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
- import { argv } from "node:process";
4
3
  import concurrently from "concurrently";
5
4
  import { recordTelemetryAttributes } from "@cedarjs/cli-helpers";
6
5
  import { shutdownPort } from "@cedarjs/internal/dist/dev";
7
6
  import { getConfig, getConfigPath } from "@cedarjs/project-config";
8
7
  import { errorTelemetry } from "@cedarjs/telemetry";
9
- import c from "../lib/colors.js";
10
- import { exitWithError } from "../lib/exit.js";
11
- import { generatePrismaClient } from "../lib/generatePrismaClient.js";
12
- import { getPaths } from "../lib/index.js";
13
- import { getFreePort } from "../lib/ports.js";
14
- import { serverFileExists } from "../lib/project.js";
15
- const defaultApiDebugPort = 18911;
8
+ import c from "../../lib/colors.js";
9
+ import { exitWithError } from "../../lib/exit.js";
10
+ import { generatePrismaClient } from "../../lib/generatePrismaClient.js";
11
+ import { getPaths } from "../../lib/index.js";
12
+ import { getFreePort } from "../../lib/ports.js";
13
+ import { serverFileExists } from "../../lib/project.js";
14
+ import { getApiDebugFlag } from "./apiDebugFlag.js";
15
+ import { getPackageWatchCommands } from "./packageWatchCommands.js";
16
16
  const handler = async ({
17
- side = ["api", "web"],
17
+ workspace = ["api", "web", "packages/*"],
18
18
  forward = "",
19
19
  generate = true,
20
20
  apiDebugPort
21
21
  }) => {
22
22
  recordTelemetryAttributes({
23
23
  command: "dev",
24
- side: JSON.stringify(side),
24
+ workspace: JSON.stringify(workspace),
25
25
  generate
26
26
  });
27
- const rwjsPaths = getPaths();
27
+ const cedarPaths = getPaths();
28
28
  const serverFile = serverFileExists();
29
29
  const apiPreferredPort = parseInt(String(getConfig().api.port));
30
30
  let webPreferredPort = parseInt(
@@ -34,7 +34,7 @@ const handler = async ({
34
34
  let apiPortChangeNeeded = false;
35
35
  let webAvailablePort = webPreferredPort;
36
36
  let webPortChangeNeeded = false;
37
- if (side.includes("api") && !serverFile) {
37
+ if (workspace.includes("api") && !serverFile) {
38
38
  apiAvailablePort = await getFreePort(apiPreferredPort);
39
39
  if (apiAvailablePort === -1) {
40
40
  exitWithError(void 0, {
@@ -43,7 +43,7 @@ const handler = async ({
43
43
  }
44
44
  apiPortChangeNeeded = apiAvailablePort !== apiPreferredPort;
45
45
  }
46
- if (side.includes("web")) {
46
+ if (workspace.includes("web")) {
47
47
  const forwardedPortMatches = [
48
48
  ...forward.matchAll(/\-\-port(\=|\s)(?<port>[^\s]*)/g)
49
49
  ];
@@ -80,14 +80,14 @@ const handler = async ({
80
80
  ].filter(Boolean).join(" ");
81
81
  exitWithError(void 0, { message });
82
82
  }
83
- if (side.includes("api")) {
83
+ if (workspace.includes("api")) {
84
84
  try {
85
85
  await generatePrismaClient({
86
86
  verbose: false,
87
87
  force: false
88
88
  });
89
89
  } catch (e) {
90
- const message = e instanceof Object && "message" in e ? e.message : String(e);
90
+ const message = getErrorMessage(e);
91
91
  errorTelemetry(process.argv, `Error generating prisma client: ${message}`);
92
92
  console.error(c.error(message));
93
93
  }
@@ -95,7 +95,7 @@ const handler = async ({
95
95
  try {
96
96
  await shutdownPort(apiAvailablePort);
97
97
  } catch (e) {
98
- const message = e instanceof Object && "message" in e ? e.message : String(e);
98
+ const message = getErrorMessage(e);
99
99
  errorTelemetry(process.argv, `Error shutting down "api": ${message}`);
100
100
  console.error(
101
101
  `Error whilst shutting down "api" port: ${c.error(message)}`
@@ -103,51 +103,41 @@ const handler = async ({
103
103
  }
104
104
  }
105
105
  }
106
- if (side.includes("web")) {
106
+ if (workspace.includes("web")) {
107
107
  try {
108
108
  await shutdownPort(webAvailablePort);
109
109
  } catch (e) {
110
- const message = e instanceof Object && "message" in e ? e.message : String(e);
110
+ const message = getErrorMessage(e);
111
111
  errorTelemetry(process.argv, `Error shutting down "web": ${message}`);
112
112
  console.error(
113
113
  `Error whilst shutting down "web" port: ${c.error(message)}`
114
114
  );
115
115
  }
116
116
  }
117
- const getApiDebugFlag = () => {
118
- if (apiDebugPort) {
119
- return `--debug-port ${apiDebugPort}`;
120
- } else if (argv.includes("--apiDebugPort")) {
121
- return `--debug-port ${defaultApiDebugPort}`;
122
- }
123
- const apiDebugPortInToml = getConfig().api.debugPort;
124
- if (apiDebugPortInToml) {
125
- return `--debug-port ${apiDebugPortInToml}`;
126
- }
127
- return "";
128
- };
129
- const redwoodConfigPath = getConfigPath();
117
+ const cedarConfigPath = getConfigPath();
130
118
  const streamingSsrEnabled = getConfig().experimental?.streamingSsr?.enabled;
131
119
  process.env.VITE_CJS_IGNORE_WARNING = "true";
132
120
  let webCommand = `yarn cross-env NODE_ENV=development rw-vite-dev ${forward}`;
133
121
  if (streamingSsrEnabled) {
134
122
  webCommand = `yarn cross-env NODE_ENV=development rw-dev-fe ${forward}`;
135
123
  }
124
+ const rootPackageJsonPath = path.join(cedarPaths.base, "package.json");
136
125
  const rootPackageJson = JSON.parse(
137
- fs.readFileSync(path.join(rwjsPaths.base, "package.json"), "utf8")
126
+ fs.readFileSync(rootPackageJsonPath, "utf8")
138
127
  );
139
128
  const isEsm = rootPackageJson.type === "module";
140
129
  const serverWatchCommand = isEsm ? `cedarjs-api-server-watch` : `rw-api-server-watch`;
141
- const jobs = {
142
- api: {
130
+ const jobs = [];
131
+ if (workspace.includes("api")) {
132
+ jobs.push({
143
133
  name: "api",
144
134
  command: [
145
135
  "yarn nodemon",
146
136
  " --quiet",
147
- ` --watch "${redwoodConfigPath}"`,
137
+ ` --watch "${cedarConfigPath}"`,
148
138
  ` --exec "yarn ${serverWatchCommand}`,
149
139
  ` --port ${apiAvailablePort}`,
150
- ` ${getApiDebugFlag()}`,
140
+ ` ${getApiDebugFlag(apiDebugPort)}`,
151
141
  ' | rw-log-formatter"'
152
142
  ].join(" ").replace(/\s+/g, " "),
153
143
  env: {
@@ -155,45 +145,48 @@ const handler = async ({
155
145
  NODE_OPTIONS: getDevNodeOptions()
156
146
  },
157
147
  prefixColor: "cyan",
158
- runWhen: () => fs.existsSync(rwjsPaths.api.src)
159
- },
160
- web: {
148
+ runWhen: () => fs.existsSync(cedarPaths.api.src)
149
+ });
150
+ }
151
+ if (workspace.includes("web")) {
152
+ jobs.push({
161
153
  name: "web",
162
154
  command: webCommand,
163
155
  prefixColor: "blue",
164
- cwd: rwjsPaths.web.base,
165
- runWhen: () => fs.existsSync(rwjsPaths.web.src)
166
- },
167
- gen: {
156
+ cwd: cedarPaths.web.base,
157
+ runWhen: () => fs.existsSync(cedarPaths.web.src)
158
+ });
159
+ }
160
+ if (generate) {
161
+ jobs.push({
168
162
  name: "gen",
169
163
  command: "yarn rw-gen-watch",
170
- prefixColor: "green",
171
- runWhen: () => generate
172
- }
173
- };
174
- const mappedJobs = Object.keys(jobs).map((job) => {
175
- if (side.includes(job) || job === "gen") {
176
- return jobs[job];
164
+ prefixColor: "green"
165
+ });
166
+ }
167
+ const packageWorkspaces = workspace.filter(
168
+ (w) => w !== "api" && w !== "web" && w !== "gen"
169
+ );
170
+ if (packageWorkspaces.length > 0) {
171
+ const hasPackageJsonWorkspaces = Array.isArray(rootPackageJson.workspaces) && rootPackageJson.workspaces.some(
172
+ (workspace2) => workspace2.startsWith("packages/")
173
+ );
174
+ if (hasPackageJsonWorkspaces && fs.existsSync(cedarPaths.packages)) {
175
+ const pkgCommands = await getPackageWatchCommands(packageWorkspaces);
176
+ jobs.push(...pkgCommands);
177
177
  }
178
- return {
179
- name: "",
180
- command: "",
181
- runWhen: () => false
182
- };
178
+ }
179
+ const filteredJobs = jobs.filter((job) => !job.runWhen || job.runWhen());
180
+ const { result } = concurrently(filteredJobs, {
181
+ prefix: "{name} |",
182
+ timestampFormat: "HH:mm:ss",
183
+ handleInput: true
183
184
  });
184
- const { result } = concurrently(
185
- mappedJobs.filter((job) => job.runWhen()),
186
- {
187
- prefix: "{name} |",
188
- timestampFormat: "HH:mm:ss",
189
- handleInput: true
190
- }
191
- );
192
185
  result.catch((e) => {
193
186
  if (e?.message) {
194
187
  errorTelemetry(
195
188
  process.argv,
196
- `Error concurrently starting sides: ${e.message}`
189
+ `Error concurrently starting workspaces: ${e.message}`
197
190
  );
198
191
  exitWithError(e);
199
192
  }
@@ -210,6 +203,9 @@ function getDevNodeOptions() {
210
203
  }
211
204
  return `${NODE_OPTIONS} ${enableSourceMapsOption}`;
212
205
  }
206
+ function getErrorMessage(error) {
207
+ return error instanceof Object && "message" in error ? error.message : String(error);
208
+ }
213
209
  export {
214
210
  getDevNodeOptions,
215
211
  handler
@@ -0,0 +1,54 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { importStatementPath } from "@cedarjs/project-config";
4
+ import c from "../../lib/colors.js";
5
+ import { getPaths } from "../../lib/index.js";
6
+ async function getPackageWatchCommands(packageWorkspaces) {
7
+ const cedarPaths = getPaths();
8
+ const globPattern = path.join(cedarPaths.packages, "*").replaceAll("\\", "/");
9
+ const workspacePaths = packageWorkspaces.some((w) => w === "packages/*") ? await Array.fromAsync(fs.promises.glob(globPattern)) : packageWorkspaces.map((w) => {
10
+ const packageFolderName = w.split("/").at(-1);
11
+ if (!packageFolderName) {
12
+ throw new Error(`Invalid package workspace: ${w}`);
13
+ }
14
+ const workspacePath = path.join(cedarPaths.packages, packageFolderName);
15
+ if (!fs.existsSync(workspacePath)) {
16
+ throw new Error(`Workspace not found: ${workspacePath}`);
17
+ }
18
+ return importStatementPath(workspacePath);
19
+ });
20
+ const watchablePackages = [];
21
+ const packagesWithoutWatch = [];
22
+ for (const workspacePath of workspacePaths) {
23
+ const packageJsonPath = path.join(workspacePath, "package.json");
24
+ if (!fs.existsSync(packageJsonPath)) {
25
+ continue;
26
+ }
27
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
28
+ const packageName = workspacePath.split("/").at(-1);
29
+ if (packageJson.scripts?.watch) {
30
+ watchablePackages.push(workspacePath);
31
+ } else {
32
+ packagesWithoutWatch.push(packageName);
33
+ }
34
+ }
35
+ if (packagesWithoutWatch.length > 0) {
36
+ console.warn(
37
+ `${c.warning("Warning: ")} The following package(s) do not have a "watch" script and will be skipped: ` + packagesWithoutWatch.join(", ")
38
+ );
39
+ }
40
+ return watchablePackages.map((workspacePath) => {
41
+ const name = workspacePath.split("/").at(-1);
42
+ if (!name) {
43
+ throw new Error(`Invalid package path: ${workspacePath}`);
44
+ }
45
+ return {
46
+ name,
47
+ command: "yarn watch",
48
+ cwd: workspacePath
49
+ };
50
+ });
51
+ }
52
+ export {
53
+ getPackageWatchCommands
54
+ };
@@ -1,19 +1,21 @@
1
1
  import { terminalLink } from "termi-link";
2
2
  import c from "../lib/colors.js";
3
+ import { workspaces } from "../lib/project.js";
3
4
  import { checkNodeVersion } from "../middleware/checkNodeVersion.js";
4
- const command = "dev [side..]";
5
- const description = "Start development servers for api, and web";
5
+ const command = "dev [workspace..]";
6
+ const description = "Start development servers for api, web, and packages";
6
7
  const builder = (yargs) => {
7
- yargs.positional("side", {
8
- choices: ["api", "web"],
9
- default: ["api", "web"],
10
- description: "Which dev server(s) to start",
8
+ yargs.positional("workspace", {
9
+ default: ["api", "web", "packages/*"],
10
+ description: "Which dev server(s) to start. Valid values: api, web, packages/*, <package-name>",
11
11
  type: "string",
12
12
  array: true
13
13
  }).option("forward", {
14
14
  alias: "fwd",
15
15
  description: 'String of one or more vite dev server config options, for example: `--fwd="--port=1234 --open=false"`',
16
16
  type: "string",
17
+ // The reason `forward` is hidden is that it's been broken with Vite and
18
+ // it's not clear how to fix it.
17
19
  hidden: true
18
20
  }).option("generate", {
19
21
  type: "boolean",
@@ -29,6 +31,22 @@ const builder = (yargs) => {
29
31
  }
30
32
  console.warn(`${c.warning("Warning")}: ${check.message}
31
33
  `);
34
+ }).check((argv) => {
35
+ const workspaceArg = argv.workspace;
36
+ if (!Array.isArray(workspaceArg)) {
37
+ return "Workspace must be an array";
38
+ }
39
+ const filtered = workspaceArg.filter(
40
+ (item) => item !== "api" && item !== "web" && item !== "packages/*"
41
+ );
42
+ if (filtered.length === 0) {
43
+ return true;
44
+ }
45
+ const workspaceNames = workspaces({ includePackages: true });
46
+ if (!filtered.every((item) => workspaceNames.includes(item))) {
47
+ return c.error(`Unknown workspace(s) ${filtered.join(" ")}`) + "\n\nValid values are: " + workspaceNames.join(", ");
48
+ }
49
+ return true;
32
50
  }).epilogue(
33
51
  `Also see the ${terminalLink(
34
52
  "CedarJS CLI Reference",
@@ -37,7 +55,7 @@ const builder = (yargs) => {
37
55
  );
38
56
  };
39
57
  const handler = async (options) => {
40
- const { handler: handler2 } = await import("./devHandler.js");
58
+ const { handler: handler2 } = await import("./dev/devHandler.js");
41
59
  return handler2(options);
42
60
  };
43
61
  export {
@@ -22,7 +22,9 @@ const REDWOOD_WEB_PATH_NAME = "components";
22
22
  const files = async ({ name, typescript, ...argv }) => {
23
23
  let cellName = removeGeneratorName(name, "cell");
24
24
  let idName = "id";
25
- let idType, mockIdValues = [42, 43, 44], model = null;
25
+ let idType;
26
+ let mockIdValues = [42, 43, 44];
27
+ let model = null;
26
28
  let templateNameSuffix = "";
27
29
  let typeName = cellName;
28
30
  const shouldGenerateList = (isWordPluralizable(cellName) ? isPlural(cellName) : argv.list) || argv.list;
@@ -2,7 +2,7 @@ import { render } from '@cedarjs/testing/web'
2
2
 
3
3
  import ${pascalName} from './${pascalName}'
4
4
 
5
- // Improve this test with help from the Redwood Testing Doc:
5
+ // Improve this test with help from the CedarJS Testing Doc:
6
6
  // https://cedarjs.com/docs/testing#testing-components
7
7
 
8
8
  describe('${pascalName}', () => {
@@ -91,7 +91,7 @@ const handler = async ({ name, force, ...rest }) => {
91
91
  `Please consult the ${terminalLink(
92
92
  "Serverless Function Considerations",
93
93
  "https://cedarjs.com/docs/serverless-functions#security-considerations"
94
- )} in the RedwoodJS documentation for more information.`
94
+ )} in the CedarJS documentation for more information.`
95
95
  );
96
96
  console.info("");
97
97
  } catch (e) {
@@ -10,7 +10,7 @@ import { logger } from 'src/lib/logger'
10
10
  * is your responsibility to secure appropriately.
11
11
  *
12
12
  * @see {@link https://cedarjs.com/docs/serverless-functions#security-considerations|Serverless Function Considerations}
13
- * in the RedwoodJS documentation for more information.
13
+ * in the CedarJS documentation for more information.
14
14
  *<% if (!typescript) { %>
15
15
  * @typedef { import('aws-lambda').APIGatewayEvent } APIGatewayEvent
16
16
  * @typedef { import('aws-lambda').Context } Context<% } %>