@fedify/cli 2.0.0-pr.474.1879 → 2.0.0-pr.479.1900

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 (63) hide show
  1. package/deno.json +1 -1
  2. package/dist/deno.js +1 -1
  3. package/dist/imagerenderer.js +1 -1
  4. package/dist/inbox.js +2 -5
  5. package/dist/init/action/configs.js +22 -13
  6. package/dist/init/action/const.js +10 -0
  7. package/dist/init/action/deps.js +26 -28
  8. package/dist/init/action/install.js +11 -13
  9. package/dist/init/action/mod.js +1 -1
  10. package/dist/init/action/notice.js +12 -19
  11. package/dist/init/action/patch.js +33 -27
  12. package/dist/init/action/precommand.js +7 -2
  13. package/dist/init/action/recommend.js +1 -1
  14. package/dist/init/action/set.js +1 -1
  15. package/dist/init/action/templates.js +2 -1
  16. package/dist/init/ask/kv.js +24 -13
  17. package/dist/init/ask/mq.js +26 -13
  18. package/dist/init/command.js +20 -3
  19. package/dist/init/lib.js +20 -13
  20. package/dist/init/mod.js +2 -1
  21. package/dist/init/templates/nitro/.env.test.tpl +1 -0
  22. package/dist/init/templates/nitro/nitro.config.ts.tpl +12 -3
  23. package/dist/init/test/action.js +15 -0
  24. package/dist/init/test/create.js +100 -0
  25. package/dist/init/test/fill.js +26 -0
  26. package/dist/init/test/lookup.js +189 -0
  27. package/dist/init/test/run.js +26 -0
  28. package/dist/init/test/utils.js +17 -0
  29. package/dist/init/webframeworks.js +31 -28
  30. package/dist/mod.js +4 -2
  31. package/dist/nodeinfo.js +6 -6
  32. package/dist/utils.js +75 -8
  33. package/package.json +5 -5
  34. package/src/inbox.tsx +1 -15
  35. package/src/init/action/configs.ts +56 -13
  36. package/src/init/action/const.ts +9 -0
  37. package/src/init/action/deps.ts +98 -30
  38. package/src/init/action/install.ts +17 -52
  39. package/src/init/action/notice.ts +16 -14
  40. package/src/init/action/patch.ts +48 -27
  41. package/src/init/action/precommand.ts +9 -2
  42. package/src/init/action/set.ts +2 -15
  43. package/src/init/action/templates.ts +3 -2
  44. package/src/init/action/utils.ts +1 -1
  45. package/src/init/ask/kv.ts +64 -21
  46. package/src/init/ask/mq.ts +69 -20
  47. package/src/init/command.ts +39 -1
  48. package/src/init/lib.ts +31 -28
  49. package/src/init/mod.ts +2 -1
  50. package/src/init/templates/nitro/.env.test.tpl +1 -0
  51. package/src/init/templates/nitro/nitro.config.ts.tpl +12 -3
  52. package/src/init/test/action.ts +25 -0
  53. package/src/init/test/create.ts +137 -0
  54. package/src/init/test/fill.ts +61 -0
  55. package/src/init/test/lookup.ts +253 -0
  56. package/src/init/test/run.ts +42 -0
  57. package/src/init/test/types.ts +34 -0
  58. package/src/init/test/utils.ts +21 -0
  59. package/src/init/types.ts +4 -3
  60. package/src/init/webframeworks.ts +35 -18
  61. package/src/mod.ts +10 -1
  62. package/src/nodeinfo.ts +2 -1
  63. package/src/utils.ts +128 -10
@@ -6,6 +6,7 @@ import {
6
6
  getNextInitCommand,
7
7
  getNitroInitCommand,
8
8
  PACKAGE_VERSION,
9
+ packageManagerToRuntime,
9
10
  readTemplate,
10
11
  } from "./lib.ts";
11
12
  import type { WebFrameworks } from "./types.ts";
