@create-node-app/core 0.6.0 → 0.6.2
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/README.md +148 -0
- package/dist/index.cjs +156 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +201 -80
- package/dist/index.js.map +1 -1
- package/package.json +10 -15
package/README.md
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<h1>⚙️ <code>@create-node-app/core</code></h1>
|
|
4
|
+
|
|
5
|
+
<p><strong>Programmatic engine behind Create Awesome Node App.</strong><br/>
|
|
6
|
+
Import the scaffolding pipeline — composable, headless, and CI-ready.</p>
|
|
7
|
+
|
|
8
|
+
[![npm][npmversion]][npmurl]
|
|
9
|
+
[![Downloads][npmdownloads]][npmurl]
|
|
10
|
+
[![License: MIT][licensebadge]][licenseurl]
|
|
11
|
+
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @create-node-app/core
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Requires **Node.js >= 22**.
|
|
23
|
+
|
|
24
|
+
> This is the _engine_ package. For the interactive CLI, use [`create-awesome-node-app`](https://www.npmjs.com/package/create-awesome-node-app) instead.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
### Scaffold a project programmatically
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { createNodeApp, getTemplateDirPath } from "@create-node-app/core";
|
|
34
|
+
|
|
35
|
+
await createNodeApp(
|
|
36
|
+
"my-app",
|
|
37
|
+
{
|
|
38
|
+
projectName: "my-app",
|
|
39
|
+
template: "react-vite-boilerplate",
|
|
40
|
+
},
|
|
41
|
+
(options) => Promise.resolve(options),
|
|
42
|
+
);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Check environment info
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
import { printEnvInfo } from "@create-node-app/core";
|
|
49
|
+
|
|
50
|
+
await printEnvInfo();
|
|
51
|
+
// Prints OS, CPU, Node, npm, browsers, etc. Then exits.
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Validate the Node.js version
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import { checkNodeVersion } from "@create-node-app/core";
|
|
58
|
+
|
|
59
|
+
checkNodeVersion(">=22", "my-tool");
|
|
60
|
+
// Exits with a red error message if the version doesn't match.
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## API Reference
|
|
66
|
+
|
|
67
|
+
All exports from `@create-node-app/core`:
|
|
68
|
+
|
|
69
|
+
### Functions
|
|
70
|
+
|
|
71
|
+
| Signature | Description |
|
|
72
|
+
| ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
73
|
+
| `createNodeApp(programName, options, transformOptions)` | Main scaffolding orchestrator. Resolves the template, copies files, merges configs, installs deps, and initializes git. |
|
|
74
|
+
| `checkNodeVersion(requiredVersion, packageName)` | Compares `process.version` against a semver range. Exits with code 1 if too old. |
|
|
75
|
+
| `checkForLatestVersion(packageName)` | Fetches the latest version from the npm registry. Falls back to `npm view`. Returns `null` if both fail. |
|
|
76
|
+
| `printEnvInfo()` | Prints OS, CPU, binaries, and browser info to stdout, then exits. |
|
|
77
|
+
| `getPackagePath(templateOrExtension, name?, ignorePackage?)` | Resolves a file path inside a template/extension directory (usually `package.json`). Handles GitHub URLs, `file://` URLs, and legacy slugs. |
|
|
78
|
+
| `getTemplateDirPath(templateOrExtensionUrl)` | Resolves the template directory. Looks for a `template/` subdirectory first, falls back to the resolved root. |
|
|
79
|
+
| `getTemplateBaseDirPath(templateOrExtensionUrl)` | Returns the parent of the `template/` directory (where `cna.config.json` lives). |
|
|
80
|
+
| `downloadRepository(options)` | Clones or pulls a Git repo into a cache dir, then copies files to the target. Supports offline mode, deduplication, and error formatting. |
|
|
81
|
+
| `loadTemplateCnaConfig(templateUrl)` | Loads the optional `cna.config.json` from a template's base directory. |
|
|
82
|
+
|
|
83
|
+
### Types
|
|
84
|
+
|
|
85
|
+
| Type | Shape |
|
|
86
|
+
| --------------------- | ----------------------------------------------------------------------------------------------------- |
|
|
87
|
+
| `CnaOptions` | `{ projectName, info?, verbose?, packageManager?, install?, template?, templatesOrExtensions?, ... }` |
|
|
88
|
+
| `CnaOptionsTransform` | `(options: CnaOptions) => Promise<CnaOptions>` |
|
|
89
|
+
| `CnaConfig` | `{ customOptions?: CnaCustomOption[] }` |
|
|
90
|
+
| `CnaCustomOption` | `{ name, type, message?, initial?, ... }` |
|
|
91
|
+
| `TemplateOrExtension` | `{ url: string; ignorePackage?: boolean }` |
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## How It Works
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
createNodeApp()
|
|
99
|
+
├── checkNodeVersion()
|
|
100
|
+
├── printEnvInfo() if info flag
|
|
101
|
+
├── resolve templates/extensions via getTemplateDirPath()
|
|
102
|
+
├── download Git repos via downloadRepository()
|
|
103
|
+
├── load cna.config.json via loadTemplateCnaConfig()
|
|
104
|
+
├── merge package.json files via lodash.merge
|
|
105
|
+
├── copy/process template files (Lodash interpolation, .if-npm, .append, etc.)
|
|
106
|
+
├── install dependencies (npm/yarn/pnpm/bun)
|
|
107
|
+
├── git init
|
|
108
|
+
└── format + lint:fix post-install
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Architecture
|
|
114
|
+
|
|
115
|
+
The package is organized into these modules:
|
|
116
|
+
|
|
117
|
+
| Module | Responsibility |
|
|
118
|
+
| -------------- | --------------------------------------------------------------------------------------------- |
|
|
119
|
+
| `index.ts` | Barrel export and main `createNodeApp` orchestration |
|
|
120
|
+
| `installer.ts` | Project directory creation, dep installation, git init, post-install scripts |
|
|
121
|
+
| `loaders.ts` | File discovery, classification (`.template`, `.append`, conditional prefixes), and processing |
|
|
122
|
+
| `package.ts` | Deep-merges `package.json` from multiple templates/extensions |
|
|
123
|
+
| `paths.ts` | URL resolution — GitHub branches, `file://`, legacy slugs, cache at `~/.cna/` |
|
|
124
|
+
| `git.ts` | Clone/pull with deduplication, offline support, error formatting |
|
|
125
|
+
| `config.ts` | Reads optional `cna.config.json` for custom CLI prompts |
|
|
126
|
+
| `helpers.ts` | Package manager detection, online check, path/naming utilities |
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Related
|
|
131
|
+
|
|
132
|
+
- [`create-awesome-node-app`](https://www.npmjs.com/package/create-awesome-node-app) — Interactive CLI built on this core
|
|
133
|
+
- [Create Node App](https://github.com/Create-Node-App/create-node-app) — Monorepo
|
|
134
|
+
- [Templates catalog](https://github.com/Create-Node-App/cna-templates)
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## License
|
|
139
|
+
|
|
140
|
+
MIT © [Create Node App Contributors](https://github.com/Create-Node-App/create-node-app/graphs/contributors)
|
|
141
|
+
|
|
142
|
+
<!-- Reference links -->
|
|
143
|
+
|
|
144
|
+
[npmversion]: https://img.shields.io/npm/v/@create-node-app/core.svg?style=flat-square&color=cb3837
|
|
145
|
+
[npmdownloads]: https://img.shields.io/npm/dm/@create-node-app/core.svg?style=flat-square&color=cb3837
|
|
146
|
+
[licensebadge]: https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square
|
|
147
|
+
[npmurl]: https://www.npmjs.com/package/@create-node-app/core
|
|
148
|
+
[licenseurl]: https://github.com/Create-Node-App/create-node-app/blob/main/LICENSE
|
package/dist/index.cjs
CHANGED
|
@@ -47,7 +47,7 @@ var import_semver3 = __toESM(require("semver"), 1);
|
|
|
47
47
|
var import_child_process3 = require("child_process");
|
|
48
48
|
|
|
49
49
|
// installer.ts
|
|
50
|
-
var
|
|
50
|
+
var import_lodash3 = __toESM(require("lodash"), 1);
|
|
51
51
|
var import_path4 = __toESM(require("path"), 1);
|
|
52
52
|
var import_fs5 = __toESM(require("fs"), 1);
|
|
53
53
|
var import_picocolors3 = __toESM(require("picocolors"), 1);
|
|
@@ -62,6 +62,11 @@ var import_picocolors = __toESM(require("picocolors"), 1);
|
|
|
62
62
|
var import_semver = __toESM(require("semver"), 1);
|
|
63
63
|
var import_dns = __toESM(require("dns"), 1);
|
|
64
64
|
var import_url = require("url");
|
|
65
|
+
|
|
66
|
+
// executable.ts
|
|
67
|
+
var resolveExecutable = (bin) => process.platform === "win32" ? `${bin}.cmd` : bin;
|
|
68
|
+
|
|
69
|
+
// helpers.ts
|
|
65
70
|
var shouldUseYarn = () => {
|
|
66
71
|
const { hasMinYarnPnp, hasMaxYarnPnp, yarnVersion } = checkYarnVersion();
|
|
67
72
|
if (!hasMinYarnPnp) {
|
|
@@ -98,6 +103,20 @@ var shouldUsePnpm = () => {
|
|
|
98
103
|
}
|
|
99
104
|
return true;
|
|
100
105
|
};
|
|
106
|
+
var shouldUseBun = () => {
|
|
107
|
+
const { hasMinBun, bunVersion } = checkBunVersion();
|
|
108
|
+
if (!hasMinBun) {
|
|
109
|
+
console.log(
|
|
110
|
+
import_picocolors.default.yellow(
|
|
111
|
+
`You are using bun version ${import_picocolors.default.bold(
|
|
112
|
+
bunVersion
|
|
113
|
+
)} which is not supported yet. To use bun, install v1.0.0 or higher. See https://bun.sh for instructions on how to install.`
|
|
114
|
+
)
|
|
115
|
+
);
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
return true;
|
|
119
|
+
};
|
|
101
120
|
var checkThatNpmCanReadCwd = () => {
|
|
102
121
|
const cwd = process.cwd();
|
|
103
122
|
let childOutput = null;
|
|
@@ -153,7 +172,7 @@ var checkPnpmVersion = () => {
|
|
|
153
172
|
let hasMinPnpm = false;
|
|
154
173
|
let pnpmVersion = null;
|
|
155
174
|
try {
|
|
156
|
-
pnpmVersion = (0, import_child_process.
|
|
175
|
+
pnpmVersion = (0, import_child_process.execFileSync)(resolveExecutable("pnpm"), ["--version"]).toString().trim();
|
|
157
176
|
if (import_semver.default.valid(pnpmVersion)) {
|
|
158
177
|
hasMinPnpm = import_semver.default.gte(pnpmVersion, minPnpm);
|
|
159
178
|
} else {
|
|
@@ -166,6 +185,19 @@ var checkPnpmVersion = () => {
|
|
|
166
185
|
}
|
|
167
186
|
return { hasMinPnpm, pnpmVersion };
|
|
168
187
|
};
|
|
188
|
+
var checkBunVersion = () => {
|
|
189
|
+
const minBun = "1.0.0";
|
|
190
|
+
let hasMinBun = false;
|
|
191
|
+
let bunVersion = null;
|
|
192
|
+
try {
|
|
193
|
+
bunVersion = (0, import_child_process.execFileSync)(resolveExecutable("bun"), ["--version"]).toString().trim();
|
|
194
|
+
if (import_semver.default.valid(bunVersion)) {
|
|
195
|
+
hasMinBun = import_semver.default.gte(bunVersion, minBun);
|
|
196
|
+
}
|
|
197
|
+
} catch {
|
|
198
|
+
}
|
|
199
|
+
return { hasMinBun, bunVersion };
|
|
200
|
+
};
|
|
169
201
|
var checkYarnVersion = () => {
|
|
170
202
|
const minYarnPnp = "1.12.0";
|
|
171
203
|
const maxYarnPnp = "2.0.0";
|
|
@@ -173,7 +205,7 @@ var checkYarnVersion = () => {
|
|
|
173
205
|
let hasMaxYarnPnp = false;
|
|
174
206
|
let yarnVersion = null;
|
|
175
207
|
try {
|
|
176
|
-
yarnVersion = (0, import_child_process.
|
|
208
|
+
yarnVersion = (0, import_child_process.execFileSync)(resolveExecutable("yarnpkg"), ["--version"]).toString().trim();
|
|
177
209
|
if (import_semver.default.valid(yarnVersion)) {
|
|
178
210
|
hasMinYarnPnp = import_semver.default.gte(yarnVersion, minYarnPnp);
|
|
179
211
|
hasMaxYarnPnp = import_semver.default.lt(yarnVersion, maxYarnPnp);
|
|
@@ -199,7 +231,7 @@ var checkNpmVersion = () => {
|
|
|
199
231
|
let hasMinNpm = false;
|
|
200
232
|
let npmVersion = null;
|
|
201
233
|
try {
|
|
202
|
-
npmVersion = (0, import_child_process.
|
|
234
|
+
npmVersion = (0, import_child_process.execFileSync)(resolveExecutable("npm"), ["--version"]).toString().trim();
|
|
203
235
|
hasMinNpm = import_semver.default.gte(npmVersion, "6.0.0");
|
|
204
236
|
} catch {
|
|
205
237
|
}
|
|
@@ -213,7 +245,11 @@ var getProxy = () => {
|
|
|
213
245
|
return process.env.HTTPS_PROXY;
|
|
214
246
|
}
|
|
215
247
|
try {
|
|
216
|
-
const httpsProxy = (0, import_child_process.
|
|
248
|
+
const httpsProxy = (0, import_child_process.execFileSync)(resolveExecutable("npm"), [
|
|
249
|
+
"config",
|
|
250
|
+
"get",
|
|
251
|
+
"https-proxy"
|
|
252
|
+
]).toString().trim();
|
|
217
253
|
return httpsProxy !== "null" ? httpsProxy : void 0;
|
|
218
254
|
} catch {
|
|
219
255
|
}
|
|
@@ -245,6 +281,7 @@ var import_lodash = __toESM(require("lodash.merge"), 1);
|
|
|
245
281
|
var import_fs2 = __toESM(require("fs"), 1);
|
|
246
282
|
var import_os2 = __toESM(require("os"), 1);
|
|
247
283
|
var import_path2 = __toESM(require("path"), 1);
|
|
284
|
+
var import_debug2 = __toESM(require("debug"), 1);
|
|
248
285
|
|
|
249
286
|
// git.ts
|
|
250
287
|
var import_os = __toESM(require("os"), 1);
|
|
@@ -254,6 +291,35 @@ var import_debug = __toESM(require("debug"), 1);
|
|
|
254
291
|
var import_simple_git = require("simple-git");
|
|
255
292
|
var fse = __toESM(require("fs-extra"), 1);
|
|
256
293
|
var log = (0, import_debug.default)("cna:git");
|
|
294
|
+
var formatRepositoryDownloadError = (error, url) => {
|
|
295
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
296
|
+
if (/not found|404|repository not found/i.test(message)) {
|
|
297
|
+
return [
|
|
298
|
+
`Error: Could not fetch template from '${url}'.`,
|
|
299
|
+
" \u2192 The URL returned HTTP 404 or the repository was not found. Please verify the URL is correct.",
|
|
300
|
+
" \u2192 Run 'npx create-awesome-node-app --list-templates' to see available templates."
|
|
301
|
+
].join("\n");
|
|
302
|
+
}
|
|
303
|
+
if (/403|authentication|permission denied|access denied/i.test(message)) {
|
|
304
|
+
return [
|
|
305
|
+
`Error: Could not fetch template from '${url}'.`,
|
|
306
|
+
" \u2192 Access denied (HTTP 403). Check that the repository is public or you have access.",
|
|
307
|
+
" \u2192 Run 'npx create-awesome-node-app --list-templates' to see available templates."
|
|
308
|
+
].join("\n");
|
|
309
|
+
}
|
|
310
|
+
if (/ECONNREFUSED|ENOTFOUND|ETIMEDOUT|network/i.test(message)) {
|
|
311
|
+
return [
|
|
312
|
+
`Error: Could not fetch template from '${url}'.`,
|
|
313
|
+
" \u2192 Could not reach the repository. Please check your internet connection.",
|
|
314
|
+
" \u2192 Run 'npx create-awesome-node-app --list-templates' to see available templates."
|
|
315
|
+
].join("\n");
|
|
316
|
+
}
|
|
317
|
+
return [
|
|
318
|
+
`Error: Could not fetch template from '${url}'.`,
|
|
319
|
+
` \u2192 ${message}`,
|
|
320
|
+
" \u2192 Run 'npx create-awesome-node-app --list-templates' to see available templates."
|
|
321
|
+
].join("\n");
|
|
322
|
+
};
|
|
257
323
|
var filterGit = (src) => {
|
|
258
324
|
return !/(\\|\/)\.git\b/.test(src);
|
|
259
325
|
};
|
|
@@ -268,6 +334,7 @@ var downloadRepository = async ({
|
|
|
268
334
|
cacheDir: optsCacheDir
|
|
269
335
|
}) => {
|
|
270
336
|
const absoluteTarget = import_path.default.isAbsolute(target) ? target : import_path.default.resolve(target);
|
|
337
|
+
const targetExistedBefore = import_fs.default.existsSync(absoluteTarget);
|
|
271
338
|
const isGithub = /^[^/]+\/[^/]+$/.test(url);
|
|
272
339
|
const gitUrl = isGithub ? `https://github.com/${url}` : url;
|
|
273
340
|
const id = targetId || Buffer.from(`${gitUrl}@${branch}`).toString("base64");
|
|
@@ -318,7 +385,15 @@ var downloadRepository = async ({
|
|
|
318
385
|
});
|
|
319
386
|
completedTargetIds.set(id, true);
|
|
320
387
|
} catch (error) {
|
|
321
|
-
|
|
388
|
+
if (!targetExistedBefore && import_fs.default.existsSync(absoluteTarget)) {
|
|
389
|
+
try {
|
|
390
|
+
fse.removeSync(absoluteTarget);
|
|
391
|
+
log("Cleaned up partially created directory: %s", absoluteTarget);
|
|
392
|
+
} catch (cleanupErr) {
|
|
393
|
+
log("Failed to clean up directory: %s", cleanupErr);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
throw new Error(formatRepositoryDownloadError(error, gitUrl));
|
|
322
397
|
} finally {
|
|
323
398
|
gitOperationMap.delete(id);
|
|
324
399
|
}
|
|
@@ -328,6 +403,8 @@ var downloadRepository = async ({
|
|
|
328
403
|
};
|
|
329
404
|
|
|
330
405
|
// paths.ts
|
|
406
|
+
var log2 = (0, import_debug2.default)("cna:paths");
|
|
407
|
+
var moduleDir = __dirname;
|
|
331
408
|
var solveValuesFromTemplateOrExtensionUrl = (templateOrExtension) => {
|
|
332
409
|
const url = new URL(templateOrExtension);
|
|
333
410
|
const ignorePackage = url.searchParams.get("ignorePackage") === "true";
|
|
@@ -381,30 +458,23 @@ var solveRepositoryPath = async ({
|
|
|
381
458
|
if (process.env.CNA_SKIP_GIT === "1") {
|
|
382
459
|
return { dir: target, subdir };
|
|
383
460
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
});
|
|
391
|
-
} catch {
|
|
392
|
-
}
|
|
461
|
+
await downloadRepository({
|
|
462
|
+
url,
|
|
463
|
+
branch: branch || "",
|
|
464
|
+
target,
|
|
465
|
+
targetId
|
|
466
|
+
});
|
|
393
467
|
return { dir: target, subdir };
|
|
394
468
|
};
|
|
395
469
|
var solveTemplateOrExtensionPath = async (templateOrExtension) => {
|
|
470
|
+
let parsed;
|
|
396
471
|
try {
|
|
397
|
-
|
|
398
|
-
if (protocol === "file:") {
|
|
399
|
-
const baseDir = pathname;
|
|
400
|
-
return { dir: baseDir, subdir, ignorePackage };
|
|
401
|
-
}
|
|
402
|
-
const gitData = await solveRepositoryPath({ url, branch, subdir });
|
|
403
|
-
return { dir: gitData.dir, subdir: gitData.subdir, ignorePackage };
|
|
472
|
+
parsed = solveValuesFromTemplateOrExtensionUrl(templateOrExtension);
|
|
404
473
|
} catch {
|
|
474
|
+
log2("Falling back to legacy template path for: %s", templateOrExtension);
|
|
405
475
|
return {
|
|
406
476
|
dir: import_path2.default.resolve(
|
|
407
|
-
|
|
477
|
+
moduleDir,
|
|
408
478
|
"..",
|
|
409
479
|
"templatesOrExtensions",
|
|
410
480
|
templateOrExtension
|
|
@@ -413,6 +483,12 @@ var solveTemplateOrExtensionPath = async (templateOrExtension) => {
|
|
|
413
483
|
ignorePackage: void 0
|
|
414
484
|
};
|
|
415
485
|
}
|
|
486
|
+
const { url, branch, subdir, protocol, pathname, ignorePackage } = parsed;
|
|
487
|
+
if (protocol === "file:") {
|
|
488
|
+
return { dir: pathname, subdir, ignorePackage };
|
|
489
|
+
}
|
|
490
|
+
const gitData = await solveRepositoryPath({ url, branch, subdir });
|
|
491
|
+
return { dir: gitData.dir, subdir: gitData.subdir, ignorePackage };
|
|
416
492
|
};
|
|
417
493
|
var getPackagePath = async (templateOrExtension, name = "package", ignorePackage = false) => {
|
|
418
494
|
const {
|
|
@@ -487,10 +563,10 @@ var loadPackages = async ({
|
|
|
487
563
|
const setup = await Promise.all(
|
|
488
564
|
templatesOrExtensions.map(async ({ url: templateOrExtension }) => {
|
|
489
565
|
try {
|
|
490
|
-
const
|
|
566
|
+
const template2 = requireIfExists(
|
|
491
567
|
await getPackagePath(templateOrExtension, "template.json")
|
|
492
568
|
);
|
|
493
|
-
return
|
|
569
|
+
return template2.package || {};
|
|
494
570
|
} catch {
|
|
495
571
|
return {};
|
|
496
572
|
}
|
|
@@ -543,12 +619,13 @@ var loadPackages = async ({
|
|
|
543
619
|
};
|
|
544
620
|
|
|
545
621
|
// loaders.ts
|
|
546
|
-
var import_underscore = __toESM(require("underscore"), 1);
|
|
547
622
|
var import_fs4 = __toESM(require("fs"), 1);
|
|
548
623
|
var import_picocolors2 = __toESM(require("picocolors"), 1);
|
|
549
624
|
var import_readdirp = require("readdirp");
|
|
550
625
|
var import_path3 = require("path");
|
|
551
626
|
var import_util = require("util");
|
|
627
|
+
var import_lodash2 = __toESM(require("lodash"), 1);
|
|
628
|
+
var { template } = import_lodash2.default;
|
|
552
629
|
var writeFileAsync = (0, import_util.promisify)(import_fs4.default.writeFile);
|
|
553
630
|
var copyFileAsync = (0, import_util.promisify)(import_fs4.default.copyFile);
|
|
554
631
|
var SRC_PATH_PATTERN = "[src]/";
|
|
@@ -577,6 +654,11 @@ var batchedCopyFiles = async (operations) => {
|
|
|
577
654
|
try {
|
|
578
655
|
makeDirectory((0, import_path3.dirname)(operation.dest));
|
|
579
656
|
await copyFileAsync(operation.src, operation.dest);
|
|
657
|
+
try {
|
|
658
|
+
const srcStat = await (0, import_util.promisify)(import_fs4.default.stat)(operation.src);
|
|
659
|
+
await (0, import_util.promisify)(import_fs4.default.chmod)(operation.dest, srcStat.mode);
|
|
660
|
+
} catch {
|
|
661
|
+
}
|
|
580
662
|
if (operation.verbose) {
|
|
581
663
|
console.log(
|
|
582
664
|
import_picocolors2.default.green(
|
|
@@ -646,7 +728,7 @@ var batchedAppendFiles = async (operations) => {
|
|
|
646
728
|
var copyLoader = ({ root, templateDir, verbose, srcDir }) => async ({ path: path5 }) => {
|
|
647
729
|
const operations = [];
|
|
648
730
|
try {
|
|
649
|
-
const newPath = path5.replace(/.if-(npm|yarn|pnpm)$/, "").replace(SRC_PATH_PATTERN, getSrcDirPattern(srcDir));
|
|
731
|
+
const newPath = path5.replace(/.if-(npm|yarn|pnpm|bun)$/, "").replace(SRC_PATH_PATTERN, getSrcDirPattern(srcDir));
|
|
650
732
|
operations.push({
|
|
651
733
|
src: `${templateDir}/${path5}`,
|
|
652
734
|
dest: `${root}/${newPath}`,
|
|
@@ -663,7 +745,7 @@ var copyLoader = ({ root, templateDir, verbose, srcDir }) => async ({ path: path
|
|
|
663
745
|
var appendLoader = ({ root, templateDir, verbose, srcDir }) => async ({ path: path5 }) => {
|
|
664
746
|
const operations = [];
|
|
665
747
|
try {
|
|
666
|
-
const newPath = path5.replace(/.append$/, "").replace(/.if-(npm|yarn|pnpm)$/, "").replace(SRC_PATH_PATTERN, getSrcDirPattern(srcDir));
|
|
748
|
+
const newPath = path5.replace(/.append$/, "").replace(/.if-(npm|yarn|pnpm|bun)$/, "").replace(SRC_PATH_PATTERN, getSrcDirPattern(srcDir));
|
|
667
749
|
operations.push({
|
|
668
750
|
src: `${templateDir}/${path5}`,
|
|
669
751
|
dest: `${root}/${newPath}`,
|
|
@@ -694,8 +776,8 @@ var templateLoader = ({
|
|
|
694
776
|
const filePath = `${templateDir}/${path5}`;
|
|
695
777
|
const file = await (0, import_util.promisify)(import_fs4.default.readFile)(filePath, "utf8");
|
|
696
778
|
const fileMode = (await (0, import_util.promisify)(import_fs4.default.stat)(filePath)).mode;
|
|
697
|
-
const newFile =
|
|
698
|
-
const newPath = path5.replace(/.template$/, "").replace(/.append$/, "").replace(/.if-(npm|yarn|pnpm)$/, "").replace(SRC_PATH_PATTERN, getSrcDirPattern(srcDir));
|
|
779
|
+
const newFile = template(file);
|
|
780
|
+
const newPath = path5.replace(/.template$/, "").replace(/.append$/, "").replace(/.if-(npm|yarn|pnpm|bun)$/, "").replace(SRC_PATH_PATTERN, getSrcDirPattern(srcDir));
|
|
699
781
|
operations.push({
|
|
700
782
|
path: `${root}/${newPath}`,
|
|
701
783
|
content: newFile({
|
|
@@ -725,6 +807,7 @@ var fileLoader = ({
|
|
|
725
807
|
verbose,
|
|
726
808
|
useYarn,
|
|
727
809
|
usePnpm,
|
|
810
|
+
useBun,
|
|
728
811
|
srcDir = DEFAULT_SRC_PATH,
|
|
729
812
|
runCommand,
|
|
730
813
|
installCommand,
|
|
@@ -747,6 +830,7 @@ var fileLoader = ({
|
|
|
747
830
|
verbose,
|
|
748
831
|
useYarn: !!useYarn,
|
|
749
832
|
usePnpm: !!usePnpm,
|
|
833
|
+
useBun: !!useBun,
|
|
750
834
|
mode,
|
|
751
835
|
srcDir,
|
|
752
836
|
runCommand,
|
|
@@ -770,6 +854,7 @@ var loadFiles = async ({
|
|
|
770
854
|
verbose,
|
|
771
855
|
useYarn = false,
|
|
772
856
|
usePnpm = false,
|
|
857
|
+
useBun = false,
|
|
773
858
|
srcDir = DEFAULT_SRC_PATH,
|
|
774
859
|
runCommand,
|
|
775
860
|
installCommand,
|
|
@@ -800,7 +885,7 @@ var loadFiles = async ({
|
|
|
800
885
|
/\byarn\.lock$/,
|
|
801
886
|
/\bpnpm-lock\.yaml$/
|
|
802
887
|
];
|
|
803
|
-
const skipManager = usePnpm ? [/\.if-npm\./, /\.if-yarn\./] : useYarn ? [/\.if-npm\./, /\.if-pnpm\./] : [/\.if-yarn\./, /\.if-pnpm\./];
|
|
888
|
+
const skipManager = usePnpm ? [/\.if-npm\./, /\.if-yarn\./, /\.if-bun\./] : useYarn ? [/\.if-npm\./, /\.if-pnpm\./, /\.if-bun\./] : useBun ? [/\.if-yarn\./, /\.if-pnpm\./] : [/\.if-yarn\./, /\.if-pnpm\./, /\.if-bun\./];
|
|
804
889
|
const shouldSkip = (p) => [...skipGlobs, ...skipManager].some((rgx) => rgx.test(p));
|
|
805
890
|
for await (const entry of (0, import_readdirp.readdirp)(templateDir, {
|
|
806
891
|
type: "files",
|
|
@@ -820,6 +905,7 @@ var loadFiles = async ({
|
|
|
820
905
|
verbose,
|
|
821
906
|
useYarn,
|
|
822
907
|
usePnpm,
|
|
908
|
+
useBun,
|
|
823
909
|
srcDir,
|
|
824
910
|
runCommand,
|
|
825
911
|
installCommand,
|
|
@@ -855,7 +941,8 @@ var loadFiles = async ({
|
|
|
855
941
|
};
|
|
856
942
|
|
|
857
943
|
// installer.ts
|
|
858
|
-
var
|
|
944
|
+
var { isEmpty } = import_lodash3.default;
|
|
945
|
+
var install = async (root, useYarn = false, usePnpm = false, useBun = false, dependencies = [], verbose = false, isOnline = true, isDevDependencies = false) => {
|
|
859
946
|
let command;
|
|
860
947
|
let args;
|
|
861
948
|
if (useYarn) {
|
|
@@ -884,6 +971,17 @@ var install = async (root, useYarn = false, usePnpm = false, dependencies = [],
|
|
|
884
971
|
args.push("--save");
|
|
885
972
|
}
|
|
886
973
|
args.push(...dependencies);
|
|
974
|
+
} else if (useBun) {
|
|
975
|
+
command = "bun";
|
|
976
|
+
if (dependencies.length > 0) {
|
|
977
|
+
args = ["add"];
|
|
978
|
+
if (isDevDependencies) {
|
|
979
|
+
args.push("--dev");
|
|
980
|
+
}
|
|
981
|
+
args.push(...dependencies);
|
|
982
|
+
} else {
|
|
983
|
+
args = ["install"];
|
|
984
|
+
}
|
|
887
985
|
} else {
|
|
888
986
|
command = "npm";
|
|
889
987
|
args = ["install", "--loglevel", "error"];
|
|
@@ -898,7 +996,7 @@ var install = async (root, useYarn = false, usePnpm = false, dependencies = [],
|
|
|
898
996
|
args.push("--verbose");
|
|
899
997
|
}
|
|
900
998
|
try {
|
|
901
|
-
(0, import_child_process2.
|
|
999
|
+
(0, import_child_process2.execFileSync)(resolveExecutable(command), args, {
|
|
902
1000
|
cwd: root,
|
|
903
1001
|
stdio: "inherit"
|
|
904
1002
|
});
|
|
@@ -907,8 +1005,9 @@ var install = async (root, useYarn = false, usePnpm = false, dependencies = [],
|
|
|
907
1005
|
}
|
|
908
1006
|
};
|
|
909
1007
|
var runCommandInProjectDir = async (root, command, args = [], successMessage = "Operation completed successfully.", errorMessage = "Operation failed.") => {
|
|
1008
|
+
const [executable, ...baseArgs] = command === "npm run" ? ["npm", "run"] : command === "pnpm run" ? ["pnpm", "run"] : command === "bun run" ? ["bun", "run"] : [command];
|
|
910
1009
|
try {
|
|
911
|
-
(0, import_child_process2.
|
|
1010
|
+
(0, import_child_process2.execFileSync)(resolveExecutable(executable), [...baseArgs, ...args], {
|
|
912
1011
|
cwd: root,
|
|
913
1012
|
stdio: "ignore"
|
|
914
1013
|
});
|
|
@@ -936,6 +1035,7 @@ var run = async ({
|
|
|
936
1035
|
verbose = false,
|
|
937
1036
|
useYarn = false,
|
|
938
1037
|
usePnpm = false,
|
|
1038
|
+
useBun = false,
|
|
939
1039
|
templatesOrExtensions = [],
|
|
940
1040
|
dependencies = [],
|
|
941
1041
|
devDependencies = [],
|
|
@@ -945,7 +1045,7 @@ var run = async ({
|
|
|
945
1045
|
...customOptions
|
|
946
1046
|
}) => {
|
|
947
1047
|
const isOnline = useYarn ? await checkIfOnline(useYarn) : true;
|
|
948
|
-
if (
|
|
1048
|
+
if (isEmpty(templatesOrExtensions)) {
|
|
949
1049
|
console.log();
|
|
950
1050
|
console.log(
|
|
951
1051
|
import_picocolors3.default.yellow(
|
|
@@ -965,6 +1065,7 @@ var run = async ({
|
|
|
965
1065
|
verbose,
|
|
966
1066
|
useYarn,
|
|
967
1067
|
usePnpm,
|
|
1068
|
+
useBun,
|
|
968
1069
|
runCommand,
|
|
969
1070
|
installCommand,
|
|
970
1071
|
...customOptions
|
|
@@ -982,6 +1083,7 @@ var run = async ({
|
|
|
982
1083
|
root,
|
|
983
1084
|
useYarn,
|
|
984
1085
|
usePnpm,
|
|
1086
|
+
useBun,
|
|
985
1087
|
dependencies,
|
|
986
1088
|
verbose,
|
|
987
1089
|
isOnline,
|
|
@@ -995,6 +1097,7 @@ var run = async ({
|
|
|
995
1097
|
root,
|
|
996
1098
|
useYarn,
|
|
997
1099
|
usePnpm,
|
|
1100
|
+
useBun,
|
|
998
1101
|
devDependencies,
|
|
999
1102
|
verbose,
|
|
1000
1103
|
isOnline,
|
|
@@ -1119,13 +1222,15 @@ var createApp = async ({
|
|
|
1119
1222
|
console.log();
|
|
1120
1223
|
const useYarn = customOptions.packageManager === "yarn" && shouldUseYarn();
|
|
1121
1224
|
const usePnpm = customOptions.packageManager === "pnpm" && shouldUsePnpm();
|
|
1122
|
-
const
|
|
1123
|
-
const
|
|
1225
|
+
const useBun = customOptions.packageManager === "bun" && shouldUseBun();
|
|
1226
|
+
const runCommand = useYarn ? "yarn" : usePnpm ? "pnpm run" : useBun ? "bun run" : "npm run";
|
|
1227
|
+
const installCommand = useYarn ? "yarn" : usePnpm ? "pnpm install" : useBun ? "bun install" : "npm install";
|
|
1124
1228
|
const { packageJson, dependencies, devDependencies } = await loadPackages({
|
|
1125
1229
|
templatesOrExtensions,
|
|
1126
1230
|
appName,
|
|
1127
1231
|
usePnpm,
|
|
1128
1232
|
useYarn,
|
|
1233
|
+
useBun,
|
|
1129
1234
|
runCommand,
|
|
1130
1235
|
ignorePackage
|
|
1131
1236
|
});
|
|
@@ -1135,7 +1240,7 @@ var createApp = async ({
|
|
|
1135
1240
|
);
|
|
1136
1241
|
const originalDirectory = process.cwd();
|
|
1137
1242
|
process.chdir(root);
|
|
1138
|
-
if (!useYarn && !checkThatNpmCanReadCwd()) {
|
|
1243
|
+
if (!useYarn && !useBun && !checkThatNpmCanReadCwd()) {
|
|
1139
1244
|
process.exit(1);
|
|
1140
1245
|
}
|
|
1141
1246
|
if (!import_semver2.default.satisfies(process.version, ">=18.0.0")) {
|
|
@@ -1148,7 +1253,7 @@ Please update to Node 18 or higher for a better, fully supported experience.
|
|
|
1148
1253
|
)
|
|
1149
1254
|
);
|
|
1150
1255
|
}
|
|
1151
|
-
if (!useYarn) {
|
|
1256
|
+
if (!useYarn && !useBun) {
|
|
1152
1257
|
const npmInfo = checkNpmVersion();
|
|
1153
1258
|
if (!npmInfo.hasMinNpm) {
|
|
1154
1259
|
if (npmInfo.npmVersion) {
|
|
@@ -1166,7 +1271,11 @@ Please update to npm 3 or higher for a better, fully supported experience.
|
|
|
1166
1271
|
if (useYarn) {
|
|
1167
1272
|
let yarnUsesDefaultRegistry = true;
|
|
1168
1273
|
try {
|
|
1169
|
-
yarnUsesDefaultRegistry = (0, import_child_process2.
|
|
1274
|
+
yarnUsesDefaultRegistry = (0, import_child_process2.execFileSync)(resolveExecutable("yarnpkg"), [
|
|
1275
|
+
"config",
|
|
1276
|
+
"get",
|
|
1277
|
+
"registry"
|
|
1278
|
+
]).toString().trim() === "https://registry.yarnpkg.com";
|
|
1170
1279
|
} catch {
|
|
1171
1280
|
}
|
|
1172
1281
|
if (false) {
|
|
@@ -1184,6 +1293,7 @@ Please update to npm 3 or higher for a better, fully supported experience.
|
|
|
1184
1293
|
verbose,
|
|
1185
1294
|
useYarn,
|
|
1186
1295
|
usePnpm,
|
|
1296
|
+
useBun,
|
|
1187
1297
|
templatesOrExtensions,
|
|
1188
1298
|
dependencies,
|
|
1189
1299
|
devDependencies,
|
|
@@ -1238,7 +1348,11 @@ var checkForLatestVersion = async (packageName) => {
|
|
|
1238
1348
|
return null;
|
|
1239
1349
|
} catch {
|
|
1240
1350
|
try {
|
|
1241
|
-
return (0, import_child_process3.
|
|
1351
|
+
return (0, import_child_process3.execFileSync)(resolveExecutable("npm"), [
|
|
1352
|
+
"view",
|
|
1353
|
+
packageName,
|
|
1354
|
+
"version"
|
|
1355
|
+
]).toString().trim();
|
|
1242
1356
|
} catch {
|
|
1243
1357
|
}
|
|
1244
1358
|
}
|
|
@@ -1249,7 +1363,7 @@ var printEnvInfo = async () => {
|
|
|
1249
1363
|
const info = await import_envinfo.default.run(
|
|
1250
1364
|
{
|
|
1251
1365
|
System: ["OS", "CPU", "Memory", "Shell"],
|
|
1252
|
-
Binaries: ["Node", "npm", "pnpm", "Yarn", "Watchman"],
|
|
1366
|
+
Binaries: ["Node", "npm", "pnpm", "Yarn", "Bun", "Watchman"],
|
|
1253
1367
|
Browsers: ["Chrome", "Edge", "Internet Explorer", "Firefox", "Safari"]
|
|
1254
1368
|
},
|
|
1255
1369
|
{
|