@fedify/cli 2.0.0-pr.479.1922 → 2.0.0

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 (160) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +3 -3
  3. package/dist/cache.js +17 -3
  4. package/dist/config.js +105 -0
  5. package/dist/deno.js +18 -8
  6. package/dist/generate-vocab/action.js +1 -1
  7. package/dist/imagerenderer.js +1 -1
  8. package/dist/inbox/rendercode.js +11 -21
  9. package/dist/inbox.js +162 -132
  10. package/dist/init/mod.js +3 -3
  11. package/dist/log.js +35 -1
  12. package/dist/lookup.js +55 -23
  13. package/dist/mod.js +95 -18
  14. package/dist/nodeinfo.js +39 -22
  15. package/dist/options.js +84 -0
  16. package/dist/relay.js +136 -0
  17. package/dist/tempserver.js +15 -8
  18. package/dist/tunnel.js +6 -10
  19. package/dist/utils.js +19 -108
  20. package/dist/webfinger/action.js +1 -1
  21. package/dist/webfinger/command.js +17 -9
  22. package/dist/webfinger/lib.js +3 -3
  23. package/package.json +50 -28
  24. package/deno.json +0 -71
  25. package/dist/globals.js +0 -49
  26. package/dist/init/action/configs.js +0 -91
  27. package/dist/init/action/const.js +0 -10
  28. package/dist/init/action/deps.js +0 -50
  29. package/dist/init/action/dir.js +0 -16
  30. package/dist/init/action/env.js +0 -13
  31. package/dist/init/action/install.js +0 -20
  32. package/dist/init/action/mod.js +0 -39
  33. package/dist/init/action/notice.js +0 -55
  34. package/dist/init/action/patch.js +0 -147
  35. package/dist/init/action/precommand.js +0 -28
  36. package/dist/init/action/recommend.js +0 -24
  37. package/dist/init/action/set.js +0 -31
  38. package/dist/init/action/templates.js +0 -58
  39. package/dist/init/action/utils.js +0 -50
  40. package/dist/init/ask/dir.js +0 -82
  41. package/dist/init/ask/kv.js +0 -44
  42. package/dist/init/ask/mod.js +0 -16
  43. package/dist/init/ask/mq.js +0 -46
  44. package/dist/init/ask/pm.js +0 -49
  45. package/dist/init/ask/wf.js +0 -29
  46. package/dist/init/command.js +0 -50
  47. package/dist/init/const.js +0 -31
  48. package/dist/init/json/biome.js +0 -24
  49. package/dist/init/json/kv.js +0 -53
  50. package/dist/init/json/mq.js +0 -72
  51. package/dist/init/json/pm.js +0 -44
  52. package/dist/init/json/rt.js +0 -39
  53. package/dist/init/json/vscode-settings-for-deno.js +0 -53
  54. package/dist/init/json/vscode-settings.js +0 -49
  55. package/dist/init/lib.js +0 -136
  56. package/dist/init/templates/defaults/federation.ts.tpl +0 -23
  57. package/dist/init/templates/defaults/logging.ts.tpl +0 -23
  58. package/dist/init/templates/express/app.ts.tpl +0 -16
  59. package/dist/init/templates/express/index.ts.tpl +0 -6
  60. package/dist/init/templates/hono/app.tsx.tpl +0 -14
  61. package/dist/init/templates/hono/index/bun.ts.tpl +0 -10
  62. package/dist/init/templates/hono/index/deno.ts.tpl +0 -13
  63. package/dist/init/templates/hono/index/node.ts.tpl +0 -14
  64. package/dist/init/templates/next/middleware.ts.tpl +0 -45
  65. package/dist/init/templates/nitro/.env.test.tpl +0 -1
  66. package/dist/init/templates/nitro/nitro.config.ts.tpl +0 -14
  67. package/dist/init/templates/nitro/server/error.ts.tpl +0 -3
  68. package/dist/init/templates/nitro/server/middleware/federation.ts.tpl +0 -8
  69. package/dist/init/test/action.js +0 -17
  70. package/dist/init/test/create.js +0 -100
  71. package/dist/init/test/fill.js +0 -32
  72. package/dist/init/test/lookup.js +0 -190
  73. package/dist/init/test/run.js +0 -25
  74. package/dist/init/test/utils.js +0 -17
  75. package/dist/init/webframeworks.js +0 -136
  76. package/scripts/pack.ts +0 -71
  77. package/src/cache.ts +0 -17
  78. package/src/docloader.ts +0 -67
  79. package/src/generate-vocab/action.ts +0 -17
  80. package/src/generate-vocab/command.ts +0 -44
  81. package/src/generate-vocab/mod.ts +0 -2
  82. package/src/globals.ts +0 -43
  83. package/src/imagerenderer.ts +0 -149
  84. package/src/inbox/entry.ts +0 -10
  85. package/src/inbox/rendercode.ts +0 -68
  86. package/src/inbox/view.tsx +0 -598
  87. package/src/inbox.tsx +0 -536
  88. package/src/init/action/configs.ts +0 -133
  89. package/src/init/action/const.ts +0 -9
  90. package/src/init/action/deps.ts +0 -161
  91. package/src/init/action/dir.ts +0 -11
  92. package/src/init/action/env.ts +0 -14
  93. package/src/init/action/install.ts +0 -24
  94. package/src/init/action/mod.ts +0 -66
  95. package/src/init/action/notice.ts +0 -103
  96. package/src/init/action/patch.ts +0 -233
  97. package/src/init/action/precommand.ts +0 -29
  98. package/src/init/action/recommend.ts +0 -38
  99. package/src/init/action/set.ts +0 -65
  100. package/src/init/action/templates.ts +0 -96
  101. package/src/init/action/utils.ts +0 -64
  102. package/src/init/ask/dir.ts +0 -98
  103. package/src/init/ask/kv.ts +0 -82
  104. package/src/init/ask/mod.ts +0 -23
  105. package/src/init/ask/mq.ts +0 -86
  106. package/src/init/ask/pm.ts +0 -58
  107. package/src/init/ask/wf.ts +0 -27
  108. package/src/init/command.ts +0 -135
  109. package/src/init/const.ts +0 -4
  110. package/src/init/json/biome.json +0 -17
  111. package/src/init/json/kv.json +0 -39
  112. package/src/init/json/mq.json +0 -95
  113. package/src/init/json/pm.json +0 -47
  114. package/src/init/json/rt.json +0 -42
  115. package/src/init/json/vscode-settings-for-deno.json +0 -43
  116. package/src/init/json/vscode-settings.json +0 -41
  117. package/src/init/lib.ts +0 -223
  118. package/src/init/mod.ts +0 -3
  119. package/src/init/templates/defaults/federation.ts.tpl +0 -23
  120. package/src/init/templates/defaults/logging.ts.tpl +0 -23
  121. package/src/init/templates/express/app.ts.tpl +0 -16
  122. package/src/init/templates/express/index.ts.tpl +0 -6
  123. package/src/init/templates/hono/app.tsx.tpl +0 -14
  124. package/src/init/templates/hono/index/bun.ts.tpl +0 -10
  125. package/src/init/templates/hono/index/deno.ts.tpl +0 -13
  126. package/src/init/templates/hono/index/node.ts.tpl +0 -14
  127. package/src/init/templates/next/middleware.ts.tpl +0 -45
  128. package/src/init/templates/nitro/.env.test.tpl +0 -1
  129. package/src/init/templates/nitro/nitro.config.ts.tpl +0 -14
  130. package/src/init/templates/nitro/server/error.ts.tpl +0 -3
  131. package/src/init/templates/nitro/server/middleware/federation.ts.tpl +0 -8
  132. package/src/init/test/action.ts +0 -28
  133. package/src/init/test/create.ts +0 -137
  134. package/src/init/test/fill.ts +0 -67
  135. package/src/init/test/lookup.ts +0 -254
  136. package/src/init/test/run.ts +0 -39
  137. package/src/init/test/types.ts +0 -27
  138. package/src/init/test/utils.ts +0 -21
  139. package/src/init/types.ts +0 -89
  140. package/src/init/webframeworks.ts +0 -168
  141. package/src/kv.bun.ts +0 -12
  142. package/src/kv.node.ts +0 -11
  143. package/src/log.ts +0 -64
  144. package/src/lookup.test.ts +0 -182
  145. package/src/lookup.ts +0 -563
  146. package/src/mod.ts +0 -62
  147. package/src/nodeinfo.test.ts +0 -229
  148. package/src/nodeinfo.ts +0 -454
  149. package/src/table.ts +0 -17
  150. package/src/tempserver.ts +0 -87
  151. package/src/tunnel.test.ts +0 -157
  152. package/src/tunnel.ts +0 -94
  153. package/src/utils.ts +0 -254
  154. package/src/webfinger/action.ts +0 -50
  155. package/src/webfinger/command.ts +0 -64
  156. package/src/webfinger/error.ts +0 -47
  157. package/src/webfinger/lib.ts +0 -37
  158. package/src/webfinger/mod.test.ts +0 -79
  159. package/src/webfinger/mod.ts +0 -2
  160. package/tsdown.config.ts +0 -35