@@ -14,21 +15,27 @@ const webFrameworks: WebFrameworks = {
14
15
  hono: {
15
16
  label: "Hono",
16
17
  packageManagers: PACKAGE_MANAGER,
17
- init: (projectName, pm) => ({
18
+ init: ({ projectName, packageManager: pm }) => ({
18
19
  dependencies: pm === "deno"
19
20
  ? {
20
21
  "@std/dotenv": "^0.225.2",
21
22
  "@hono/hono": "^4.5.0",
22
23
  "@hongminhee/x-forwarded-fetch": "^0.2.0",
24
+ "@fedify/hono": PACKAGE_VERSION,
23
25
  }
24
26
  : pm === "bun"
25
- ? { hono: "^4.5.0", "x-forwarded-fetch": "^0.2.0" }
27
+ ? {
28
+ hono: "^4.5.0",
29
+ "x-forwarded-fetch": "^0.2.0",
30
+ "@fedify/hono": PACKAGE_VERSION,
31
+ }
26
32
  : {
27
33
  "@dotenvx/dotenvx": "^1.14.1",
28
34
  hono: "^4.5.0",
29
35
  "@hono/node-server": "^1.12.0",
30
36
  tsx: "^4.17.0",
31
37
  "x-forwarded-fetch": "^0.2.0",
38
+ "@fedify/hono": PACKAGE_VERSION,
32
39
  },
33
40
  devDependencies: pm === "bun" ? { "@types/bun": "^1.1.6" } : {},
34
41
  federationFile: "src/federation.ts",
@@ -37,13 +44,12 @@ const webFrameworks: WebFrameworks = {
37
44
  "src/app.tsx": pipe(
38
45
  "hono/app.tsx",
39
46
  readTemplate,
40
- replace(
41
- /\/\* hono \*\//,
42
- pm === "deno" ? "@hono/hono" : "hono",
43
- ),
44
- )
45
- .replace(/\/\* logger \*\//, projectName),
46
- "src/index.ts": readTemplate(`hono/index/${pm}.ts`),
47
+ replace(/\/\* hono \*\//, pm === "deno" ? "@hono/hono" : "hono"),
48
+ replace(/\/\* logger \*\//, projectName),
49
+ ),
50
+ "src/index.ts": readTemplate(
51
+ `hono/index/${packageManagerToRuntime(pm)}.ts`,
52
+ ),
47
53
  },
48
54
  compilerOptions: pm === "deno" ? undefined : {
49
55
  "lib": ["ESNext", "DOM"],
@@ -69,15 +75,16 @@ const webFrameworks: WebFrameworks = {
69
75
  ? "bun run ./src/index.ts"
70
76
  : "dotenvx run -- node --import tsx ./src/index.ts",
71
77
  },
72
- instruction: getInstruction(pm),
78
+ instruction: getInstruction(pm, 8000),
73
79
  }),
80
+ defaultPort: 8000,
74
81
  },
75
82
  express: {
76
83
  label: "Express",
77
- packageManagers: ["bun", "npm", "yarn", "pnpm"] as const,
78
- init: (projectName, pm) => ({
84
+ packageManagers: PACKAGE_MANAGER,
85
+ init: ({ projectName, packageManager: pm }) => ({
79
86
  dependencies: {
80
- express: "^4.19.2",
87
+ "npm:express": "^4.19.2",
81
88
  "@fedify/express": PACKAGE_VERSION,
82
89
  ...(pm !== "deno" && pm !== "bun"
83
90
  ? { "@dotenvx/dotenvx": "^1.14.1", tsx: "^4.17.0" }
@@ -107,18 +114,23 @@ const webFrameworks: WebFrameworks = {
107
114
  tasks: {
108
115
  "dev": pm === "bun"
109
116
  ? "bun run --hot ./src/index.ts"
117
+ : pm === "deno"
118
+ ? "deno run --allow-net --allow-env --allow-sys --watch ./src/index.ts"
110
119
  : "dotenvx run -- tsx watch ./src/index.ts",
111
120
  "prod": pm === "bun"
112
121
  ? "bun run ./src/index.ts"
122
+ : pm === "deno"
123
+ ? "deno run --allow-net --allow-env --allow-sys ./src/index.ts"
113
124
  : "dotenvx run -- node --import tsx ./src/index.ts",
114
125
  },
115
- instruction: getInstruction(pm),
126
+ instruction: getInstruction(pm, 8000),
116
127
  }),
128
+ defaultPort: 8000,
117
129
  },
118
130
  nitro: {
119
131
  label: "Nitro",
120
132
  packageManagers: PACKAGE_MANAGER,
121
- init: (_, pm) => ({
133
+ init: ({ packageManager: pm, testMode }) => ({
122
134
  command: getNitroInitCommand(pm),
123
135
  dependencies: { "@fedify/h3": PACKAGE_VERSION },
124
136
  federationFile: "server/federation.ts",
@@ -129,14 +141,18 @@ const webFrameworks: WebFrameworks = {
129
141
  ),
130
142
  "server/error.ts": readTemplate("nitro/server/error.ts"),
131
143
  "nitro.config.ts": readTemplate("nitro/nitro.config.ts"),
144
+ ...(
145
+ testMode ? { ".env": readTemplate("nitro/.env.test") } : {}
146
+ ),
132
147
  },
133
- instruction: getInstruction(pm),
148
+ instruction: getInstruction(pm, 3000),
134
149
  }),
150
+ defaultPort: 3000,
135
151
  },
136
152
  next: {
137
153
  label: "Next.js",
138
154
  packageManagers: PACKAGE_MANAGER,
139
- init: (_, pm) => ({
155
+ init: ({ packageManager: pm }) => ({
140
156
  label: "Next.js",
141
157
  command: getNextInitCommand(pm),
142
158
  dependencies: { "@fedify/next": PACKAGE_VERSION },
@@ -144,8 +160,9 @@ const webFrameworks: WebFrameworks = {
144
160
  federationFile: "federation/index.ts",
145
161
  loggingFile: "logging.ts",
146
162
  files: { "middleware.ts": readTemplate("next/middleware.ts") },
147
- instruction: getInstruction(pm),
163
+ instruction: getInstruction(pm, 3000),
148
164
  }),
165
+ defaultPort: 3000,
149
166
  },
150
167
  } as const;
151
168
  export default webFrameworks;
package/src/mod.ts CHANGED
@@ -6,7 +6,12 @@ import {
6
6
  runGenerateVocab,
7
7
  } from "./generate-vocab/mod.ts";
8
8
  import { inboxCommand, runInbox } from "./inbox.tsx";
9
- import { initCommand, runInit } from "./init/mod.ts";
9
+ import {
10
+ initCommand,
11
+ runInit,
12
+ runTestInit,
13
+ testInitCommand,
14
+ } from "./init/mod.ts";
10
15
  import { lookupCommand, runLookup } from "./lookup.ts";
11
16
  import { nodeInfoCommand, runNodeInfo } from "./nodeinfo.ts";
12
17
  import { runTunnel, tunnelCommand } from "./tunnel.ts";
@@ -20,6 +25,7 @@ const command = or(
20
25
  nodeInfoCommand,
21
26
  tunnelCommand,
22
27
  generateVocabCommand,
28
+ testInitCommand,
23
29
  );
24
30
 
25
31
  async function main() {
@@ -48,6 +54,9 @@ async function main() {
48
54
  if (result.command === "generate-vocab") {
49
55
  await runGenerateVocab(result);
50
56
  }
57
+ if (result.command === "test-init") {
58
+ await runTestInit(result);
59
+ }
51
60
  }
52
61
 
53
62
  await main();
package/src/nodeinfo.ts CHANGED
@@ -16,6 +16,7 @@ import {
16
16
  optional,
17
17
  or,
18
18
  string,
19
+ text,
19
20
  } from "@optique/core";
20
21
  import { print, printError } from "@optique/run";
21
22
  import type { ChalkInstance } from "chalk";
@@ -111,7 +112,7 @@ export async function runNodeInfo(
111
112
  }
112
113
  spinner.succeed("NodeInfo document fetched.");
113
114
 
114
- console.log(formatObject(nodeInfo, undefined, true));
115
+ print(message`${text(formatObject(nodeInfo, undefined, true))}`);
115
116
  return;
116
117
  }
117
118
  const nodeInfo = await getNodeInfo(url, {
package/src/utils.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  import { isObject } from "@fxts/core";
2
+ import { message } from "@optique/core";
3
+ import { print, printError } from "@optique/run";
2
4
  import { Chalk } from "chalk";
3
5
  import { highlight } from "cli-highlight";
4
- import { toMerged } from "es-toolkit";
6
+ import { flow, toMerged } from "es-toolkit";
5
7
  import { spawn } from "node:child_process";
6
8
  import { writeFile } from "node:fs/promises";
7
9
  import process from "node:process";
@@ -59,18 +61,68 @@ export const isNotFoundError = (e: unknown): e is { code: "ENOENT" } =>
59
61
  "code" in e &&
60
62
  e.code === "ENOENT";
61
63
 
62
- export const runSubCommand = <Opt extends Parameters<typeof spawn>[2]>(
64
+ export class CommandError extends Error {
65
+ public commandLine: string;
66
+ constructor(
67
+ message: string,
68
+ public stdout: string,
69
+ public stderr: string,
70
+ public code: number,
71
+ public command: string[],
72
+ ) {
73
+ super(message);
74
+ this.name = "CommandError";
75
+ this.commandLine = command.join(" ");
76
+ }
77
+ }
78
+
79
+ export const runSubCommand = async <Opt extends Parameters<typeof spawn>[2]>(
63
80
  command: string[],
64
81
  options: Opt,
65
82
  ): Promise<{
66
83
  stdout: string;
67
84
  stderr: string;
68
- }> =>
69
- new Promise((resolve, reject) => {
70
- const child = spawn(command[0], command.slice(1), options);
85
+ }> => {
86
+ const commands = // split by "&&"
87
+ command.reduce<string[][]>((acc, cur) => {
88
+ if (cur === "&&") {
89
+ acc.push([]);
90
+ } else {
91
+ if (acc.length === 0) acc.push([]);
92
+ acc[acc.length - 1].push(cur);
93
+ }
94
+ return acc;
95
+ }, []);
96
+
97
+ const results = { stdout: "", stderr: "" };
98
+
99
+ for (const cmd of commands) {
100
+ try {
101
+ const result = await runSingularCommand(cmd, options);
102
+ results.stdout += (results.stdout ? "\n" : "") + result.stdout;
103
+ results.stderr += (results.stderr ? "\n" : "") + result.stderr;
104
+ } catch (e) {
105
+ if (e instanceof CommandError) {
106
+ results.stdout += (results.stdout ? "\n" : "") + e.stdout;
107
+ results.stderr += (results.stderr ? "\n" : "") + e.stderr;
108
+ }
109
+ throw e;
110
+ }
111
+ }
112
+ return results;
113
+ };
71
114
 
115
+ const runSingularCommand = (
116
+ command: string[],
117
+ options: Parameters<typeof spawn>[2],
118
+ ) =>
119
+ new Promise<{
120
+ stdout: string;
121
+ stderr: string;
122
+ }>((resolve, reject) => {
72
123
  let stdout = "";
73
124
  let stderr = "";
125
+ const child = spawn(command[0], command.slice(1), options);
74
126
 
75
127
  child.stdout?.on("data", (data) => {
76
128
  stdout += data.toString();
@@ -79,11 +131,23 @@ export const runSubCommand = <Opt extends Parameters<typeof spawn>[2]>(
79
131
  stderr += data.toString();
80
132
  });
81
133
 
82
- child.on("close", () => {
83
- resolve({
84
- stdout: stdout.trim(),
85
- stderr: stderr.trim(),
86
- });
134
+ child.on("close", (code) => {
135
+ if (code === 0) {
136
+ resolve({
137
+ stdout: stdout.trim(),
138
+ stderr: stderr.trim(),
139
+ });
140
+ } else {
141
+ reject(
142
+ new CommandError(
143
+ `Command exited with code ${code ?? "unknown"}`,
144
+ stdout.trim(),
145
+ stderr.trim(),
146
+ code ?? -1,
147
+ command,
148
+ ),
149
+ );
150
+ }
87
151
  });
88
152
 
89
153
  child.on("error", (error) => {
@@ -103,6 +167,12 @@ export const replace = (
103
167
  ) =>
104
168
  (text: string): string => text.replace(pattern, replacement as string);
105
169
 
170
+ export const replaceAll = (
171
+ pattern: string | RegExp,
172
+ replacement: string | ((substring: string, ...args: unknown[]) => string),
173
+ ) =>
174
+ (text: string): string => text.replaceAll(pattern, replacement as string);
175
+
106
176
  export const getOsType = () => process.platform;
107
177
 
108
178
  export async function writeTextFile(
@@ -134,3 +204,51 @@ export const notEmptyObj = <T extends Record<PropertyKey, never> | object>(
134
204
  ): obj is Exclude<T, Record<PropertyKey, never>> => Object.keys(obj).length > 0;
135
205
 
136
206
  export const exit = (code: number) => process.exit(code);
207
+
208
+ /**
209
+ * Generic type to represent the types of the items in iterables.
210
+ */
211
+ export type ItersItems<T extends Iterable<unknown>[]> = T extends [] ? []
212
+ : T extends [infer Head, ...infer Tail]
213
+ ? Head extends Iterable<infer Item>
214
+ ? Tail extends Iterable<unknown>[] ? [Item, ...ItersItems<Tail>]
215
+ : [Item]
216
+ : never
217
+ : never;
218
+
219
+ /**
220
+ * ```haskell
221
+ * product::[[a], [b], ...] -> [[a, b, ...]]
222
+ * ```
223
+ *
224
+ * Cartesian product of the input iterables.
225
+ * Inspired by Python's `itertools.product`.
226
+ *
227
+ * @param {...Iterable<unknown>} iters - The input iterables to compute the Cartesian product.
228
+ * @returns {Generator<ItersItems<T>>} A generator that yields arrays containing one element from each iterable.
229
+ *
230
+ * @example
231
+ * ```ts
232
+ * const iter1 = [1, 2];
233
+ * const iter2 = ['a', 'b'];
234
+ * const iter3 = [true, false];
235
+ * const productIter = product(iter1, iter2, iter3);
236
+ * console.log(Array.from(productIter)); // Output: [[1, 'a', true], [1, 'a', false], [
237
+ */
238
+ export function* product<T extends Iterable<unknown>[]>(
239
+ ...[head, ...tail]: T
240
+ ): Generator<ItersItems<T>> {
241
+ if (!head) yield [] as ItersItems<T>;
242
+ else {
243
+ for (const x of head) {
244
+ for (const xs of product(...tail)) yield [x, ...xs] as ItersItems<T>;
245
+ }
246
+ }
247
+ }
248
+
249
+ export type GeneratedType<T extends Generator> = T extends
250
+ Generator<unknown, infer R, unknown> ? R : never;
251
+
252
+ type PrintMessage = (...args: Parameters<typeof message>) => void;
253
+ export const printMessage: PrintMessage = flow(message, print);
254
+ export const printErrorMessage: PrintMessage = flow(message, printError);