@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
package/dist/mod.js CHANGED
@@ -7,7 +7,8 @@ import command_default from "./generate-vocab/command.js";
7
7
  import "./generate-vocab/mod.js";
8
8
  import { inboxCommand, runInbox } from "./inbox.js";
9
9
  import action_default from "./init/action/mod.js";
10
- import { initCommand } from "./init/command.js";
10
+ import { initCommand, testInitCommand } from "./init/command.js";
11
+ import action_default$1 from "./init/test/action.js";
11
12
  import "./init/mod.js";
12
13
  import { nodeInfoCommand, runNodeInfo } from "./nodeinfo.js";
13
14
  import { lookupCommand, runLookup } from "./lookup.js";
@@ -19,7 +20,7 @@ import { or } from "@optique/core";
19
20
  import { run } from "@optique/run";
20
21
 
21
22
  //#region src/mod.ts
22
- const command$1 = or(initCommand, webFingerCommand, lookupCommand, inboxCommand, nodeInfoCommand, tunnelCommand, command_default);
23
+ const command$1 = or(initCommand, webFingerCommand, lookupCommand, inboxCommand, nodeInfoCommand, tunnelCommand, command_default, testInitCommand);
23
24
  async function main() {
24
25
  const result = run(command$1, {
25
26
  programName: "fedify",
@@ -32,6 +33,7 @@ async function main() {
32
33
  if (result.command === "nodeinfo") runNodeInfo(result);
33
34
  if (result.command === "tunnel") await runTunnel(result);
34
35
  if (result.command === "generate-vocab") await runGenerateVocab(result);
36
+ if (result.command === "test-init") await action_default$1(result);
35
37
  }
36
38
  await main();
37
39
 
package/dist/nodeinfo.js CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  import { debugOption } from "./globals.js";
5
5
  import { colors, formatObject } from "./utils.js";
6
- import { argument, command, constant, flag, merge, message, object, option, optional, or, string } from "@optique/core";
6
+ import { argument, command, constant, flag, merge, message, object, option, optional, or, string, text } from "@optique/core";
7
7
  import { print, printError } from "@optique/run";
8
8
  import process from "node:process";
9
9
  import { getNodeInfo } from "@fedify/fedify";
@@ -58,7 +58,7 @@ async function runNodeInfo(command$1) {
58
58
  process.exit(1);
59
59
  }
60
60
  spinner.succeed("NodeInfo document fetched.");
61
- console.log(formatObject(nodeInfo$1, void 0, true));
61
+ print(message`${text(formatObject(nodeInfo$1, void 0, true))}`);
62
62
  return;
63
63
  }
64
64
  const nodeInfo = await getNodeInfo(url, {
@@ -153,15 +153,15 @@ async function runNodeInfo(command$1) {
153
153
  }
154
154
  console.log(layout.join("\n"));
155
155
  }
156
- function indent(text, depth) {
157
- return text.replace(/\n/g, "\n" + " ".repeat(depth));
156
+ function indent(text$1, depth) {
157
+ return text$1.replace(/\n/g, "\n" + " ".repeat(depth));
158
158
  }
159
159
  const LINK_REGEXP = /<link((?:\s+(?:[-a-z]+)=(?:"[^"]*"|'[^']*'|[^\s]+))*)\s*\/?>/gi;
160
160
  const LINK_ATTRS_REGEXP = /(?:\s+([-a-z]+)=("[^"]*"|'[^']*'|[^\s]+))/gi;
161
161
  async function getFaviconUrl(url, userAgent) {
162
162
  const response = await fetch(url, { headers: { "User-Agent": userAgent == null ? getUserAgent() : userAgent } });
163
- const text = await response.text();
164
- for (const match of text.matchAll(LINK_REGEXP)) {
163
+ const text$1 = await response.text();
164
+ for (const match of text$1.matchAll(LINK_REGEXP)) {
165
165
  const attrs = {};
166
166
  for (const attrMatch of match[1].matchAll(LINK_ATTRS_REGEXP)) {
167
167
  const [, key, value] = attrMatch;
package/dist/utils.js CHANGED
@@ -2,12 +2,14 @@
2
2
  import { Temporal } from "@js-temporal/polyfill";
3
3
 
4
4
  import { writeFile } from "node:fs/promises";
5
+ import { message } from "@optique/core";
6
+ import { print, printError } from "@optique/run";
5
7
  import process from "node:process";
6
8
  import util from "node:util";
7
9
  import { isObject } from "@fxts/core";
8
10
  import { Chalk } from "chalk";
9
11
  import { highlight } from "cli-highlight";
10
- import { toMerged } from "es-toolkit";
12
+ import { flow, toMerged } from "es-toolkit";
11
13
  import { spawn } from "node:child_process";
12
14
 
13
15
  //#region src/utils.ts
@@ -34,34 +36,99 @@ function set(key, f) {
34
36
  };
35
37
  };
36
38
  }
37
- const merge = (source = {}) => (target = {}) => toMerged(target, source);
39
+ const merge$1 = (source = {}) => (target = {}) => toMerged(target, source);
38
40
  const isNotFoundError = (e) => isObject(e) && "code" in e && e.code === "ENOENT";
39
- const runSubCommand = (command, options) => new Promise((resolve, reject) => {
40
- const child = spawn(command[0], command.slice(1), options);
41
+ var CommandError = class extends Error {
42
+ commandLine;
43
+ constructor(message$1, stdout, stderr, code, command$1) {
44
+ super(message$1);
45
+ this.stdout = stdout;
46
+ this.stderr = stderr;
47
+ this.code = code;
48
+ this.command = command$1;
49
+ this.name = "CommandError";
50
+ this.commandLine = command$1.join(" ");
51
+ }
52
+ };
53
+ const runSubCommand = async (command$1, options) => {
54
+ const commands = command$1.reduce((acc, cur) => {
55
+ if (cur === "&&") acc.push([]);
56
+ else {
57
+ if (acc.length === 0) acc.push([]);
58
+ acc[acc.length - 1].push(cur);
59
+ }
60
+ return acc;
61
+ }, []);
62
+ const results = {
63
+ stdout: "",
64
+ stderr: ""
65
+ };
66
+ for (const cmd of commands) try {
67
+ const result = await runSingularCommand(cmd, options);
68
+ results.stdout += (results.stdout ? "\n" : "") + result.stdout;
69
+ results.stderr += (results.stderr ? "\n" : "") + result.stderr;
70
+ } catch (e) {
71
+ if (e instanceof CommandError) {
72
+ results.stdout += (results.stdout ? "\n" : "") + e.stdout;
73
+ results.stderr += (results.stderr ? "\n" : "") + e.stderr;
74
+ }
75
+ throw e;
76
+ }
77
+ return results;
78
+ };
79
+ const runSingularCommand = (command$1, options) => new Promise((resolve, reject) => {
41
80
  let stdout = "";
42
81
  let stderr = "";
82
+ const child = spawn(command$1[0], command$1.slice(1), options);
43
83
  child.stdout?.on("data", (data) => {
44
84
  stdout += data.toString();
45
85
  });
46
86
  child.stderr?.on("data", (data) => {
47
87
  stderr += data.toString();
48
88
  });
49
- child.on("close", () => {
50
- resolve({
89
+ child.on("close", (code) => {
90
+ if (code === 0) resolve({
51
91
  stdout: stdout.trim(),
52
92
  stderr: stderr.trim()
53
93
  });
94
+ else reject(new CommandError(`Command exited with code ${code ?? "unknown"}`, stdout.trim(), stderr.trim(), code ?? -1, command$1));
54
95
  });
55
96
  child.on("error", (error) => {
56
97
  reject(error);
57
98
  });
58
99
  });
59
100
  const getCwd = () => process.cwd();
60
- const replace = (pattern, replacement) => (text) => text.replace(pattern, replacement);
101
+ const replace = (pattern, replacement) => (text$1) => text$1.replace(pattern, replacement);
102
+ const replaceAll = (pattern, replacement) => (text$1) => text$1.replaceAll(pattern, replacement);
61
103
  const getOsType = () => process.platform;
62
104
  const formatJson = (obj) => JSON.stringify(obj, null, 2) + "\n";
63
105
  const notEmpty = (s) => s.length > 0;
64
106
  const exit = (code) => process.exit(code);
107
+ /**
108
+ * ```haskell
109
+ * product::[[a], [b], ...] -> [[a, b, ...]]
110
+ * ```
111
+ *
112
+ * Cartesian product of the input iterables.
113
+ * Inspired by Python's `itertools.product`.
114
+ *
115
+ * @param {...Iterable<unknown>} iters - The input iterables to compute the Cartesian product.
116
+ * @returns {Generator<ItersItems<T>>} A generator that yields arrays containing one element from each iterable.
117
+ *
118
+ * @example
119
+ * ```ts
120
+ * const iter1 = [1, 2];
121
+ * const iter2 = ['a', 'b'];
122
+ * const iter3 = [true, false];
123
+ * const productIter = product(iter1, iter2, iter3);
124
+ * console.log(Array.from(productIter)); // Output: [[1, 'a', true], [1, 'a', false], [
125
+ */
126
+ function* product(...[head, ...tail]) {
127
+ if (!head) yield [];
128
+ else for (const x of head) for (const xs of product(...tail)) yield [x, ...xs];
129
+ }
130
+ const printMessage = flow(message, print);
131
+ const printErrorMessage = flow(message, printError);
65
132
 
66
133
  //#endregion
67
- export { colorEnabled, colors, exit, formatJson, formatObject, getCwd, getOsType, isNotFoundError, merge, notEmpty, replace, runSubCommand, set };
134
+ export { CommandError, colorEnabled, colors, exit, formatJson, formatObject, getCwd, getOsType, isNotFoundError, merge$1 as merge, notEmpty, printErrorMessage, printMessage, product, replace, replaceAll, runSubCommand, set };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/cli",
3
- "version": "2.0.0-pr.474.1879+be9e2989",
3
+ "version": "2.0.0-pr.479.1900+0b40bf02",
4
4
  "description": "CLI toolchain for Fedify and debugging ActivityPub",
5
5
  "keywords": [
6
6
  "fedify",
@@ -71,10 +71,10 @@
71
71
  "ora": "^8.2.0",
72
72
  "shiki": "^1.6.4",
73
73
  "srvx": "^0.8.7",
74
- "@fedify/fedify": "2.0.0-pr.474.1879+be9e2989",
75
- "@fedify/vocab-runtime": "2.0.0-pr.474.1879+be9e2989",
76
- "@fedify/vocab-tools": "2.0.0-pr.474.1879+be9e2989",
77
- "@fedify/sqlite": "2.0.0-pr.474.1879+be9e2989"
74
+ "@fedify/sqlite": "2.0.0-pr.479.1900+0b40bf02",
75
+ "@fedify/fedify": "2.0.0-pr.479.1900+0b40bf02",
76
+ "@fedify/vocab-tools": "2.0.0-pr.479.1900+0b40bf02",
77
+ "@fedify/vocab-runtime": "2.0.0-pr.479.1900+0b40bf02"
78
78
  },
79
79
  "devDependencies": {
80
80
  "@types/bun": "^1.2.23",
package/src/inbox.tsx CHANGED
@@ -103,14 +103,6 @@ export const inboxCommand = command(
103
103
  }),
104
104
  "An ephemeral ActivityPub inbox for testing purposes.",
105
105
  ),
106
- authorizedFetch: option(
107
- "-A",
108
- "--authorized-fetch",
109
- {
110
- description:
111
- message`Require HTTP Signatures for all incoming requests. Returns 401 for unsigned requests.`,
112
- },
113
- ),
114
106
  }),
115
107
  debugOption,
116
108
  ),
@@ -127,7 +119,6 @@ export async function runInbox(
127
119
  const fetch = createFetchHandler({
128
120
  actorName: command.actorName,
129
121
  actorSummary: command.actorSummary,
130
- requireHttpSignature: command.authorizedFetch,
131
122
  });
132
123
  const sendDeleteToPeers = createSendDeleteToPeers({
133
124
  actorName: command.actorName,
@@ -508,11 +499,7 @@ app.get("/r/:idx{[0-9]+}", (c) => {
508
499
  });
509
500
 
510
501
  function createFetchHandler(
511
- actorOptions: {
512
- actorName: string;
513
- actorSummary: string;
514
- requireHttpSignature?: boolean;
515
- },
502
+ actorOptions: { actorName: string; actorSummary: string },
516
503
  ): (request: Request) => Promise<Response> {
517
504
  return async function fetch(request: Request): Promise<Response> {
518
505
  const timestamp = Temporal.Now.instant();
@@ -534,7 +521,6 @@ function createFetchHandler(
534
521
  actorName: actorOptions.actorName,
535
522
  actorSummary: actorOptions.actorSummary,
536
523
  },
537
- requireHttpSignature: actorOptions.requireHttpSignature,
538
524
  onNotAcceptable: app.fetch.bind(app),
539
525
  onNotFound: app.fetch.bind(app),
540
526
  onUnauthorized: app.fetch.bind(app),
@@ -1,4 +1,15 @@
1
- import { join as joinPath } from "node:path";
1
+ import {
2
+ concat,
3
+ filter,
4
+ keys,
5
+ map,
6
+ pick,
7
+ pipe,
8
+ toArray,
9
+ } from "@fxts/core/index.js";
10
+ import { uniq } from "es-toolkit";
11
+ import { join as joinPath, relative } from "node:path";
12
+ import { merge } from "../../utils.ts";
2
13
  import biome from "../json/biome.json" with { type: "json" };
3
14
  import vscodeSettingsForDeno from "../json/vscode-settings-for-deno.json" with {
4
15
  type: "json",
@@ -7,6 +18,8 @@ import vscodeSettings from "../json/vscode-settings.json" with {
7
18
  type: "json",
8
19
  };
9
20
  import type { InitCommandData } from "../types.ts";
21
+ import { PACKAGES_PATH } from "./const.ts";
22
+ import { getDependencies, getDevDependencies, joinDepsReg } from "./deps.ts";
10
23
 
11
24
  /**
12
25
  * Loads Deno configuration object with compiler options, unstable features, and tasks.
@@ -16,20 +29,46 @@ import type { InitCommandData } from "../types.ts";
16
29
  * @returns Configuration object with path and Deno-specific settings
17
30
  */
18
31
  export const loadDenoConfig = (
19
- { kv, mq, initializer, dir }: InitCommandData,
32
+ data: InitCommandData,
20
33
  ) => ({
21
- path: joinPath(dir, "deno.json"),
34
+ path: "deno.json",
22
35
  data: {
23
- compilerOptions: initializer.compilerOptions,
36
+ ...pick(["compilerOptions", "tasks"], data.initializer),
37
+ unstable: getUnstable(data),
38
+ nodeModulesDir: "auto",
39
+ imports: joinDepsReg("deno")(getDependencies(data)),
40
+ ...(data.testMode ? { links: getLinks(data) } : {}),
24
41
  },
25
- unstable: [
26
- "temporal",
27
- ...kv.denoUnstable ?? [],
28
- ...mq.denoUnstable ?? [],
29
- ],
30
- tasks: initializer.tasks,
31
42
  });
32
43
 
44
+ const getUnstable = <T extends Pick<InitCommandData, "kv" | "mq">>({
45
+ kv: { denoUnstable: kv = [] },
46
+ mq: { denoUnstable: mq = [] },
47
+ }: T) =>
48
+ pipe(
49
+ ["temporal"],
50
+ concat(kv),
51
+ concat(mq),
52
+ toArray,
53
+ uniq,
54
+ );
55
+
56
+ const getLinks = <
57
+ T extends Pick<InitCommandData, "kv" | "mq" | "initializer" | "dir">,
58
+ >({ kv, mq, initializer, dir }: T) =>
59
+ pipe(
60
+ { "@fedify/fedify": "" },
61
+ merge(initializer.dependencies),
62
+ merge(kv.dependencies),
63
+ merge(mq.dependencies),
64
+ keys,
65
+ filter((dep) => dep.includes("@fedify/")),
66
+ map((dep) => dep.replace("@fedify/", "")),
67
+ map((dep) => joinPath(PACKAGES_PATH, dep)),
68
+ map((absolutePath) => relative(dir, absolutePath)),
69
+ toArray,
70
+ );
71
+
33
72
  /**
34
73
  * Loads TypeScript configuration object for Node.js/Bun projects.
35
74
  * Uses compiler options from the framework initializer.
@@ -51,11 +90,15 @@ export const loadTsConfig = ({ initializer, dir }: InitCommandData) => ({
51
90
  * @param param0 - Destructured initialization data containing initializer and directory
52
91
  * @returns Configuration object with path and package.json settings
53
92
  */
54
- export const loadPackageJson = ({ initializer, dir }: InitCommandData) => ({
55
- path: joinPath(dir, "package.json"),
93
+ export const loadPackageJson = (
94
+ data: InitCommandData,
95
+ ) => ({
96
+ path: "package.json",
56
97
  data: {
57
98
  type: "module",
58
- scripts: initializer.tasks,
99
+ scripts: data.initializer.tasks,
100
+ dependencies: getDependencies(data),
101
+ devDependencies: getDevDependencies(data),
59
102
  },
60
103
  });
61
104
 
@@ -0,0 +1,9 @@
1
+ import { join as joinPath } from "node:path";
2
+
3
+ export const PACKAGES_PATH = joinPath(
4
+ import.meta.dirname!, // action
5
+ "..", // init
6
+ "..", // src
7
+ "..", // cli
8
+ "..", // packages
9
+ );
@@ -1,7 +1,18 @@
1
- import { entries, map, pipe, toArray } from "@fxts/core";
2
- import { merge } from "../../utils.ts";
1
+ import {
2
+ always,
3
+ entries,
4
+ filter,
5
+ fromEntries,
6
+ map,
7
+ pipe,
8
+ when,
9
+ } from "@fxts/core";
10
+ import { join as joinPath } from "node:path";
11
+ import { merge, replace } from "../../utils.ts";
3
12
  import { PACKAGE_VERSION } from "../lib.ts";
4
13
  import type { InitCommandData, PackageManager } from "../types.ts";
14
+ import { PACKAGES_PATH } from "./const.ts";
15
+ import { isDeno } from "./utils.ts";
5
16
 
6
17
  type Deps = Record<string, string>;
7
18
 
@@ -9,11 +20,15 @@ type Deps = Record<string, string>;
9
20
  * Gathers all dependencies required for the project based on the initializer,
10
21
  * key-value store, and message queue configurations.
11
22
  *
12
- * @param data - Web Framework initializer, key-value store and message queue descriptions
23
+ * @param data - Web Framework initializer, key-value store and
24
+ * message queue descriptions
13
25
  * @returns A record of dependencies with their versions
14
26
  */
15
27
  export const getDependencies = (
16
- { initializer, kv, mq }: InitCommandData,
28
+ { initializer, kv, mq, testMode, packageManager }: Pick<
29
+ InitCommandData,
30
+ "initializer" | "kv" | "mq" | "packageManager" | "testMode"
31
+ >,
17
32
  ): Deps =>
18
33
  pipe(
19
34
  {
@@ -23,16 +38,54 @@ export const getDependencies = (
23
38
  merge(initializer.dependencies),
24
39
  merge(kv.dependencies),
25
40
  merge(mq.dependencies),
41
+ when(
42
+ always(testMode),
43
+ isDeno({ packageManager }) ? removeFedifyDeps : addLocalFedifyDeps,
44
+ ),
45
+ normalizePackageNames(packageManager),
26
46
  );
27
47
 
28
- /** Gathers all devDependencies required for the project based on the initializer,
29
- * key-value store, and message queue configurations, including Biome for linting/formatting.
48
+ const removeFedifyDeps = (deps: Deps): Deps =>
49
+ pipe(
50
+ deps,
51
+ entries,
52
+ filter(([name]) => !name.includes("@fedify")),
53
+ fromEntries,
54
+ );
55
+
56
+ const addLocalFedifyDeps = (deps: Deps): Deps =>
57
+ pipe(
58
+ deps,
59
+ entries,
60
+ map(when(
61
+ ([name]) => name.includes("@fedify/"),
62
+ (
63
+ [name, _version],
64
+ ): [string, string] => [name, convertFedifyToLocal(name)],
65
+ )),
66
+ fromEntries,
67
+ );
68
+
69
+ const convertFedifyToLocal = (name: string): string =>
70
+ pipe(
71
+ name,
72
+ replace("@fedify/", ""),
73
+ (pkg) => joinPath(PACKAGES_PATH, pkg),
74
+ );
75
+
76
+ /** Gathers all devDependencies required for the project based on the
77
+ * initializer, key-value store, and message queue configurations,
78
+ * including Biome for linting/formatting.
30
79
  *
31
- * @param data - Web Framework initializer, key-value store and message queue descriptions
80
+ * @param data - Web Framework initializer, key-value store
81
+ * and message queue descriptions
32
82
  * @returns A record of devDependencies with their versions
33
83
  */
34
84
  export const getDevDependencies = (
35
- { initializer, kv, mq }: InitCommandData,
85
+ { initializer, kv, mq, packageManager }: Pick<
86
+ InitCommandData,
87
+ "initializer" | "kv" | "mq" | "packageManager"
88
+ >,
36
89
  ): Deps =>
37
90
  pipe(
38
91
  {
@@ -41,14 +94,16 @@ export const getDevDependencies = (
41
94
  merge(initializer.devDependencies),
42
95
  merge(kv.devDependencies),
43
96
  merge(mq.devDependencies),
97
+ normalizePackageNames(packageManager),
44
98
  );
45
99
 
46
100
  /**
47
- * Generates the command-line arguments needed to add dependencies or devDependencies
48
- * using the specified package manager.
101
+ * Generates the command-line arguments needed to add dependencies
102
+ * or devDependencies using the specified package manager.
49
103
  * If it is devDependencies, the '-D' flag is included.
50
104
  *
51
- * @param param0 - Object containing the package manager and a boolean indicating if dev dependencies are to be added
105
+ * @param param0 - Object containing the package manager and a boolean
106
+ * indicating if dev dependencies are to be added
52
107
  * @yields The command-line arguments as strings
53
108
  */
54
109
  export function* getAddDepsArgs<
@@ -60,34 +115,47 @@ export function* getAddDepsArgs<
60
115
  }
61
116
 
62
117
  /**
63
- * Joins package names with their versions for installation commands.
64
- * For Deno, it prefixes packages with 'jsr:' unless they already start with 'npm:'.
118
+ * Joins package names with their versions for installation dependencies.
119
+ * For Deno, it prefixes packages with 'jsr:'
120
+ * unless they already start with 'npm:' or 'jsr:'.
65
121
  *
66
122
  * @param data - Package manager and dependencies to be joined with versions
67
- * @returns `${registry}:${package}@${version}`[] for deno or `${package}@${version}`[] for others
123
+ * @returns \{ name: `${registry}:${package}@${version}` } for deno
68
124
  */
69
- export const joinDepsVer = <
70
- T extends { packageManager: PackageManager; dependencies: Deps },
71
- >({ packageManager: pm, dependencies }: T): string[] =>
125
+ export const joinDepsReg = (pm: PackageManager) => //
126
+ (dependencies: Deps): Deps =>
72
127
  pipe(
73
128
  dependencies,
74
129
  entries,
75
- map(([name, version]) =>
76
- `${getPackageName(pm, name)}@${getPackageVersion(pm, version)}`
77
- ),
78
- toArray,
130
+ map(([name, version]): [string, string] => [
131
+ name.substring(4),
132
+ `${name}@${getPackageVersion(pm, version)}`,
133
+ ]),
134
+ fromEntries,
79
135
  );
80
136
 
81
- const getPackageName = (pm: PackageManager, name: string) =>
82
- pm !== "deno"
83
- ? name
84
- : name.startsWith("npm:")
85
- ? name.substring(4)
86
- : !name.startsWith("npm:")
87
- ? `jsr:${name}`
88
- : name;
89
-
90
137
  const getPackageVersion = (pm: PackageManager, version: string) =>
91
138
  pm !== "deno" && version.includes("+")
92
139
  ? version.substring(0, version.indexOf("+"))
93
140
  : version;
141
+
142
+ const normalizePackageNames = (pm: PackageManager) => (deps: Deps): Deps =>
143
+ pipe(
144
+ deps,
145
+ entries,
146
+ map(([name, version]): [string, string] => [
147
+ getPackageName(pm, name),
148
+ version,
149
+ ]),
150
+ fromEntries,
151
+ );
152
+
153
+ const getPackageName = (pm: PackageManager, name: string) =>
154
+ pm !== "deno"
155
+ ? name.startsWith("npm:")
156
+ ? name.replace("npm:", "") // not deno, have npm: prefix, remove it
157
+ : name // not deno, no prefix, keep it
158
+ : name.startsWith("npm:")
159
+ ? name // deno, have npm: prefix, keep it
160
+ : `jsr:${name}` // deno, no prefix, add jsr: prefix
161
+ ;
@@ -1,59 +1,24 @@
1
- import { always, concat, pipe, tap, toArray, unless, when } from "@fxts/core";
2
- import { notEmpty, runSubCommand, set } from "../../utils.ts";
1
+ import { apply, pipe } from "@fxts/core";
2
+ import { CommandError, runSubCommand } from "../../utils.ts";
3
3
  import type { InitCommandData } from "../types.ts";
4
- import {
5
- getAddDepsArgs,
6
- getDependencies,
7
- getDevDependencies,
8
- joinDepsVer,
9
- } from "./deps.ts";
10
- import { noticeErrorWhileAddDeps } from "./notice.ts";
11
- import { isDeno } from "./utils.ts";
12
4
 
13
5
  const installDependencies = (data: InitCommandData) =>
14
6
  pipe(
15
7
  data,
16
- tap(installDeps),
17
- unless(isDeno, tap(installDevDeps)),
18
- );
8
+ ({ packageManager, dir }) =>
9
+ [[packageManager, "install"], { cwd: dir }] as //
10
+ Parameters<typeof runSubCommand>,
11
+ apply(runSubCommand),
12
+ ).catch((e) => {
13
+ if (e instanceof CommandError) {
14
+ console.error(
15
+ `Failed to install dependencies using ${data.packageManager}.`,
16
+ );
17
+ console.error("Command:", e.commandLine);
18
+ if (e.stderr) console.error("Error:", e.stderr);
19
+ throw e;
20
+ }
21
+ throw e;
22
+ });
19
23
 
20
24
  export default installDependencies;
21
-
22
- type Deps = Record<string, string>;
23
-
24
- const installDeps = (data: InitCommandData) =>
25
- pipe(
26
- data,
27
- set("dependencies", getDependencies),
28
- getAddDepsCommand,
29
- when(notEmpty, runAddDeps(data)),
30
- );
31
-
32
- const installDevDeps = (data: InitCommandData) =>
33
- pipe(
34
- data,
35
- set("dependencies", getDevDependencies),
36
- set("dev", always(true)),
37
- getAddDepsCommand,
38
- when(notEmpty, runAddDeps(data)),
39
- );
40
-
41
- const getAddDepsCommand = <
42
- T extends InitCommandData & {
43
- dependencies: Deps;
44
- dev?: boolean;
45
- },
46
- >(data: T) =>
47
- pipe(
48
- data,
49
- joinDepsVer,
50
- when(notEmpty<string[]>, concat(getAddDepsArgs(data))),
51
- toArray,
52
- );
53
-
54
- const runAddDeps =
55
- <T extends { dir: string }>({ dir }: T) => (command: string[]) =>
56
- runSubCommand(command, {
57
- cwd: dir,
58
- stdio: "inherit",
59
- }).catch(noticeErrorWhileAddDeps(command));
@@ -1,14 +1,14 @@
1
- import { message } from "@optique/core";
2
- import { print, printError } from "@optique/run";
1
+ import { text } from "@optique/core";
3
2
  import { flow } from "es-toolkit";
4
- import { colors, type RequiredNotNull } from "../../utils.ts";
3
+ import {
4
+ colors,
5
+ printErrorMessage,
6
+ printMessage,
7
+ type RequiredNotNull,
8
+ } from "../../utils.ts";
5
9
  import type { InitCommand } from "../command.ts";
6
10
  import type { InitCommandData } from "../types.ts";
7
11
 
8
- type PrintMessage = (...args: Parameters<typeof message>) => void;
9
- const printMessage: PrintMessage = flow(message, print);
10
- const printErrorMessage: PrintMessage = flow(message, printError);
11
-
12
12
  export function drawDinosaur() {
13
13
  const d = flow(colors.bgBlue, colors.black);
14
14
  const f = colors.blue;
@@ -80,16 +80,18 @@ export const noticeConfigEnv = () =>
80
80
  printMessage`Note that you probably want to edit the ${".env"} file.
81
81
  It currently contains the following values:\n`;
82
82
 
83
- export const noticeEnvKeyValue = ([key, value]: [string, string]) =>
84
- printMessage` ${key}=${value}`;
83
+ export const noticeEnvKeyValue = ([key, value]: [string, string]) => {
84
+ printMessage`${text(` ${key}='${value}'`)}`;
85
+ };
85
86
 
86
- export function noticeHowToRun(
87
+ export const noticeHowToRun = (
87
88
  { initializer: { instruction, federationFile } }: InitCommandData,
88
- ) {
89
- printMessage`${instruction}`;
90
- printMessage`Start by editing the ${federationFile} file to define your federation!
89
+ ) =>
90
+ printMessage`
91
+ ${instruction}
92
+
93
+ Start by editing the ${text(federationFile)} file to define your federation!
91
94
  `;
92
- }
93
95
 
94
96
  export function noticeErrorWhileAddDeps(command: string[]) {
95
97
  return (error: unknown) => {