@@ -1,50 +0,0 @@
1
-
2
- import { Temporal } from "@js-temporal/polyfill";
3
-
4
- import { merge, replace } from "../../utils.js";
5
- import { PACKAGE_VERSION } from "../lib.js";
6
- import { PACKAGES_PATH } from "./const.js";
7
- import { isDeno } from "./utils.js";
8
- import { join } from "node:path";
9
- import { always, entries, filter, fromEntries, map, pipe, when } from "@fxts/core";
10
-
11
- //#region src/init/action/deps.ts
12
- /**
13
- * Gathers all dependencies required for the project based on the initializer,
14
- * key-value store, and message queue configurations.
15
- *
16
- * @param data - Web Framework initializer, key-value store and
17
- * message queue descriptions
18
- * @returns A record of dependencies with their versions
19
- */
20
- const getDependencies = ({ initializer, kv, mq, testMode, packageManager }) => pipe({
21
- "@fedify/fedify": PACKAGE_VERSION,
22
- "@logtape/logtape": "^1.1.0"
23
- }, merge(initializer.dependencies), merge(kv.dependencies), merge(mq.dependencies), when(always(testMode), isDeno({ packageManager }) ? removeFedifyDeps : addLocalFedifyDeps), normalizePackageNames(packageManager));
24
- const removeFedifyDeps = (deps) => pipe(deps, entries, filter(([name]) => !name.includes("@fedify")), fromEntries);
25
- const addLocalFedifyDeps = (deps) => pipe(deps, entries, map(when(([name]) => name.includes("@fedify/"), ([name, _version]) => [name, convertFedifyToLocal(name)])), fromEntries);
26
- const convertFedifyToLocal = (name) => pipe(name, replace("@fedify/", ""), (pkg) => join(PACKAGES_PATH, pkg));
27
- /** Gathers all devDependencies required for the project based on the
28
- * initializer, key-value store, and message queue configurations,
29
- * including Biome for linting/formatting.
30
- *
31
- * @param data - Web Framework initializer, key-value store
32
- * and message queue descriptions
33
- * @returns A record of devDependencies with their versions
34
- */
35
- const getDevDependencies = ({ initializer, kv, mq, packageManager }) => pipe({ "@biomejs/biome": "^2.2.4" }, merge(initializer.devDependencies), merge(kv.devDependencies), merge(mq.devDependencies), normalizePackageNames(packageManager));
36
- /**
37
- * Joins package names with their versions for installation dependencies.
38
- * For Deno, it prefixes packages with 'jsr:'
39
- * unless they already start with 'npm:' or 'jsr:'.
40
- *
41
- * @param data - Package manager and dependencies to be joined with versions
42
- * @returns \{ name: `${registry}:${package}@${version}` } for deno
43
- */
44
- const joinDepsReg = (pm) => (dependencies) => pipe(dependencies, entries, map(([name, version]) => [name.substring(4), `${name}@${getPackageVersion(pm, version)}`]), fromEntries);
45
- const getPackageVersion = (pm, version) => pm !== "deno" && version.includes("+") ? version.substring(0, version.indexOf("+")) : version;
46
- const normalizePackageNames = (pm) => (deps) => pipe(deps, entries, map(([name, version]) => [getPackageName(pm, name), version]), fromEntries);
47
- const getPackageName = (pm, name) => pm !== "deno" ? name.startsWith("npm:") ? name.replace("npm:", "") : name : name.startsWith("npm:") ? name : `jsr:${name}`;
48
-
49
- //#endregion
50
- export { getDependencies, getDevDependencies, joinDepsReg };
@@ -1,16 +0,0 @@
1
-
2
- import { Temporal } from "@js-temporal/polyfill";
3
-
4
- import { mkdir } from "node:fs/promises";
5
-
6
- //#region src/init/action/dir.ts
7
- /**
8
- * Creates the target directory if it does not exist.
9
- *
10
- * @param data - The directory
11
- * @returns A promise that resolves when the directory is created
12
- */
13
- const makeDirIfHyd = ({ dir }) => mkdir(dir, { recursive: true });
14
-
15
- //#endregion
16
- export { makeDirIfHyd };
@@ -1,13 +0,0 @@
1
-
2
- import { Temporal } from "@js-temporal/polyfill";
3
-
4
- import { notEmpty } from "../../utils.js";
5
- import { noticeConfigEnv, noticeEnvKeyValue } from "./notice.js";
6
- import { entries, forEach, pipeLazy, tap, toArray, when } from "@fxts/core";
7
-
8
- //#region src/init/action/env.ts
9
- const recommendConfigEnv = pipeLazy((data) => data.env, entries, toArray, when(notEmpty, tap(noticeConfigEnv)), forEach(noticeEnvKeyValue));
10
- var env_default = recommendConfigEnv;
11
-
12
- //#endregion
13
- export { env_default as default };
@@ -1,20 +0,0 @@
1
-
2
- import { Temporal } from "@js-temporal/polyfill";
3
-
4
- import { CommandError, runSubCommand } from "../../utils.js";
5
- import { apply, pipe } from "@fxts/core";
6
-
7
- //#region src/init/action/install.ts
8
- const installDependencies = (data) => pipe(data, ({ packageManager, dir }) => [[packageManager, "install"], { cwd: dir }], apply(runSubCommand)).catch((e) => {
9
- if (e instanceof CommandError) {
10
- console.error(`Failed to install dependencies using ${data.packageManager}.`);
11
- console.error("Command:", e.commandLine);
12
- if (e.stderr) console.error("Error:", e.stderr);
13
- throw e;
14
- }
15
- throw e;
16
- });
17
- var install_default = installDependencies;
18
-
19
- //#endregion
20
- export { install_default as default };
@@ -1,39 +0,0 @@
1
-
2
- import { Temporal } from "@js-temporal/polyfill";
3
-
4
- import ask_default from "../ask/mod.js";
5
- import { makeDirIfHyd } from "./dir.js";
6
- import { drawDinosaur, noticeHowToRun, noticeOptions, noticePrecommand } from "./notice.js";
7
- import env_default from "./env.js";
8
- import install_default from "./install.js";
9
- import { hasCommand, isDry } from "./utils.js";
10
- import { patchFiles, recommendPatchFiles } from "./patch.js";
11
- import precommand_default from "./precommand.js";
12
- import recommend_default from "./recommend.js";
13
- import set_default from "./set.js";
14
- import { pipe, tap, unless, when } from "@fxts/core";
15
-
16
- //#region src/init/action/mod.ts
17
- /**
18
- * options: InitCommand
19
- * ├ drawDinosaur
20
- * ┌─────┴──────┐
21
- * │ askOptions │ InitCommand -> InitCommandOptions
22
- * └─────┬──────┘
23
- * ├ noticeOptions
24
- * ┌────┴────┐
25
- * │ setData │ InitCommandOptions -> InitCommandData
26
- * └────┬────┘
27
- * ┌─┴─┐ isDry
28
- * handleDryRun ┤ ├ handleHydRun
29
- * └─┬─┘
30
- * ├ recommendConfigEnv
31
- * ├ noticeHowToRun
32
- */
33
- const runInit = (options) => pipe(options, tap(drawDinosaur), ask_default, tap(noticeOptions), set_default, when(isDry, handleDryRun), unless(isDry, handleHydRun), tap(env_default), tap(noticeHowToRun));
34
- var action_default = runInit;
35
- const handleDryRun = (data) => pipe(data, tap(when(hasCommand, noticePrecommand)), tap(recommendPatchFiles), tap(recommend_default));
36
- const handleHydRun = (data) => pipe(data, tap(makeDirIfHyd), tap(when(hasCommand, precommand_default)), tap(patchFiles), tap(install_default));
37
-
38
- //#endregion
39
- export { action_default as default };
@@ -1,55 +0,0 @@
1
-
2
- import { Temporal } from "@js-temporal/polyfill";
3
-
4
- import { colors, printMessage } from "../../utils.js";
5
- import { text } from "@optique/core";
6
- import { flow } from "es-toolkit";
7
-
8
- //#region src/init/action/notice.ts
9
- function drawDinosaur() {
10
- const d = flow(colors.bgBlue, colors.black);
11
- const f = colors.blue;
12
- console.error(`\
13
- ${d(" ___ ")} ${f(" _____ _ _ __")}
14
- ${d(" /'_') ")} ${f("| ___|__ __| (_)/ _|_ _")}
15
- ${d(" .-^^^-/ / ")} ${f("| |_ / _ \\/ _` | | |_| | | |")}
16
- ${d(" __/ / ")} ${f("| _| __/ (_| | | _| |_| |")}
17
- ${d(" <__.|_|-|_| ")} ${f("|_| \\___|\\__,_|_|_| \\__, |")}
18
- ${d(" ")} ${f(" |___/")}
19
- `);
20
- }
21
- const noticeOptions = ({ packageManager, webFramework, kvStore, messageQueue }) => printMessage`
22
- Package manager: ${packageManager};
23
- Web framework: ${webFramework};
24
- Key–value store: ${kvStore};
25
- Message queue: ${messageQueue};
26
- `;
27
- function noticePrecommand({ initializer: { command: command$1 }, dir }) {
28
- printMessage`📦 Would run command:`;
29
- printMessage` cd ${dir}`;
30
- printMessage` ${command$1.join(" ")}\n`;
31
- }
32
- const noticeFilesToCreate = () => printMessage`📄 Would create files:\n`;
33
- const noticeFilesToInsert = () => printMessage`Would create/update JSON files:\n`;
34
- const noticeDepsIfExist = () => printMessage`📦 Would install dependencies:`;
35
- const noticeDevDepsIfExist = () => printMessage`📦 Would install dev dependencies:`;
36
- const noticeDeps = ([name, version]) => printMessage`${name}@${version}`;
37
- function displayFile(path, content, emoji = "📄") {
38
- printMessage`${emoji} ${path}`;
39
- printMessage`${"─".repeat(60)}`;
40
- printMessage`${content}`;
41
- printMessage`${"─".repeat(60)}\n`;
42
- }
43
- const noticeConfigEnv = () => printMessage`Note that you probably want to edit the ${".env"} file.
44
- It currently contains the following values:\n`;
45
- const noticeEnvKeyValue = ([key, value]) => {
46
- printMessage`${text(` ${key}='${value}'`)}`;
47
- };
48
- const noticeHowToRun = ({ initializer: { instruction, federationFile } }) => printMessage`
49
- ${instruction}
50
-
51
- Start by editing the ${text(federationFile)} file to define your federation!
52
- `;
53
-
54
- //#endregion
55
- export { displayFile, drawDinosaur, noticeConfigEnv, noticeDeps, noticeDepsIfExist, noticeDevDepsIfExist, noticeEnvKeyValue, noticeFilesToCreate, noticeFilesToInsert, noticeHowToRun, noticeOptions, noticePrecommand };
@@ -1,147 +0,0 @@
1
-
2
- import { Temporal } from "@js-temporal/polyfill";
3
-
4
- import { formatJson, merge, replaceAll, set } from "../../utils.js";
5
- import { createFile, throwUnlessNotExists } from "../lib.js";
6
- import { displayFile, noticeFilesToCreate, noticeFilesToInsert } from "./notice.js";
7
- import { joinDir, stringifyEnvs } from "./utils.js";
8
- import { devToolConfigs, loadDenoConfig, loadPackageJson, loadTsConfig } from "./configs.js";
9
- import { getImports, loadFederation, loadLogging } from "./templates.js";
10
- import { readFile } from "node:fs/promises";
11
- import { always, apply, entries, map, pipe, pipeLazy, tap } from "@fxts/core";
12
- import { toMerged } from "es-toolkit";
13
-
14
- //#region src/init/action/patch.ts
15
- /**
16
- * Main function that initializes the project by creating necessary files and configurations.
17
- * Handles both dry-run mode (recommending files) and actual file creation.
18
- * Orchestrates the entire file generation and writing process.
19
- *
20
- * @param data - The initialization command data containing project
21
- * configuration
22
- * @returns A processed data object with files and JSONs ready for creation
23
- */
24
- const patchFiles = (data) => pipe(data, set("files", getFiles), set("jsons", getJsons), createFiles);
25
- const recommendPatchFiles = (data) => pipe(data, set("files", getFiles), set("jsons", getJsons), recommendFiles);
26
- /**
27
- * Generates text-based files (TypeScript, environment files) for the project.
28
- * Creates federation configuration, logging setup, environment variables, and
29
- * framework-specific files by processing templates and combining them with
30
- * project-specific data.
31
- *
32
- * @param data - The initialization command data
33
- * @returns A record of file paths to their string content
34
- */
35
- const getFiles = (data) => ({
36
- [data.initializer.federationFile]: loadFederation({
37
- imports: getImports(data),
38
- ...data
39
- }),
40
- [data.initializer.loggingFile]: loadLogging(data),
41
- ".env": stringifyEnvs(data.env),
42
- ...data.initializer.files
43
- });
44
- /**
45
- * Generates JSON configuration files based on the package manager type.
46
- * Creates different sets of configuration files for Deno vs other environments,
47
- * including compiler configs, package manifests, and development
48
- * tool configurations.
49
- *
50
- * @param data - The initialization command data
51
- * @returns A record of file paths to their JSON object content
52
- */
53
- const getJsons = (data) => data.packageManager === "deno" ? {
54
- "deno.json": loadDenoConfig(data).data,
55
- [devToolConfigs["vscSetDeno"].path]: devToolConfigs["vscSetDeno"].data,
56
- [devToolConfigs["vscExtDeno"].path]: devToolConfigs["vscExtDeno"].data
57
- } : {
58
- ...data.initializer.compilerOptions ? { "tsconfig.json": loadTsConfig(data).data } : {},
59
- "package.json": loadPackageJson(data).data,
60
- [devToolConfigs["biome"].path]: devToolConfigs["biome"].data,
61
- [devToolConfigs["vscSet"].path]: devToolConfigs["vscSet"].data,
62
- [devToolConfigs["vscExt"].path]: devToolConfigs["vscExt"].data
63
- };
64
- /**
65
- * Handles dry-run mode by recommending files to be created without actually
66
- * creating them.
67
- * Displays what files would be created and shows their content for user review,
68
- * so users can preview the initialization process before committing to it.
69
- *
70
- * @param data - The initialization command data with files and JSONs prepared
71
- * @returns The processed data with recommendations displayed
72
- */
73
- const recommendFiles = (data) => pipe(data, tap(noticeFilesToCreate), tap(processAllFiles(displayFile)), tap(noticeFilesToInsert), set("files", ({ jsons }) => jsons), tap(processAllFiles(displayFile)));
74
- /**
75
- * Actually creates files on the filesystem during normal execution.
76
- * Merges text files and JSON files together and writes them to disk.
77
- * This performs the actual file system operations to initialize the project.
78
- *
79
- * @param data - The initialization command data with files and JSONs prepared
80
- * @returns The processed data after files have been created
81
- */
82
- const createFiles = (data) => pipe(data, set("files", ({ jsons, files }) => toMerged(files, jsons)), tap(processAllFiles(createFile)));
83
- /**
84
- * Processes all files with a given processing function.
85
- * Takes a processor (either display or create) and applies it to all files
86
- * in the target directory, handling path resolution and content patching.
87
- *
88
- * @param process - Function to process each file (either display or create)
89
- * @returns A function that processes all files in the given directory with the provided processor
90
- */
91
- const processAllFiles = (process) => ({ dir, files }) => pipe(files, entries, map(pipeLazy(joinDir(dir), apply(patchContent), apply(process))), Array.fromAsync);
92
- /**
93
- * Patches file content by either merging JSON or appending text content.
94
- * Handles existing files by reading their current content and intelligently
95
- * combining it with new content based on the content type (JSON vs text).
96
- *
97
- * @param path - The file path to patch
98
- * @param content - The new content (either string or object)
99
- * @returns A tuple containing the file path and the final content string
100
- */
101
- async function patchContent(path, content) {
102
- const prev = await readFileIfExists(path);
103
- const data = typeof content === "object" ? mergeJson(prev, content) : appendText(prev, content);
104
- return [path, data];
105
- }
106
- /**
107
- * Merges new JSON data with existing JSON content and formats the result.
108
- * Parses existing JSON content (if any) and deep merges it with new data,
109
- * then formats the result for consistent output.
110
- * Supports JSONC (JSON with Comments) by removing comments before parsing.
111
- *
112
- * @param prev - The previous JSON content as string
113
- * @param data - The new data object to merge
114
- * @returns Formatted JSON string with merged content
115
- */
116
- const mergeJson = (prev, data) => pipe(prev ? JSON.parse(removeJsonComments(prev)) : {}, merge(data), formatJson);
117
- /**
118
- * Removes single-line (//) and multi-line (/* *\/) comments from JSON string.
119
- * This allows parsing JSONC (JSON with Comments) files.
120
- *
121
- * @param jsonString - The JSON string potentially containing comments
122
- * @returns JSON string with comments removed
123
- */
124
- const removeJsonComments = (jsonString) => pipe(jsonString, replaceAll(/\/\/.*$/gm, ""), replaceAll(/\/\*[\s\S]*?\*\//g, ""));
125
- /**
126
- * Appends new text content to existing text content line by line.
127
- * Concatenates new content lines with existing content lines,
128
- * preserving line structure and formatting.
129
- *
130
- * @param prev - The previous text content
131
- * @param data - The new text content to append
132
- * @returns Combined text content as a single string
133
- */
134
- const appendText = (prev, data) => prev ? `${prev}\n${data}` : data;
135
- /**
136
- * Safely reads a file if it exists, returns empty string if it doesn't exist.
137
- * Provides error handling to distinguish between "file not found" and other
138
- * file system errors, throwing only for unexpected errors.
139
- *
140
- * @param path - The file path to read
141
- * @returns The file content as string, or empty string if file doesn't exist
142
- * @throws Error if file access fails for reasons other than file not existing
143
- */
144
- const readFileIfExists = (path) => readFile(path, "utf8").catch(pipeLazy(tap(throwUnlessNotExists), always("")));
145
-
146
- //#endregion
147
- export { patchFiles, recommendPatchFiles };
@@ -1,28 +0,0 @@
1
-
2
- import { Temporal } from "@js-temporal/polyfill";
3
-
4
- import { CommandError, exit, runSubCommand } from "../../utils.js";
5
-
6
- //#region src/init/action/precommand.ts
7
- /**
8
- * Runs the precommand specified in the initializer to set up the project.
9
- *
10
- * @param data - The initialization command data containing the initializer command and directory
11
- * @returns A promise that resolves when the precommand has been executed
12
- */
13
- const runPrecommand = ({ initializer: { command }, dir }) => runSubCommand(command, {
14
- cwd: dir,
15
- stdio: "inherit"
16
- }).catch((e) => {
17
- if (e instanceof CommandError) {
18
- console.error("Failed to run the precommand.");
19
- console.error("Command:", e.commandLine);
20
- if (e.stderr) console.error("Error:", e.stderr);
21
- if (e.stdout) console.error("Output:", e.stdout);
22
- } else console.error("Failed to run the precommand:", e);
23
- exit(1);
24
- });
25
- var precommand_default = runPrecommand;
26
-
27
- //#endregion
28
- export { precommand_default as default };
@@ -1,24 +0,0 @@
1
-
2
- import { Temporal } from "@js-temporal/polyfill";
3
-
4
- import { notEmpty } from "../../utils.js";
5
- import { noticeDeps, noticeDepsIfExist, noticeDevDepsIfExist } from "./notice.js";
6
- import { isDeno } from "./utils.js";
7
- import { getDependencies, getDevDependencies } from "./deps.js";
8
- import { map, peek, pipeLazy, tap, unless, when } from "@fxts/core";
9
-
10
- //#region src/init/action/recommend.ts
11
- const recommendDeps = pipeLazy(getDependencies, Object.entries, when(notEmpty, tap(noticeDepsIfExist)), peek(noticeDeps));
12
- const recommendDevDeps = pipeLazy(getDevDependencies, Object.entries, when(notEmpty, tap(noticeDevDepsIfExist)), map(noticeDeps));
13
- /**
14
- * Recommends dependencies and devDependencies to be added to package.json.
15
- * Skips devDependencies recommendation if the package manager is Deno.
16
- *
17
- * @param data - The initialization command data
18
- * @returns An InitCommandIo function that performs the recommendation
19
- */
20
- const recommendDependencies = pipeLazy(tap(recommendDeps), unless(isDeno, tap(recommendDevDeps)));
21
- var recommend_default = recommendDependencies;
22
-
23
- //#endregion
24
- export { recommend_default as default };
@@ -1,31 +0,0 @@
1
-
2
- import { Temporal } from "@js-temporal/polyfill";
3
-
4
- import { merge, set } from "../../utils.js";
5
- import webframeworks_default from "../webframeworks.js";
6
- import { kvStores, messageQueues } from "../lib.js";
7
- import { basename, normalize } from "node:path";
8
- import { realpath } from "node:fs/promises";
9
- import { pipe } from "@fxts/core";
10
- import { existsSync } from "node:fs";
11
-
12
- //#region src/init/action/set.ts
13
- /**
14
- * Set all necessary data for initializing the project.
15
- * This function orchestrates the setting of project name, initializer,
16
- * key-value store, message queue, and environment variables by calling
17
- * individual setter functions for each piece of data.
18
- *
19
- * @param data - The initial command options provided by the user
20
- * @returns A promise resolving to a complete InitCommandData object
21
- */
22
- const setData = (data) => pipe(data, setProjectName, setInitializer, setKv, setMq, setEnv);
23
- var set_default = setData;
24
- const setProjectName = set("projectName", async ({ dir }) => basename(existsSync(dir) ? await realpath(dir) : normalize(dir)));
25
- const setInitializer = set("initializer", (data) => webframeworks_default[data.webFramework].init(data));
26
- const setKv = set("kv", ({ kvStore }) => kvStores[kvStore]);
27
- const setMq = set("mq", ({ messageQueue }) => messageQueues[messageQueue]);
28
- const setEnv = set("env", ({ kv, mq }) => merge(kv.env)(mq.env));
29
-
30
- //#endregion
31
- export { set_default as default };
@@ -1,58 +0,0 @@
1
-
2
- import { Temporal } from "@js-temporal/polyfill";
3
-
4
- import { replace } from "../../utils.js";
5
- import { readTemplate } from "../lib.js";
6
- import { entries, join, map, pipe } from "@fxts/core";
7
- import { toMerged } from "es-toolkit";
8
-
9
- //#region src/init/action/templates.ts
10
- /**
11
- * Loads the federation configuration file content from template.
12
- * Reads the default federation template and replaces placeholders with actual configuration values.
13
- *
14
- * @param param0 - Configuration object containing imports, project name, KV store, message queue, and package manager
15
- * @returns The complete federation configuration file content as a string
16
- */
17
- const loadFederation = ({ imports, projectName, kv, mq, packageManager }) => pipe("defaults/federation.ts", readTemplate, replace(/\/\* imports \*\//, imports), replace(/\/\* logger \*\//, JSON.stringify(projectName)), replace(/\/\* kv \*\//, convertEnv(kv.object, packageManager)), replace(/\/\* queue \*\//, convertEnv(mq.object, packageManager)));
18
- /**
19
- * Loads the logging configuration file content from template.
20
- * Reads the default logging template and replaces the project name placeholder.
21
- *
22
- * @param param0 - Destructured object containing the project name
23
- * @returns The complete logging configuration file content as a string
24
- */
25
- const loadLogging = ({ projectName }) => pipe("defaults/logging.ts", readTemplate, replace(/\/\* project name \*\//, JSON.stringify(projectName)));
26
- /**
27
- * Generates import statements for KV store and message queue dependencies.
28
- * Merges imports from both KV and MQ configurations and creates proper ES module import syntax.
29
- *
30
- * @param param0 - Destructured object containing kv and mq configurations
31
- * @returns A multi-line string containing all necessary import statements
32
- */
33
- const getImports = ({ kv, mq }) => pipe(toMerged(kv.imports, mq.imports), entries, map(([module, { "default": defaultImport = "",...imports }]) => [
34
- module,
35
- defaultImport,
36
- getAlias(imports)
37
- ]), map(([module, defaultImport, namedImports]) => `import ${[defaultImport, namedImports.length > 0 ? `{ ${namedImports} }` : ""].filter((x) => x.length > 0).join(", ")} from ${JSON.stringify(module)};`), join("\n"));
38
- /**
39
- * Converts import mappings to named import string with aliases.
40
- * Creates proper ES module named import syntax, using aliases when the import name differs from the local name.
41
- *
42
- * @param imports - A record mapping import names to their local aliases
43
- * @returns A comma-separated string of named imports with aliases where needed
44
- */
45
- const getAlias = (imports) => pipe(imports, entries, map(([name, alias]) => name === alias ? name : `${name} as ${alias}`), join(", "));
46
- const ENV_REG_EXP = /process\.env\.(\w+)/g;
47
- /**
48
- * Converts Node.js environment variable access to Deno-compatible syntax when needed.
49
- * Transforms `process.env.VAR_NAME` to `Deno.env.get("VAR_NAME")` for Deno projects.
50
- *
51
- * @param obj - The object string containing potential environment variable references
52
- * @param pm - The package manager (runtime) being used
53
- * @returns The converted object string with appropriate environment variable access syntax
54
- */
55
- const convertEnv = (obj, pm) => pm === "deno" && ENV_REG_EXP.test(obj) ? obj.replaceAll(ENV_REG_EXP, (_, g1) => `Deno.env.get("${g1}")`) : obj;
56
-
57
- //#endregion
58
- export { getImports, loadFederation, loadLogging };
@@ -1,50 +0,0 @@
1
-
2
- import { Temporal } from "@js-temporal/polyfill";
3
-
4
- import { join } from "node:path";
5
-
6
- //#region src/init/action/utils.ts
7
- const isDry = ({ dryRun }) => dryRun;
8
- const hasCommand = (data) => !!data.initializer.command;
9
- const isDeno = ({ packageManager }) => packageManager === "deno";
10
- const joinDir = (dir) => ([filename, content]) => [join(dir, ...filename.split("/")), content];
11
- /**
12
- * Stringify an object into a valid `.env` file format.
13
- * From `@std/dotenv/stringify`.
14
- *
15
- * @example Usage
16
- * ```ts
17
- * import { stringifyEnvs } from "./utils.ts";
18
- * import { assertEquals } from "@std/assert";
19
- *
20
- * const object = { GREETING: "hello world" };
21
- * assertEquals(stringifyEnvs(object), "GREETING='hello world'");
22
- * ```
23
- *
24
- * @param object object to be stringified
25
- * @returns string of object
26
- */
27
- function stringifyEnvs(object) {
28
- const lines = [];
29
- for (const [key, value] of Object.entries(object)) {
30
- let quote;
31
- let escapedValue = value ?? "";
32
- if (key.startsWith("#")) {
33
- console.warn(`key starts with a '#' indicates a comment and is ignored: '${key}'`);
34
- continue;
35
- } else if (escapedValue.includes("\n") || escapedValue.includes("'")) {
36
- escapedValue = escapedValue.replaceAll("\n", "\\n");
37
- quote = `"`;
38
- } else if (escapedValue.match(/\W/)) quote = "'";
39
- if (quote) {
40
- escapedValue = escapedValue.replaceAll(quote, `\\${quote}`);
41
- escapedValue = `${quote}${escapedValue}${quote}`;
42
- }
43
- const line = `${key}=${escapedValue}`;
44
- lines.push(line);
45
- }
46
- return lines.join("\n");
47
- }
48
-
49
- //#endregion
50
- export { hasCommand, isDeno, isDry, joinDir, stringifyEnvs };
@@ -1,82 +0,0 @@
1
-
2
- import { Temporal } from "@js-temporal/polyfill";
3
-
4
- import { getCwd, getOsType, runSubCommand } from "../../utils.js";
5
- import { isDirectoryEmpty, logger } from "../lib.js";
6
- import { printError } from "@optique/run";
7
- import { message } from "@optique/core/message";
8
- import { identity, pipe, when } from "@fxts/core";
9
- import { input } from "@inquirer/prompts";
10
- import toggle from "inquirer-toggle";
11
-
12
- //#region src/init/ask/dir.ts
13
- /**
14
- * Fills in the project directory by prompting the user if not provided.
15
- * If the directory is not empty, asks the user whether to use it anyway.
16
- * If the user agrees, offers to move existing contents to trash.
17
- * Else, recursively prompts for a new directory until a valid one is provided.
18
- *
19
- * @param options - Initialization options possibly containing a directory
20
- * @returns A promise resolving to options with a guaranteed directory
21
- */
22
- const fillDir = async (options) => {
23
- const dir = options.dir ?? await askDir(getCwd());
24
- return await askIfNonEmpty(dir) ? {
25
- ...options,
26
- dir
27
- } : await fillDir(options);
28
- };
29
- var dir_default = fillDir;
30
- const askDir = (cwd) => input({
31
- message: "Project directory:",
32
- default: cwd
33
- });
34
- const askIfNonEmpty = async (dir) => {
35
- if (await isDirectoryEmpty(dir)) return true;
36
- if (await askNonEmpty(dir)) return await moveDirToTrash(dir);
37
- return false;
38
- };
39
- const askNonEmpty = (dir) => toggle.default({
40
- message: `Directory "${dir}" is not empty.
41
- Do you want to use it anyway?`,
42
- default: false
43
- });
44
- const moveDirToTrash = (dir) => pipe(dir, askMoveToTrash, when(identity, moveToTrash(dir)));
45
- const askMoveToTrash = (dir) => toggle.default({
46
- message: `Do you want to move the contents of "${dir}" to the trash?
47
- If you choose "No", you should choose another directory.`,
48
- default: false
49
- });
50
- const moveToTrash = (dir) => () => pipe(getOsType(), getTrashCommand, (fn) => fn(dir), (cmd) => runSubCommand(cmd, { stdio: "ignore" }), () => true).catch((e) => {
51
- logger.error(e);
52
- printError(message`Failed to move ${dir} to trash.
53
- Please move it manually.`);
54
- return false;
55
- });
56
- const getTrashCommand = (os) => trashCommands[os] ?? trashCommands.linux;
57
- const trashCommands = {
58
- darwin: (dir) => ["trash", dir],
59
- win32: (dir) => [
60
- "powershell",
61
- "-Command",
62
- getPowershellTrashCommand(dir)
63
- ],
64
- linux: (dir) => [
65
- "rm",
66
- "-rf",
67
- dir
68
- ]
69
- };
70
- const getPowershellTrashCommand = (dir) => [
71
- "Add-Type",
72
- "-AssemblyName",
73
- "Microsoft.VisualBasic;",
74
- "[Microsoft.VisualBasic.FileIO.FileSystem]::DeleteDirectory('",
75
- dir,
76
- "',",
77
- "'OnlyErrorDialogs',",
78
- "'SendToRecycleBin')"
79
- ].join(" ");
80
-
81
- //#endregion
82
- export { dir_default as default };