@reliverse/dler 1.2.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.
- package/LICENSE +21 -0
- package/README.md +312 -0
- package/bin/cli/args/agg/main.js +0 -0
- package/bin/cli/args/conv/README.md +3 -0
- package/bin/cli/args/conv/main.js +0 -0
- package/bin/cli/args/deps/analyzer.js +42 -0
- package/bin/cli/args/deps/filesystem.js +42 -0
- package/bin/cli/args/deps/formatter.js +65 -0
- package/bin/cli/args/deps/mod.js +48 -0
- package/bin/cli/args/deps/parser.js +59 -0
- package/bin/cli/args/deps/types.js +0 -0
- package/bin/cli/args/init/README.md +121 -0
- package/bin/cli/args/init/libs/reinit/reinit-main.js +5 -0
- package/bin/cli/args/init/libs/reinit/reint-impl/const.js +26 -0
- package/bin/cli/args/init/libs/reinit/reint-impl/mod.txt +395 -0
- package/bin/cli/args/init/libs/reinit/reint-impl/templates/t-gitignore.js +9 -0
- package/bin/cli/args/init/libs/reinit/reint-impl/templates/t-license.js +22 -0
- package/bin/cli/args/init/libs/reinit/reint-impl/templates/t-readme.js +59 -0
- package/bin/cli/args/init/libs/reinit/reint-impl/types.js +0 -0
- package/bin/cli/args/init/libs/reinit/reint-impl/utils.js +3 -0
- package/bin/cli/args/init/main.txt +121 -0
- package/bin/cli/args/init/types.js +1 -0
- package/bin/cli/args/inject/README.md +148 -0
- package/bin/cli/args/inject/arg-ts-expect-error.txt +49 -0
- package/bin/cli/args/inject/cli-mod.js +32 -0
- package/bin/cli/args/inject/main.txt +28 -0
- package/bin/cli/args/inject/reinject.config.js +4 -0
- package/bin/cli/args/inject/ts-expect-error.txt +277 -0
- package/bin/cli/args/merger/README.md +125 -0
- package/bin/cli/args/merger/main.txt +306 -0
- package/bin/cli/args/mono/main.js +0 -0
- package/bin/cli/args/spells/mod.js +44 -0
- package/bin/cli/args/split/README.md +13 -0
- package/bin/cli/args/split/split-main.js +26 -0
- package/bin/cli/args/split/split-mod.js +117 -0
- package/bin/cli/args/tools/index.js +81 -0
- package/bin/cli/args/tools/tools-impl.js +296 -0
- package/bin/cli.js +111 -0
- package/bin/init.js +157 -0
- package/bin/libs/cfg/cfg-default.js +50 -0
- package/bin/libs/cfg/cfg-main.js +1 -0
- package/bin/libs/cfg/cfg-mod.js +4 -0
- package/bin/libs/cfg/cfg-types.js +1 -0
- package/bin/libs/sdk/sdk-impl/build/build-library.js +865 -0
- package/bin/libs/sdk/sdk-impl/build/build-regular.js +373 -0
- package/bin/libs/sdk/sdk-impl/build/bundlers/unified/auto.js +110 -0
- package/bin/libs/sdk/sdk-impl/build/bundlers/unified/build.js +322 -0
- package/bin/libs/sdk/sdk-impl/build/bundlers/unified/copy/copy.js +62 -0
- package/bin/libs/sdk/sdk-impl/build/bundlers/unified/copy/types.js +0 -0
- package/bin/libs/sdk/sdk-impl/build/bundlers/unified/mkdist/mkdist.js +57 -0
- package/bin/libs/sdk/sdk-impl/build/bundlers/unified/mkdist/types.js +0 -0
- package/bin/libs/sdk/sdk-impl/build/bundlers/unified/rollup/build.js +104 -0
- package/bin/libs/sdk/sdk-impl/build/bundlers/unified/rollup/config.js +124 -0
- package/bin/libs/sdk/sdk-impl/build/bundlers/unified/rollup/plugins/cjs.js +48 -0
- package/bin/libs/sdk/sdk-impl/build/bundlers/unified/rollup/plugins/esbuild.js +91 -0
- package/bin/libs/sdk/sdk-impl/build/bundlers/unified/rollup/plugins/json.js +17 -0
- package/bin/libs/sdk/sdk-impl/build/bundlers/unified/rollup/plugins/raw.js +20 -0
- package/bin/libs/sdk/sdk-impl/build/bundlers/unified/rollup/plugins/shebang.js +42 -0
- package/bin/libs/sdk/sdk-impl/build/bundlers/unified/rollup/stub.js +137 -0
- package/bin/libs/sdk/sdk-impl/build/bundlers/unified/rollup/types.js +0 -0
- package/bin/libs/sdk/sdk-impl/build/bundlers/unified/rollup/utils.js +41 -0
- package/bin/libs/sdk/sdk-impl/build/bundlers/unified/rollup/watch.js +33 -0
- package/bin/libs/sdk/sdk-impl/build/bundlers/unified/types.js +6 -0
- package/bin/libs/sdk/sdk-impl/build/bundlers/unified/untyped/index.js +125 -0
- package/bin/libs/sdk/sdk-impl/build/bundlers/unified/untyped/types.js +0 -0
- package/bin/libs/sdk/sdk-impl/build/bundlers/unified/utils.js +158 -0
- package/bin/libs/sdk/sdk-impl/build/bundlers/unified/validate.js +68 -0
- package/bin/libs/sdk/sdk-impl/library-flow.js +169 -0
- package/bin/libs/sdk/sdk-impl/pub/pub-library.js +132 -0
- package/bin/libs/sdk/sdk-impl/pub/pub-regular.js +69 -0
- package/bin/libs/sdk/sdk-impl/regular-flow.js +219 -0
- package/bin/libs/sdk/sdk-impl/spells/spells-executors.js +307 -0
- package/bin/libs/sdk/sdk-impl/spells/spells-filesystem.js +72 -0
- package/bin/libs/sdk/sdk-impl/spells/spells-main.js +87 -0
- package/bin/libs/sdk/sdk-impl/spells/spells-parser.js +60 -0
- package/bin/libs/sdk/sdk-impl/spells/spells-types.js +0 -0
- package/bin/libs/sdk/sdk-impl/utils/tools/tools-agg.js +149 -0
- package/bin/libs/sdk/sdk-impl/utils/tools/tools-impl.js +21 -0
- package/bin/libs/sdk/sdk-impl/utils/utils-build.js +102 -0
- package/bin/libs/sdk/sdk-impl/utils/utils-bump.js +238 -0
- package/bin/libs/sdk/sdk-impl/utils/utils-clean.js +35 -0
- package/bin/libs/sdk/sdk-impl/utils/utils-consts.js +17 -0
- package/bin/libs/sdk/sdk-impl/utils/utils-cwd.js +36 -0
- package/bin/libs/sdk/sdk-impl/utils/utils-deps.js +73 -0
- package/bin/libs/sdk/sdk-impl/utils/utils-determine.js +25 -0
- package/bin/libs/sdk/sdk-impl/utils/utils-error.js +17 -0
- package/bin/libs/sdk/sdk-impl/utils/utils-fs.js +202 -0
- package/bin/libs/sdk/sdk-impl/utils/utils-info.js +42 -0
- package/bin/libs/sdk/sdk-impl/utils/utils-jsr-json.js +51 -0
- package/bin/libs/sdk/sdk-impl/utils/utils-paths.js +658 -0
- package/bin/libs/sdk/sdk-impl/utils/utils-perf.js +22 -0
- package/bin/libs/sdk/sdk-impl/utils/utils-pkg-json-libs.js +259 -0
- package/bin/libs/sdk/sdk-impl/utils/utils-pkg-json-reg.js +207 -0
- package/bin/libs/sdk/sdk-impl/utils/utils-tsconfig.js +44 -0
- package/bin/libs/sdk/sdk-main.js +114 -0
- package/bin/libs/sdk/sdk-types.js +1 -0
- package/bin/load.js +27 -0
- package/bin/main.js +46 -0
- package/bin/tools.txt +92 -0
- package/bin/types.js +0 -0
- package/package.json +93 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# @reliverse/reinit | Reinit CLI & Core
|
|
2
|
+
|
|
3
|
+
[💖 GitHub Sponsors](https://github.com/sponsors/blefnk) • [💬 Discord](https://discord.gg/Pb8uKbwpsJ) • [📦 NPM](https://npmjs.com/@reliverse/reinit-cli) • [📚 Docs](https://blefnk.reliverse.org/blog/my-products/reinit)
|
|
4
|
+
|
|
5
|
+
**@reliverse/reinit** is your buddy for bootstrapping the boring stuff — so you can jump straight into building the good stuff.
|
|
6
|
+
|
|
7
|
+
- Need a `README.md`? `.gitignore`? `eslint.config.js`? Boom — done.
|
|
8
|
+
- Configs, docs, boilerplate — Reinit helps you set them up in seconds, not hours.
|
|
9
|
+
|
|
10
|
+
## 🛠️ What it can do
|
|
11
|
+
|
|
12
|
+
- 📝 Instantly generate common project files (README, LICENSE, configs, etc).
|
|
13
|
+
- ⚙️ Supports a wide range of file types: `eslint`, `knip`, `tsconfig`, `gitignore`, and more.
|
|
14
|
+
- 🚀 Use presets or customize everything with interactive prompts.
|
|
15
|
+
- 🛠️ Choose between single-file or multi-file generation.
|
|
16
|
+
- 📦 Comes in two flavors: CLI (`@reliverse/reinit-cli`) and Core (`@reliverse/reinit`) — use whichever fits your flow.
|
|
17
|
+
- 🧠 Handles conflicts smartly: overwrite, skip, prompt, or attach an index.
|
|
18
|
+
|
|
19
|
+
## ⚡ Getting Started
|
|
20
|
+
|
|
21
|
+
Ensure Git, Node.js, and bun•pnpm•yarn•npm are installed. Then:
|
|
22
|
+
|
|
23
|
+
### Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
bun i -g @reliverse/reinit-cli
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Or use with `bun x` (or `npx`):
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
bun x @reliverse/reinit-cli
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Basic Usage
|
|
36
|
+
|
|
37
|
+
Run without arguments to launch interactive mode:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
reinit-cli
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Generate a specific file
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
reinit-cli --fileType md:README
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Generate multiple files
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
reinit-cli --multiple
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Add `--parallel` to go even faster:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
reinit-cli --multiple --parallel --concurrency 3
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Custom destination
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
reinit-cli --fileType git:gitignore --destDir ./my-folder
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## 🧩 Supported File Types
|
|
68
|
+
|
|
69
|
+
Some examples of supported `fileType` values:
|
|
70
|
+
|
|
71
|
+
- `md:README`
|
|
72
|
+
- `md:LICENSE`
|
|
73
|
+
- `cfg:eslint`
|
|
74
|
+
- `cfg:tsconfig.json`
|
|
75
|
+
- `cfg:package.json`
|
|
76
|
+
- `cfg:reliverse`
|
|
77
|
+
- `cfg:knip`
|
|
78
|
+
- `git:gitignore`
|
|
79
|
+
- `git:gitattributes`
|
|
80
|
+
|
|
81
|
+
Each file type has smart defaults and helpful variations. Choose one, or let the CLI guide you.
|
|
82
|
+
|
|
83
|
+
## 🧠 Advanced Features
|
|
84
|
+
|
|
85
|
+
- 🔄 **Fallback copy mode** — If generating fails, Reinit can copy templates from your local base.
|
|
86
|
+
- 🧩 **Attach index** — Already have a file? Reinit can create `file.1.json`, `file.2.json`, etc. Instead of overwriting, it builds alongside.
|
|
87
|
+
- 🧠 **Configurable behavior** — Add `reinit.config.ts` to control parallelism, conflict handling, and lifecycle hooks.
|
|
88
|
+
|
|
89
|
+
## 🧪 CLI Flags
|
|
90
|
+
|
|
91
|
+
| Flag | Description |
|
|
92
|
+
|-----------------|--------------------------------------------|
|
|
93
|
+
| `--fileType` | File type to generate (e.g. `md:README`) |
|
|
94
|
+
| `--destDir` | Destination directory (default: `.`) |
|
|
95
|
+
| `--multiple` | Select multiple files via interactive UI |
|
|
96
|
+
| `--parallel` | Run tasks in parallel |
|
|
97
|
+
| `--concurrency` | Set concurrency for parallel execution |
|
|
98
|
+
| `--dev` | Run in dev mode |
|
|
99
|
+
|
|
100
|
+
## ✅ TODO
|
|
101
|
+
|
|
102
|
+
- [x] Implement basic logic
|
|
103
|
+
- [ ] Parse templates for `gitignore` ([link](https://github.com/github/gitignore#readme)), `gitattributes` ([link](https://github.com/gitattributes/gitattributes#readme)), etc
|
|
104
|
+
|
|
105
|
+
## 🔋 Powered by
|
|
106
|
+
|
|
107
|
+
- 🧠 [`@reliverse/reinit`](https://npmjs.com/@reliverse/reinit) — the core engine
|
|
108
|
+
- ⚡ [`@reliverse/rempts`](https://npmjs.com/@reliverse/rempts) — interactive prompts
|
|
109
|
+
- 🧰 [`c12`](https://github.com/unjs/c12) — zero-config file loading
|
|
110
|
+
|
|
111
|
+
## 🫶 Show some love
|
|
112
|
+
|
|
113
|
+
If `@reliverse/reinit` made your setup easier:
|
|
114
|
+
|
|
115
|
+
- ⭐ [Star the repo](https://github.com/reliverse/reinit)
|
|
116
|
+
- 💖 [Sponsor on GitHub](https://github.com/sponsors/blefnk)
|
|
117
|
+
- 🫶 Share it with a dev friend!
|
|
118
|
+
|
|
119
|
+
## 📄 License
|
|
120
|
+
|
|
121
|
+
MIT © 2025 [blefnk (Nazar Kornienko)](https://github.com/blefnk)
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { FILE_TYPES } from "./reint-impl/const.js";
|
|
2
|
+
export { gitignoreTemplate } from "./reint-impl/templates/t-gitignore.js";
|
|
3
|
+
export { licenseTemplate } from "./reint-impl/templates/t-license.js";
|
|
4
|
+
export { readmeTemplate } from "./reint-impl/templates/t-readme.js";
|
|
5
|
+
export { escapeMarkdownCodeBlocks } from "./reint-impl/utils.js";
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export const FILE_TYPES = [
|
|
2
|
+
{ type: "cfg:eslint", variations: ["eslint.config.js"] },
|
|
3
|
+
{ type: "cfg:knip", variations: ["knip.json"] },
|
|
4
|
+
{
|
|
5
|
+
type: "cfg:reliverse",
|
|
6
|
+
variations: [".config/rse.jsonc", ".config/rse.ts"]
|
|
7
|
+
},
|
|
8
|
+
{ type: "cfg:package.json", variations: ["package.json"] },
|
|
9
|
+
{ type: "cfg:tsconfig.json", variations: ["tsconfig.json"] },
|
|
10
|
+
{ type: "git:gitattributes", variations: [".gitattributes"] },
|
|
11
|
+
{ type: "git:gitignore", variations: [".gitignore"] },
|
|
12
|
+
{ type: "md:LICENSE", variations: ["LICENSE.md", "LICENSE"] },
|
|
13
|
+
{ type: "md:README", variations: ["README.md"] }
|
|
14
|
+
];
|
|
15
|
+
export const INIT_BEHAVIOURS = [
|
|
16
|
+
"create",
|
|
17
|
+
"copy",
|
|
18
|
+
"create-if-copy-failed"
|
|
19
|
+
];
|
|
20
|
+
export const DEST_FILE_EXISTS_BEHAVIOURS = [
|
|
21
|
+
"rewrite",
|
|
22
|
+
"skip",
|
|
23
|
+
"attach-index",
|
|
24
|
+
"prompt"
|
|
25
|
+
];
|
|
26
|
+
export const CONTENT_CREATE_MODES = ["license-basic", "simple-readme"];
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
import { relinka, selectPrompt } from "@reliverse/rempts";
|
|
2
|
+
import { loadConfig } from "c12";
|
|
3
|
+
import fs from "fs-extra";
|
|
4
|
+
import pMap from "p-map";
|
|
5
|
+
import path from "pathe";
|
|
6
|
+
|
|
7
|
+
import type {
|
|
8
|
+
DestFileExistsBehaviour,
|
|
9
|
+
FileType,
|
|
10
|
+
InitBehaviour,
|
|
11
|
+
InitFileRequest,
|
|
12
|
+
InitFileResult,
|
|
13
|
+
ReinitUserConfig,
|
|
14
|
+
} from "./types.js";
|
|
15
|
+
|
|
16
|
+
import { FILE_TYPES } from "./const.js";
|
|
17
|
+
import { gitignoreTemplate } from "./templates/t-gitignore.js";
|
|
18
|
+
import { licenseTemplate } from "./templates/t-license.js";
|
|
19
|
+
import { readmeTemplate } from "./templates/t-readme.js";
|
|
20
|
+
import { escapeMarkdownCodeBlocks } from "./utils.js";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Creates a file from scratch, including parent directories,
|
|
24
|
+
* basing the file content on the fileType.
|
|
25
|
+
*/
|
|
26
|
+
export async function createFileFromScratch(
|
|
27
|
+
destPath: string,
|
|
28
|
+
fileType: FileType, // e.g. "cfg:eslint", "md:LICENSE", "md:README", ...
|
|
29
|
+
contentCreateMode?: string,
|
|
30
|
+
) {
|
|
31
|
+
// Ensure parent directory
|
|
32
|
+
await fs.ensureDir(path.dirname(destPath));
|
|
33
|
+
|
|
34
|
+
let content = "";
|
|
35
|
+
switch (fileType) {
|
|
36
|
+
case "md:LICENSE":
|
|
37
|
+
content = licenseTemplate;
|
|
38
|
+
break;
|
|
39
|
+
case "md:README":
|
|
40
|
+
content = escapeMarkdownCodeBlocks(readmeTemplate);
|
|
41
|
+
break;
|
|
42
|
+
case "git:gitignore":
|
|
43
|
+
content = gitignoreTemplate;
|
|
44
|
+
break;
|
|
45
|
+
default:
|
|
46
|
+
content = `// Auto-generated file for type: ${fileType}`;
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (contentCreateMode) {
|
|
51
|
+
content = contentCreateMode;
|
|
52
|
+
relinka("verbose", `Using custom content for file ${destPath}`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
await fs.outputFile(destPath, content, { encoding: "utf-8" });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Loads user config from `reinit.config.(ts|js|json...)` using c12
|
|
60
|
+
* and merges with fallback defaults.
|
|
61
|
+
*/
|
|
62
|
+
async function loadReinitConfig(): Promise<ReinitUserConfig> {
|
|
63
|
+
const { config } = await loadConfig<ReinitUserConfig>({
|
|
64
|
+
name: "reinit",
|
|
65
|
+
defaults: {},
|
|
66
|
+
overrides: {},
|
|
67
|
+
dotenv: false,
|
|
68
|
+
packageJson: false,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const merged: ReinitUserConfig = {
|
|
72
|
+
defaultInitBehaviour: config.defaultInitBehaviour ?? "create",
|
|
73
|
+
defaultDestFileExistsBehaviour:
|
|
74
|
+
config.defaultDestFileExistsBehaviour ?? "prompt",
|
|
75
|
+
parallelByDefault: config.parallelByDefault ?? false,
|
|
76
|
+
parallelConcurrency: config.parallelConcurrency ?? 4,
|
|
77
|
+
onFileStart: config.onFileStart,
|
|
78
|
+
onFileComplete: config.onFileComplete,
|
|
79
|
+
};
|
|
80
|
+
return merged;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Single-file initialization using the merged config.
|
|
85
|
+
*/
|
|
86
|
+
export async function initFile(
|
|
87
|
+
req: InitFileRequest,
|
|
88
|
+
userCfg?: ReinitUserConfig,
|
|
89
|
+
): Promise<InitFileResult> {
|
|
90
|
+
const config = userCfg ?? (await loadReinitConfig());
|
|
91
|
+
const initBehaviour = req.initBehaviour ?? config.defaultInitBehaviour!;
|
|
92
|
+
const existsBehaviour =
|
|
93
|
+
req.destFileExistsBehaviour ?? config.defaultDestFileExistsBehaviour!;
|
|
94
|
+
|
|
95
|
+
config.onFileStart?.(req);
|
|
96
|
+
|
|
97
|
+
let result: InitFileResult;
|
|
98
|
+
try {
|
|
99
|
+
result = await doInitFile(req, initBehaviour, existsBehaviour);
|
|
100
|
+
} catch (error) {
|
|
101
|
+
result = {
|
|
102
|
+
requested: req,
|
|
103
|
+
status: "error",
|
|
104
|
+
error,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
config.onFileComplete?.(result);
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Multi-file version. By default, uses the "parallelByDefault" from config.
|
|
114
|
+
* If parallel is true, uses p-map with concurrency from "parallelConcurrency".
|
|
115
|
+
*/
|
|
116
|
+
export async function initFiles(
|
|
117
|
+
items: InitFileRequest[],
|
|
118
|
+
options?: { parallel?: boolean; concurrency?: number },
|
|
119
|
+
userCfg?: ReinitUserConfig,
|
|
120
|
+
): Promise<InitFileResult[]> {
|
|
121
|
+
const config = userCfg ?? (await loadReinitConfig());
|
|
122
|
+
|
|
123
|
+
const parallel =
|
|
124
|
+
typeof options?.parallel === "boolean"
|
|
125
|
+
? options.parallel
|
|
126
|
+
: config.parallelByDefault;
|
|
127
|
+
|
|
128
|
+
const concurrency = options?.concurrency ?? config.parallelConcurrency ?? 4;
|
|
129
|
+
|
|
130
|
+
if (parallel) {
|
|
131
|
+
return pMap(items, (item) => initFile(item, config), { concurrency });
|
|
132
|
+
} else {
|
|
133
|
+
const results: InitFileResult[] = [];
|
|
134
|
+
for (const item of items) {
|
|
135
|
+
results.push(await initFile(item, config));
|
|
136
|
+
}
|
|
137
|
+
return results;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* The main logic for creating or copying a file.
|
|
143
|
+
*/
|
|
144
|
+
async function doInitFile(
|
|
145
|
+
req: InitFileRequest,
|
|
146
|
+
initBehaviour: InitBehaviour,
|
|
147
|
+
destFileExistsBehaviour: DestFileExistsBehaviour,
|
|
148
|
+
): Promise<InitFileResult> {
|
|
149
|
+
const { fileType, destDir, options } = req;
|
|
150
|
+
const { destFileName, srcCopyMode, fallbackSource } = options ?? {};
|
|
151
|
+
|
|
152
|
+
// Look up known variations for the fileType
|
|
153
|
+
const knownType = FILE_TYPES.find(
|
|
154
|
+
(f) => f.type.toLowerCase() === fileType.toLowerCase(),
|
|
155
|
+
);
|
|
156
|
+
const variations = knownType ? knownType.variations : [fileType];
|
|
157
|
+
|
|
158
|
+
// Possibly prompt if multiple variations exist
|
|
159
|
+
let chosenVariation: string;
|
|
160
|
+
if (variations.length === 1) {
|
|
161
|
+
chosenVariation = variations[0];
|
|
162
|
+
} else {
|
|
163
|
+
chosenVariation = await selectPrompt({
|
|
164
|
+
title: `Select variation for ${fileType}`,
|
|
165
|
+
options: variations.map((v) => ({ label: v, value: v })),
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const finalName = destFileName ?? chosenVariation;
|
|
170
|
+
|
|
171
|
+
// Convert destDir to absolute path
|
|
172
|
+
const absoluteDestDir = path.resolve(process.cwd(), destDir || "");
|
|
173
|
+
const resolvedDestPath = path.join(absoluteDestDir, finalName);
|
|
174
|
+
|
|
175
|
+
relinka(
|
|
176
|
+
"verbose",
|
|
177
|
+
`Preparing to init file:
|
|
178
|
+
- File Type: ${fileType}
|
|
179
|
+
- Variation: ${chosenVariation}
|
|
180
|
+
- Destination Dir: ${absoluteDestDir}
|
|
181
|
+
- Final Path: ${resolvedDestPath}
|
|
182
|
+
`,
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
// If file already exists
|
|
186
|
+
const alreadyExists = await fs.pathExists(resolvedDestPath);
|
|
187
|
+
if (alreadyExists) {
|
|
188
|
+
const maybeNewDest = await handleExistingFile(
|
|
189
|
+
resolvedDestPath,
|
|
190
|
+
destFileExistsBehaviour,
|
|
191
|
+
);
|
|
192
|
+
if (!maybeNewDest) {
|
|
193
|
+
return {
|
|
194
|
+
requested: req,
|
|
195
|
+
status: "skipped",
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
if (maybeNewDest !== resolvedDestPath) {
|
|
199
|
+
// e.g., attach-index was chosen
|
|
200
|
+
relinka("info", `attach-index or rename => ${maybeNewDest}`);
|
|
201
|
+
return await finalizeInit(
|
|
202
|
+
req,
|
|
203
|
+
initBehaviour,
|
|
204
|
+
chosenVariation,
|
|
205
|
+
maybeNewDest,
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return await finalizeInit(
|
|
211
|
+
req,
|
|
212
|
+
initBehaviour,
|
|
213
|
+
chosenVariation,
|
|
214
|
+
resolvedDestPath,
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/** Reusable helper to finalize creation or copy after we pick a path. */
|
|
219
|
+
async function finalizeInit(
|
|
220
|
+
req: InitFileRequest,
|
|
221
|
+
initBehaviour: InitBehaviour,
|
|
222
|
+
chosenVariation: string,
|
|
223
|
+
resolvedDestPath: string,
|
|
224
|
+
): Promise<InitFileResult> {
|
|
225
|
+
try {
|
|
226
|
+
switch (initBehaviour) {
|
|
227
|
+
case "copy":
|
|
228
|
+
return await runCopy(req, chosenVariation, resolvedDestPath);
|
|
229
|
+
case "create":
|
|
230
|
+
return await runCreate(req, resolvedDestPath);
|
|
231
|
+
// If user or config explicitly sets "create-if-copy-failed" or something else
|
|
232
|
+
case "create-if-copy-failed":
|
|
233
|
+
default:
|
|
234
|
+
try {
|
|
235
|
+
return await runCopy(req, chosenVariation, resolvedDestPath);
|
|
236
|
+
} catch (err) {
|
|
237
|
+
relinka(
|
|
238
|
+
"warn",
|
|
239
|
+
`Copy failed for ${chosenVariation}, fallback to create...`,
|
|
240
|
+
);
|
|
241
|
+
return await runCreate(req, resolvedDestPath);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
} catch (error) {
|
|
245
|
+
throw error;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async function runCopy(
|
|
250
|
+
req: InitFileRequest,
|
|
251
|
+
chosenVariation: string,
|
|
252
|
+
resolvedDestPath: string,
|
|
253
|
+
): Promise<InitFileResult> {
|
|
254
|
+
const { srcCopyMode, fallbackSource } = req.options ?? {};
|
|
255
|
+
const resolvedSrcDir = path.resolve(process.cwd(), srcCopyMode || "");
|
|
256
|
+
const sourcePath = path.join(resolvedSrcDir, chosenVariation);
|
|
257
|
+
|
|
258
|
+
if (sourcePath === resolvedDestPath) {
|
|
259
|
+
relinka(
|
|
260
|
+
"warn",
|
|
261
|
+
`Source path equals destination => doing a no-op: ${sourcePath}`,
|
|
262
|
+
);
|
|
263
|
+
return {
|
|
264
|
+
requested: req,
|
|
265
|
+
finalPath: resolvedDestPath,
|
|
266
|
+
status: "copied",
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
relinka(
|
|
271
|
+
"info",
|
|
272
|
+
`Attempting copy:
|
|
273
|
+
- Source Dir: ${resolvedSrcDir}
|
|
274
|
+
- Source Path: ${sourcePath}
|
|
275
|
+
- Destination Path: ${resolvedDestPath}
|
|
276
|
+
`,
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
try {
|
|
280
|
+
await fs.ensureDir(path.dirname(resolvedDestPath));
|
|
281
|
+
|
|
282
|
+
if (!(await fs.pathExists(sourcePath))) {
|
|
283
|
+
throw new Error(`Source file not found: ${sourcePath}`);
|
|
284
|
+
}
|
|
285
|
+
await fs.copy(sourcePath, resolvedDestPath, { overwrite: true });
|
|
286
|
+
relinka("info", `Copied file: ${chosenVariation} -> ${resolvedDestPath}`);
|
|
287
|
+
return {
|
|
288
|
+
requested: req,
|
|
289
|
+
finalPath: resolvedDestPath,
|
|
290
|
+
status: "copied",
|
|
291
|
+
};
|
|
292
|
+
} catch (primaryErr) {
|
|
293
|
+
if (fallbackSource) {
|
|
294
|
+
relinka(
|
|
295
|
+
"warn",
|
|
296
|
+
`Primary copy failed, trying fallback: ${fallbackSource}`,
|
|
297
|
+
);
|
|
298
|
+
const fallbackFullPath = path.join(resolvedSrcDir, fallbackSource);
|
|
299
|
+
try {
|
|
300
|
+
await fs.ensureDir(path.dirname(resolvedDestPath));
|
|
301
|
+
if (!(await fs.pathExists(fallbackFullPath))) {
|
|
302
|
+
throw new Error(
|
|
303
|
+
`Fallback source file not found: ${fallbackFullPath}`,
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
await fs.copy(fallbackFullPath, resolvedDestPath, { overwrite: true });
|
|
307
|
+
relinka(
|
|
308
|
+
"info",
|
|
309
|
+
`Fallback copy: ${fallbackSource} -> ${resolvedDestPath}`,
|
|
310
|
+
);
|
|
311
|
+
return {
|
|
312
|
+
requested: req,
|
|
313
|
+
finalPath: resolvedDestPath,
|
|
314
|
+
status: "copied",
|
|
315
|
+
};
|
|
316
|
+
} catch (fallbackErr) {
|
|
317
|
+
throw new Error(
|
|
318
|
+
`Primary copy error: ${String(primaryErr)}\nFallback copy error: ${String(
|
|
319
|
+
fallbackErr,
|
|
320
|
+
)}`,
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
throw primaryErr;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
async function runCreate(
|
|
329
|
+
req: InitFileRequest,
|
|
330
|
+
resolvedDestPath: string,
|
|
331
|
+
): Promise<InitFileResult> {
|
|
332
|
+
relinka("verbose", `Creating file from scratch at: ${resolvedDestPath}`);
|
|
333
|
+
|
|
334
|
+
// The "fileType" is used to decide how to create content inside `createFileFromScratch`
|
|
335
|
+
const { fileType } = req;
|
|
336
|
+
|
|
337
|
+
await createFileFromScratch(resolvedDestPath, fileType);
|
|
338
|
+
relinka("verbose", `Created file from scratch: ${resolvedDestPath}`);
|
|
339
|
+
return {
|
|
340
|
+
requested: req,
|
|
341
|
+
finalPath: resolvedDestPath,
|
|
342
|
+
status: "created",
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/** If file exists, handle rewrite, skip, attach-index, or prompt. */
|
|
347
|
+
async function handleExistingFile(
|
|
348
|
+
destPath: string,
|
|
349
|
+
behaviour: DestFileExistsBehaviour,
|
|
350
|
+
): Promise<string | null> {
|
|
351
|
+
switch (behaviour) {
|
|
352
|
+
case "rewrite":
|
|
353
|
+
relinka("warn", `File exists, rewriting in-place: ${destPath}`);
|
|
354
|
+
return destPath;
|
|
355
|
+
|
|
356
|
+
case "skip":
|
|
357
|
+
relinka("warn", `File exists, skipping: ${destPath}`);
|
|
358
|
+
return null;
|
|
359
|
+
|
|
360
|
+
case "attach-index":
|
|
361
|
+
return attachIndex(destPath);
|
|
362
|
+
|
|
363
|
+
case "prompt":
|
|
364
|
+
const choice = await selectPrompt({
|
|
365
|
+
title: `File exists: ${path.basename(destPath)}. How to handle?`,
|
|
366
|
+
options: [
|
|
367
|
+
{ label: "Overwrite", value: "overwrite" },
|
|
368
|
+
{ label: "Skip", value: "skip" },
|
|
369
|
+
{ label: "Attach Index", value: "attachIndex" },
|
|
370
|
+
],
|
|
371
|
+
});
|
|
372
|
+
if (choice === "skip") return null;
|
|
373
|
+
if (choice === "attachIndex") {
|
|
374
|
+
return attachIndex(destPath);
|
|
375
|
+
}
|
|
376
|
+
relinka("warn", `Overwriting in-place: ${destPath}`);
|
|
377
|
+
return destPath;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/** For attach-index, do file.1.ext, file.2.ext, etc. */
|
|
382
|
+
async function attachIndex(originalPath: string) {
|
|
383
|
+
const ext = path.extname(originalPath);
|
|
384
|
+
const base = path.basename(originalPath, ext);
|
|
385
|
+
const dir = path.dirname(originalPath);
|
|
386
|
+
|
|
387
|
+
let counter = 1;
|
|
388
|
+
let newPath = originalPath;
|
|
389
|
+
while (await fs.pathExists(newPath)) {
|
|
390
|
+
newPath = path.join(dir, `${base}.${counter}${ext}`);
|
|
391
|
+
counter++;
|
|
392
|
+
}
|
|
393
|
+
relinka("info", `Attaching index => ${newPath}`);
|
|
394
|
+
return newPath;
|
|
395
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export const licenseTemplate = `# MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Nazar Kornienko (blefnk), Reliverse
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
`;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export const readmeTemplate = `# \u{1F680} Project Name
|
|
2
|
+
|
|
3
|
+
Welcome! This project was bootstrapped with [@reliverse/reinit](https://www.npmjs.com/package/@reliverse/reinit).
|
|
4
|
+
It's already got the basics \u2014 now it's your turn to make it awesome \u2728
|
|
5
|
+
|
|
6
|
+
## \u{1F527} Tech Stack
|
|
7
|
+
|
|
8
|
+
- \u2699\uFE0F Framework: _<Add your framework here>_
|
|
9
|
+
- \u{1F6E0}\uFE0F Tools: _<Add your tooling, CLIs, etc>_
|
|
10
|
+
- \u{1F9EA} Tests: _<Vitest, Jest, or something else?>_
|
|
11
|
+
- \u{1F9E0} Linting: _ESLint, Biome, etc_
|
|
12
|
+
- \u{1F310} Deployment: _<Vercel, Netlify, Railway?>_
|
|
13
|
+
|
|
14
|
+
## \u{1F680} Getting Started
|
|
15
|
+
|
|
16
|
+
Clone the repo and install dependencies:
|
|
17
|
+
|
|
18
|
+
'''bash
|
|
19
|
+
bun install
|
|
20
|
+
bun dev
|
|
21
|
+
'''
|
|
22
|
+
|
|
23
|
+
Or if you're using another package manager:
|
|
24
|
+
|
|
25
|
+
'''bash
|
|
26
|
+
npm install && npm run dev
|
|
27
|
+
# or
|
|
28
|
+
pnpm i && pnpm dev
|
|
29
|
+
'''
|
|
30
|
+
|
|
31
|
+
## \u{1F5C2}\uFE0F Project Structure
|
|
32
|
+
|
|
33
|
+
'''bash
|
|
34
|
+
src/
|
|
35
|
+
\u251C\u2500\u2500 components/
|
|
36
|
+
\u251C\u2500\u2500 pages/
|
|
37
|
+
\u251C\u2500\u2500 lib/
|
|
38
|
+
\u2514\u2500\u2500 styles/
|
|
39
|
+
'''
|
|
40
|
+
|
|
41
|
+
Feel free to tweak the structure to your liking.
|
|
42
|
+
|
|
43
|
+
## \u{1F9E9} Customize it
|
|
44
|
+
|
|
45
|
+
This project is just a starting point. You can add:
|
|
46
|
+
|
|
47
|
+
- \u{1F9D9}\u200D\u2642\uFE0F Your own components and UI
|
|
48
|
+
- \u{1F4E6} APIs, auth, i18n, analytics, whatever you need
|
|
49
|
+
- \u{1F916} AI integrations using [Reliverse CLI](https://www.npmjs.com/package/@reliverse/rse)
|
|
50
|
+
|
|
51
|
+
## \u{1FAF6} Credits
|
|
52
|
+
|
|
53
|
+
Made with \u2764\uFE0F using [@reliverse/reinit](https://reliverse.org)
|
|
54
|
+
Need help? [Join the Discord](https://discord.gg/Pb8uKbwpsJ)
|
|
55
|
+
|
|
56
|
+
## \u{1F4C4} License
|
|
57
|
+
|
|
58
|
+
MIT \xA9 YourNameHere
|
|
59
|
+
`;
|
|
File without changes
|