@rshono/create 1.0.0-rc.1 → 1.0.0-rc.10
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 +82 -59
- package/bin/create-rshono.mjs +5 -3
- package/dist/api.mjs +122 -137
- package/dist/cli.mjs +195 -232
- package/package.json +11 -12
- package/templates/base/AGENTS.md +5 -0
- package/templates/base/CLAUDE.md +1 -0
- package/templates/base/README.md +6 -10
- package/templates/base/_env +2 -5
- package/templates/base/public/favicon.svg +2 -1
- package/templates/base/rshono.config.ts +1 -31
- package/templates/base/src/components/404.tsx +0 -1
- package/templates/base/src/components/500.tsx +0 -6
- package/templates/base/src/components/home.tsx +6 -23
- package/templates/base/src/components/layout.tsx +4 -11
- package/templates/base/src/routes.ts +1 -26
- package/templates/base/src/server.ts +20 -35
- package/templates/base/src/styles.css +1 -64
- package/templates/biome/biome.json +2 -1
- package/templates/biome-tailwind/biome.json +1 -1
- package/templates/eslint/eslint.config.mjs +0 -15
- package/templates/oxfmt/_oxfmtrc.json +1 -1
- package/templates/oxlint/_oxlintrc.json +1 -1
- package/templates/prettier/_prettierignore +6 -1
- package/templates/tailwind/postcss.config.mjs +0 -4
- package/templates/tailwind/rshono.config.ts +2 -38
- package/templates/tailwind/src/components/home.tsx +6 -23
- package/templates/tailwind/src/components/layout.tsx +4 -11
- package/templates/tailwind/src/styles.css +0 -25
- package/templates/base/src/actions.ts +0 -22
- package/templates/base/src/components/greet-form.tsx +0 -27
- package/templates/base/src/lib/env.ts +0 -26
package/dist/api.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {fileURLToPath as __rspack_fileURLToPath} from "node:url";
|
|
3
3
|
import {dirname as __rspack_dirname} from "node:path";
|
|
4
4
|
var __rspack_import_meta_dirname__ = __rspack_dirname(__rspack_fileURLToPath(import.meta.url));
|
|
5
|
-
import {
|
|
5
|
+
import { mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
6
6
|
import { dirname, join, posix, sep } from "node:path";
|
|
7
7
|
import "node:child_process";
|
|
8
8
|
// The require scope
|
|
@@ -32,16 +32,16 @@ var __webpack_exports__ = {};
|
|
|
32
32
|
__webpack_require__.d(__webpack_exports__, {
|
|
33
33
|
bp: () => (/* reexport */ DEPLOY_TARGET_NAMES),
|
|
34
34
|
ml: () => (/* reexport */ (/* inlined export .ESLINT_TYPESCRIPT */"~6.0.3")),
|
|
35
|
+
wC: () => (/* reexport */ FORMATTER_NAMES),
|
|
35
36
|
e7: () => (/* reexport */ FRAMEWORK_DEPS),
|
|
37
|
+
At: () => (/* reexport */ LINTER_NAMES),
|
|
36
38
|
Ab: () => (/* reexport */ PACKAGE_MANAGERS),
|
|
37
39
|
pm: () => (/* reexport */ QUALITY_PRESETS),
|
|
38
40
|
s_: () => (/* reexport */ RSHONO_RANGE),
|
|
39
41
|
RM: () => (/* reexport */ TOOL_VERSIONS),
|
|
40
|
-
|
|
42
|
+
dh: () => (/* reexport */ conflictingEntries),
|
|
41
43
|
P8: () => (/* reexport */ deployHint),
|
|
42
44
|
Lv: () => (/* reexport */ detectPackageManager),
|
|
43
|
-
WL: () => (/* reexport */ inspectTarget),
|
|
44
|
-
p1: () => (/* reexport */ isDeployTarget),
|
|
45
45
|
eW: () => (/* reexport */ isValidPackageName),
|
|
46
46
|
VZ: () => (/* reexport */ packageManager),
|
|
47
47
|
et: () => (/* reexport */ plan_plan),
|
|
@@ -79,7 +79,11 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
79
79
|
|
|
80
80
|
;// CONCATENATED MODULE: ./src/generated/framework.ts
|
|
81
81
|
// GENERATED by scripts/codegen.mjs from packages/core — do not edit. Run `pnpm --filter @rshono/create codegen`.
|
|
82
|
-
/** The framework release a scaffolded app is pinned to: this package and rshono ship together. */ const RSHONO_VERSION = '1.0.0-rc.
|
|
82
|
+
/** The framework release a scaffolded app is pinned to: this package and rshono ship together. */ const RSHONO_VERSION = '1.0.0-rc.10';
|
|
83
|
+
/**
|
|
84
|
+
* The Node range rshono itself declares, restated in every scaffolded app's `engines` — so a CI image
|
|
85
|
+
* or a contributor on an older Node hears it from their package manager rather than from a stack trace.
|
|
86
|
+
*/ const NODE_ENGINE = '>=22.18.0';
|
|
83
87
|
/**
|
|
84
88
|
* The dependency versions rshono is tested against, copied from its own manifest. Exact where it is
|
|
85
89
|
* exact — React's RSC internals are coupled across builds, and a generated app has no workspace
|
|
@@ -101,22 +105,10 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
101
105
|
name: 'cloudflare',
|
|
102
106
|
hint: 'deploy with `wrangler deploy`'
|
|
103
107
|
},
|
|
104
|
-
{
|
|
105
|
-
name: 'bun',
|
|
106
|
-
hint: 'run `bun dist/server/main.mjs`'
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
name: 'deno',
|
|
110
|
-
hint: 'run `deno serve -A dist/server/main.mjs`'
|
|
111
|
-
},
|
|
112
108
|
{
|
|
113
109
|
name: 'vercel',
|
|
114
110
|
hint: 'deploy with `vercel deploy --prebuilt`'
|
|
115
111
|
},
|
|
116
|
-
{
|
|
117
|
-
name: 'netlify',
|
|
118
|
-
hint: 'deploy with `netlify deploy --build=false --dir=.netlify/publish`'
|
|
119
|
-
},
|
|
120
112
|
{
|
|
121
113
|
name: 'aws-lambda',
|
|
122
114
|
hint: 'zip dist/ with the handler at dist/server/main.mjs'
|
|
@@ -125,7 +117,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
125
117
|
|
|
126
118
|
;// CONCATENATED MODULE: ./src/versions.ts
|
|
127
119
|
|
|
128
|
-
|
|
120
|
+
/** Passed straight through, so everything generated from the framework reaches the rest of the package here. */
|
|
129
121
|
/** The framework range a scaffolded app gets. The two packages are released together, so this is ours. */ const RSHONO_RANGE = `^${RSHONO_VERSION}`;
|
|
130
122
|
/**
|
|
131
123
|
* Versions for the optional tooling the features can add — the one place in this package where a
|
|
@@ -156,12 +148,11 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
156
148
|
};
|
|
157
149
|
/**
|
|
158
150
|
* The TypeScript an ESLint app pins, in place of the framework's own — the one deliberate exception to
|
|
159
|
-
* {@link FRAMEWORK_DEPS}
|
|
151
|
+
* {@link FRAMEWORK_DEPS}.
|
|
160
152
|
*
|
|
161
|
-
* typescript-eslint reads TypeScript's compiler API directly rather than through a stable interface,
|
|
162
|
-
* it accepts `typescript >=4.8.4 <6.1.0` and nothing above
|
|
163
|
-
*
|
|
164
|
-
* rshono's declarations compile the same under either, which is what makes this pin an app's business
|
|
153
|
+
* typescript-eslint reads TypeScript's compiler API directly rather than through a stable interface,
|
|
154
|
+
* so it accepts `typescript >=4.8.4 <6.1.0` and nothing above; `~6.0.3` is the newest that satisfies
|
|
155
|
+
* it. rshono's declarations compile the same under either, which is what makes this an app's business
|
|
165
156
|
* and not the framework's.
|
|
166
157
|
*
|
|
167
158
|
* When upstream widens the range, this constant and the ESLint feature's use of it are what to delete.
|
|
@@ -170,14 +161,13 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
170
161
|
;// CONCATENATED MODULE: ./src/features/deploy.ts
|
|
171
162
|
|
|
172
163
|
/**
|
|
173
|
-
* What a deploy target adds beyond the `deploy` line in `rshono.config.ts
|
|
174
|
-
* to read, and the template's to carry.
|
|
164
|
+
* What a deploy target adds beyond the `deploy` line in `rshono.config.ts`, which the template carries.
|
|
175
165
|
*
|
|
176
|
-
* Deliberately thin
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
* the
|
|
166
|
+
* Deliberately thin: the framework arranges its own output for every platform, and `rshono build`
|
|
167
|
+
* writes the one platform config that has to exist (`wrangler.jsonc`, dated the day it ran) if the
|
|
168
|
+
* project has none — a second copy generated here would only go stale. So a target contributes the
|
|
169
|
+
* command that ships the build, the CLI that command needs, the directories to gitignore, and a note
|
|
170
|
+
* for the step no command covers. Several contribute just one of those.
|
|
181
171
|
*/ const DEPLOY_FEATURES = {
|
|
182
172
|
// Where a Node build goes from here is a Dockerfile or a process manager, neither of which this can
|
|
183
173
|
// guess — so the target contributes only the command that runs what was built.
|
|
@@ -187,28 +177,16 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
187
177
|
start: 'rshono start'
|
|
188
178
|
}
|
|
189
179
|
},
|
|
190
|
-
// `rshono start` is the Node target's launcher and refuses a build made for another platform, so
|
|
191
|
-
// these two get the command their own runtime uses under the same script name.
|
|
192
|
-
bun: {
|
|
193
|
-
id: 'deploy-bun',
|
|
194
|
-
scripts: {
|
|
195
|
-
start: 'bun dist/server/main.mjs'
|
|
196
|
-
}
|
|
197
|
-
},
|
|
198
|
-
deno: {
|
|
199
|
-
id: 'deploy-deno',
|
|
200
|
-
scripts: {
|
|
201
|
-
start: 'deno serve -A dist/server/main.mjs'
|
|
202
|
-
}
|
|
203
|
-
},
|
|
204
180
|
cloudflare: {
|
|
205
181
|
id: 'deploy-cloudflare',
|
|
206
182
|
devDependencies: {
|
|
207
183
|
wrangler: TOOL_VERSIONS.wrangler
|
|
208
184
|
},
|
|
209
|
-
//
|
|
210
|
-
//
|
|
185
|
+
// The only two install scripts a scaffolded app can end up with, and wrangler brings both. Each
|
|
186
|
+
// one merely picks the platform binary out of the optional dependency that already carries it, so
|
|
187
|
+
// neither needs to run — `workerd --version` and `esbuild --version` both answer without it.
|
|
211
188
|
allowBuilds: {
|
|
189
|
+
esbuild: false,
|
|
212
190
|
workerd: false
|
|
213
191
|
},
|
|
214
192
|
scripts: {
|
|
@@ -233,15 +211,6 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
233
211
|
'--prebuilt uploads what rshono build assembled; the platform must not rebuild it.'
|
|
234
212
|
]
|
|
235
213
|
},
|
|
236
|
-
netlify: {
|
|
237
|
-
id: 'deploy-netlify',
|
|
238
|
-
scripts: {
|
|
239
|
-
deploy: 'rshono build && netlify deploy --build=false --dir=.netlify/publish'
|
|
240
|
-
},
|
|
241
|
-
gitignore: [
|
|
242
|
-
'.netlify/'
|
|
243
|
-
]
|
|
244
|
-
},
|
|
245
214
|
'aws-lambda': {
|
|
246
215
|
id: 'deploy-aws-lambda',
|
|
247
216
|
notes: [
|
|
@@ -260,8 +229,10 @@ function deployFeature(target) {
|
|
|
260
229
|
* deduplicates by `id`, so `formatter: 'biome', linter: 'biome'` contributes one set of files, one
|
|
261
230
|
* dependency and one pair of scripts.
|
|
262
231
|
*
|
|
263
|
-
*
|
|
264
|
-
*
|
|
232
|
+
* A formatter brings `format:check` beside `format`, because the writing half and the CI half want
|
|
233
|
+
* different exit-code behaviour: `format` rewrites files, `format:check` fails instead. A linter brings
|
|
234
|
+
* `lint:fix` beside `lint`, for the same reason in the other direction — `lint` is already the failing
|
|
235
|
+
* one. Biome adds a `check` of its own, which is the pair of them in a single pass.
|
|
265
236
|
*/ const PRETTIER = {
|
|
266
237
|
id: 'prettier',
|
|
267
238
|
overlays: [
|
|
@@ -302,12 +273,11 @@ const OXLINT = {
|
|
|
302
273
|
}
|
|
303
274
|
};
|
|
304
275
|
/**
|
|
305
|
-
* The one feature that changes a dependency the framework otherwise decides: typescript-eslint cannot
|
|
306
|
-
* installed alongside the TypeScript rshono is tested against, so an ESLint app pins the newest one
|
|
307
|
-
* peer range accepts (see {@link ESLINT_TYPESCRIPT}).
|
|
308
|
-
*
|
|
309
|
-
*
|
|
310
|
-
* so the config it ships hands the whole program to the parser rather than linting file by file.
|
|
276
|
+
* The one feature that changes a dependency the framework otherwise decides: typescript-eslint cannot
|
|
277
|
+
* be installed alongside the TypeScript rshono is tested against, so an ESLint app pins the newest one
|
|
278
|
+
* its peer range accepts (see {@link ESLINT_TYPESCRIPT}). Its rules are type-aware — the reason to
|
|
279
|
+
* reach for ESLint over a syntax-only linter — so the config it ships hands the parser the whole
|
|
280
|
+
* program rather than linting file by file.
|
|
311
281
|
*/ const ESLINT = {
|
|
312
282
|
id: 'eslint',
|
|
313
283
|
overlays: [
|
|
@@ -363,14 +333,13 @@ function linterFeature(linter) {
|
|
|
363
333
|
;// CONCATENATED MODULE: ./src/features/styling.ts
|
|
364
334
|
|
|
365
335
|
/**
|
|
366
|
-
* Tailwind is a PostCSS plugin and nothing more, which is the whole of this feature: four packages,
|
|
367
|
-
* an overlay carrying
|
|
368
|
-
*
|
|
369
|
-
*
|
|
336
|
+
* Tailwind is a PostCSS plugin and nothing more, which is the whole of this feature: four packages,
|
|
337
|
+
* plus an overlay carrying `postcss.config.mjs`, an `rshono.config.ts` whose `rspack` hook puts
|
|
338
|
+
* postcss-loader in front of the CSS parser, a Tailwind entry stylesheet, and the two views rewritten
|
|
339
|
+
* in utilities.
|
|
370
340
|
*
|
|
371
341
|
* `postcss` and `postcss-loader` are the app's dependencies rather than the framework's — rshono
|
|
372
|
-
* compiles CSS natively
|
|
373
|
-
* install one.
|
|
342
|
+
* compiles CSS natively, so an app that does not want a plugin chain does not install one.
|
|
374
343
|
*/ const TAILWIND = {
|
|
375
344
|
id: 'tailwind',
|
|
376
345
|
overlays: [
|
|
@@ -416,6 +385,22 @@ function stylingFeature(styling) {
|
|
|
416
385
|
|
|
417
386
|
;// CONCATENATED MODULE: ./src/options.ts
|
|
418
387
|
|
|
388
|
+
/*
|
|
389
|
+
* The names each option accepts, spelled once. The types below are derived from them, the CLI validates
|
|
390
|
+
* its flags against them and prints them in `--help`, and `pm.ts` recognises a package manager by them
|
|
391
|
+
* — so a name added here reaches all three without a second list to remember.
|
|
392
|
+
*/ const FORMATTER_NAMES = [
|
|
393
|
+
'prettier',
|
|
394
|
+
'biome',
|
|
395
|
+
'oxfmt',
|
|
396
|
+
'none'
|
|
397
|
+
];
|
|
398
|
+
const LINTER_NAMES = [
|
|
399
|
+
'oxlint',
|
|
400
|
+
'eslint',
|
|
401
|
+
'biome',
|
|
402
|
+
'none'
|
|
403
|
+
];
|
|
419
404
|
const PACKAGE_MANAGERS = [
|
|
420
405
|
'npm',
|
|
421
406
|
'pnpm',
|
|
@@ -426,9 +411,6 @@ const DEPLOY_TARGET_NAMES = DEPLOY_TARGETS.map((target)=>target.name);
|
|
|
426
411
|
function deployHint(name) {
|
|
427
412
|
return DEPLOY_TARGETS.find((target)=>target.name === name)?.hint ?? '';
|
|
428
413
|
}
|
|
429
|
-
function isDeployTarget(value) {
|
|
430
|
-
return DEPLOY_TARGET_NAMES.includes(value);
|
|
431
|
-
}
|
|
432
414
|
const QUALITY_PRESETS = [
|
|
433
415
|
{
|
|
434
416
|
id: 'prettier-oxlint',
|
|
@@ -486,11 +468,16 @@ const QUALITY_PRESETS = [
|
|
|
486
468
|
return /^(?:@[a-z\d\-*~][a-z\d\-*._~]*\/)?[a-z\d\-~][a-z\d\-._~]*$/.test(name) && name.length <= 214;
|
|
487
469
|
}
|
|
488
470
|
|
|
471
|
+
;// CONCATENATED MODULE: external "node:fs"
|
|
472
|
+
|
|
473
|
+
;// CONCATENATED MODULE: external "node:path"
|
|
474
|
+
|
|
489
475
|
;// CONCATENATED MODULE: ./src/pkg.ts
|
|
490
476
|
|
|
491
477
|
/**
|
|
492
|
-
* The scripts every app gets. `start` is not among them
|
|
493
|
-
*
|
|
478
|
+
* The scripts every app gets. `start` is not among them, because it means something different per
|
|
479
|
+
* platform: `node` is the one target that runs the build itself, so it contributes its own, and a
|
|
480
|
+
* platform target contributes a `deploy` instead, where its platform has one command to give.
|
|
494
481
|
*/ const BASE_SCRIPTS = {
|
|
495
482
|
dev: 'rshono dev',
|
|
496
483
|
build: 'rshono build',
|
|
@@ -511,35 +498,26 @@ function sorted(record) {
|
|
|
511
498
|
return Object.fromEntries(Object.entries(record).sort(([a], [b])=>a < b ? -1 : 1));
|
|
512
499
|
}
|
|
513
500
|
/**
|
|
514
|
-
*
|
|
515
|
-
*
|
|
516
|
-
* the optional dependency that already carries it — rshono's own repo denies it for the same reason.
|
|
517
|
-
*/ const BASE_ALLOW_BUILDS = {
|
|
518
|
-
esbuild: false
|
|
519
|
-
};
|
|
520
|
-
/**
|
|
521
|
-
* pnpm's settings for the new app — written for pnpm and for nobody else.
|
|
501
|
+
* pnpm's settings for the new app, written only when a feature has something to put in them. `null`
|
|
502
|
+
* means there is nothing to say, so no file is written.
|
|
522
503
|
*
|
|
523
|
-
* It exists for one field
|
|
524
|
-
*
|
|
525
|
-
*
|
|
526
|
-
*
|
|
527
|
-
* `pnpm approve-builds` before it has rendered a page once.
|
|
504
|
+
* It exists for one field, `allowBuilds`. pnpm fails an install — and every `pnpm dev` after it —
|
|
505
|
+
* until the project has said whether a dependency's install script should run. Nothing rshono itself
|
|
506
|
+
* installs has one, so most apps get no file; the packages that do (wrangler's esbuild and workerd)
|
|
507
|
+
* declare their answer on the feature that brings them.
|
|
528
508
|
*
|
|
529
|
-
*
|
|
530
|
-
* package projects included. What lands here is a decision about *this* app: a scaffolded file the app
|
|
531
|
-
* owns from then on, not something the framework reaches back into.
|
|
509
|
+
* A file rather than a `pnpm` key in `package.json`, which pnpm 11 no longer reads.
|
|
532
510
|
*/ function buildPnpmSettings(features) {
|
|
533
|
-
const allowBuilds = {
|
|
534
|
-
...BASE_ALLOW_BUILDS
|
|
535
|
-
};
|
|
511
|
+
const allowBuilds = {};
|
|
536
512
|
for (const feature of features)Object.assign(allowBuilds, feature.allowBuilds);
|
|
513
|
+
const entries = Object.entries(sorted(allowBuilds));
|
|
514
|
+
if (entries.length === 0) return null;
|
|
537
515
|
return [
|
|
538
516
|
'# Which dependencies may run an install script. pnpm runs none it has not been told about, and',
|
|
539
517
|
'# fails the install rather than skip one quietly — so anything added later belongs here too.',
|
|
540
518
|
'# `false` means the script was looked at: these ship their real binary as an optional dependency.',
|
|
541
519
|
'allowBuilds:',
|
|
542
|
-
...
|
|
520
|
+
...entries.map(([name, allowed])=>` ${name}: ${allowed}`),
|
|
543
521
|
''
|
|
544
522
|
].join('\n');
|
|
545
523
|
}
|
|
@@ -574,10 +552,9 @@ function sorted(record) {
|
|
|
574
552
|
version: '0.1.0',
|
|
575
553
|
private: true,
|
|
576
554
|
type: 'module',
|
|
577
|
-
//
|
|
578
|
-
// Node finds out from their package manager rather than from a stack trace.
|
|
555
|
+
// Generated from the framework's own manifest, so the app's floor cannot drift below rshono's.
|
|
579
556
|
engines: {
|
|
580
|
-
node:
|
|
557
|
+
node: NODE_ENGINE
|
|
581
558
|
},
|
|
582
559
|
scripts,
|
|
583
560
|
dependencies: sorted(dependencies),
|
|
@@ -593,25 +570,24 @@ function sorted(record) {
|
|
|
593
570
|
return `${JSON.stringify(ordered, null, 2)}\n`;
|
|
594
571
|
}
|
|
595
572
|
|
|
596
|
-
;// CONCATENATED MODULE: external "node:fs"
|
|
597
|
-
|
|
598
|
-
;// CONCATENATED MODULE: external "node:path"
|
|
599
|
-
|
|
600
573
|
;// CONCATENATED MODULE: ./src/render.ts
|
|
601
574
|
|
|
602
|
-
|
|
575
|
+
/**
|
|
576
|
+
* `{{NAME}}`, deliberately not `__NAME__`: templates are real files that real tools run over, and in
|
|
577
|
+
* markdown `__NAME__` *is* strong emphasis — Prettier rewrites it to `**NAME**` and the token stops
|
|
578
|
+
* matching. `{{…}}` means nothing to any format these templates are written in.
|
|
579
|
+
*/ const TOKEN_PATTERN = /\{\{[A-Z][A-Z\d_]*\}\}/g;
|
|
603
580
|
function tokensFor(answers, pm) {
|
|
604
581
|
return {
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
__PM_RUN__: pm.run
|
|
582
|
+
'{{PROJECT_NAME}}': answers.packageName,
|
|
583
|
+
'{{DEPLOY_TARGET}}': answers.deploy,
|
|
584
|
+
'{{DEPLOY_HINT}}': deployHint(answers.deploy),
|
|
585
|
+
'{{PM_RUN}}': pm.run
|
|
610
586
|
};
|
|
611
587
|
}
|
|
612
588
|
/**
|
|
613
589
|
* Substitutes tokens, and throws on one it doesn't know — a typo in a template would otherwise ship a
|
|
614
|
-
* literal `
|
|
590
|
+
* literal `{{PORJECT_NAME}}` into somebody's new app, which no test of the generator's logic would
|
|
615
591
|
* catch.
|
|
616
592
|
*/ function render(contents, tokens, source) {
|
|
617
593
|
return contents.replace(TOKEN_PATTERN, (token)=>{
|
|
@@ -644,10 +620,9 @@ function readTemplateDir(dir) {
|
|
|
644
620
|
/**
|
|
645
621
|
* `_gitignore` → `.gitignore`, and so on for every dotfile.
|
|
646
622
|
*
|
|
647
|
-
* npm strips a literal `.gitignore` out of a published tarball, so a template cannot
|
|
648
|
-
*
|
|
649
|
-
*
|
|
650
|
-
* fix. It applies to the basename only, so `src/lib/_x.ts` is a dotfile but `templates/_x/y.ts` is not.
|
|
623
|
+
* npm strips a literal `.gitignore` out of a published tarball, so a template cannot contain one — it
|
|
624
|
+
* would exist in the repo, pass every local test, and be missing from the package everybody installs.
|
|
625
|
+
* Applies to the basename only, so `src/lib/_x.ts` is a dotfile but `templates/_x/y.ts` is not.
|
|
651
626
|
*/ function undotted(path) {
|
|
652
627
|
const segments = path.split(posix.sep);
|
|
653
628
|
const name = segments.pop();
|
|
@@ -687,7 +662,9 @@ function readTemplateDir(dir) {
|
|
|
687
662
|
const gitignore = files.get('.gitignore');
|
|
688
663
|
if (gitignore) files.set('.gitignore', appendGitignore(gitignore, features));
|
|
689
664
|
files.set('package.json', buildPackageJson(answers, features, pm));
|
|
690
|
-
|
|
665
|
+
// Only for pnpm, and only when a feature brought an install script to answer for — see `buildPnpmSettings`.
|
|
666
|
+
const pnpmSettings = pm.name === 'pnpm' ? buildPnpmSettings(features) : null;
|
|
667
|
+
if (pnpmSettings) files.set('pnpm-workspace.yaml', pnpmSettings);
|
|
691
668
|
return {
|
|
692
669
|
// Sorted, so both the write order and a test's snapshot are stable.
|
|
693
670
|
files: new Map([
|
|
@@ -702,6 +679,7 @@ function readTemplateDir(dir) {
|
|
|
702
679
|
|
|
703
680
|
;// CONCATENATED MODULE: ./src/pm.ts
|
|
704
681
|
|
|
682
|
+
|
|
705
683
|
const INSTALL = {
|
|
706
684
|
npm: [
|
|
707
685
|
'install'
|
|
@@ -721,7 +699,7 @@ const RUN = {
|
|
|
721
699
|
bun: 'bun'
|
|
722
700
|
};
|
|
723
701
|
function isKnown(name) {
|
|
724
|
-
return name
|
|
702
|
+
return PACKAGE_MANAGERS.includes(name);
|
|
725
703
|
}
|
|
726
704
|
function packageManager(name, version) {
|
|
727
705
|
return {
|
|
@@ -732,8 +710,8 @@ function packageManager(name, version) {
|
|
|
732
710
|
};
|
|
733
711
|
}
|
|
734
712
|
/**
|
|
735
|
-
* Which package manager invoked us. Every one of them sets `npm_config_user_agent`
|
|
736
|
-
* spawns — `pnpm/11.9.0 npm/? node/v22.14.0 darwin arm64` — so `
|
|
713
|
+
* Which package manager invoked us. Every one of them sets `npm_config_user_agent` on the process it
|
|
714
|
+
* spawns — `pnpm/11.9.0 npm/? node/v22.14.0 darwin arm64` — so `pnx @rshono/create` scaffolds a pnpm
|
|
737
715
|
* project without asking, and the exact version comes along for the `packageManager` field.
|
|
738
716
|
*
|
|
739
717
|
* Falls back to npm, which is also what a bare `node bin/create-rshono.mjs` gets.
|
|
@@ -750,12 +728,6 @@ function packageManager(name, version) {
|
|
|
750
728
|
*/ function runInstall(pm, cwd) {
|
|
751
729
|
return run(pm, pm.install, cwd);
|
|
752
730
|
}
|
|
753
|
-
/** `<pm> run <script>` — the one form every package manager accepts, Yarn v1 included. */ function runScript(pm, script, cwd) {
|
|
754
|
-
return run(pm, [
|
|
755
|
-
'run',
|
|
756
|
-
script
|
|
757
|
-
], cwd);
|
|
758
|
-
}
|
|
759
731
|
function run(pm, args, cwd) {
|
|
760
732
|
const result = spawnSync(pm.name, args, {
|
|
761
733
|
cwd,
|
|
@@ -778,15 +750,20 @@ function run(pm, args, cwd) {
|
|
|
778
750
|
'.vscode',
|
|
779
751
|
'Thumbs.db'
|
|
780
752
|
]);
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
753
|
+
/**
|
|
754
|
+
* What is already at the target path, ignoring the entries a fresh clone or an editor leaves behind —
|
|
755
|
+
* which is what decides whether scaffolding into it is safe.
|
|
756
|
+
*
|
|
757
|
+
* A path that does not exist yet is no conflict. A path that exists and is *not* a directory throws
|
|
758
|
+
* rather than reporting an empty list, since `--force` should not write into one either — otherwise
|
|
759
|
+
* `create-rshono README.md` gets as far as `mkdir` before failing on a raw ENOTDIR.
|
|
760
|
+
*/ function conflictingEntries(dir) {
|
|
761
|
+
const stats = statSync(dir, {
|
|
762
|
+
throwIfNoEntry: false
|
|
763
|
+
});
|
|
764
|
+
if (!stats) return [];
|
|
765
|
+
if (!stats.isDirectory()) throw new Error(`${dir} already exists and is not a directory.`);
|
|
766
|
+
return readdirSync(dir).filter((entry)=>!IGNORED_ENTRIES.has(entry));
|
|
790
767
|
}
|
|
791
768
|
/**
|
|
792
769
|
* Writes the plan. Directories are created as needed, and files are written with the plan's own
|
|
@@ -808,7 +785,16 @@ function inspectTarget(dir) {
|
|
|
808
785
|
/**
|
|
809
786
|
* The generator without the CLI around it: answers in, the exact set of files out. This is what the
|
|
810
787
|
* test suite asserts on — the whole matrix of options, in memory, with no directory to clean up — and
|
|
811
|
-
* what another tool would call to scaffold an app itself
|
|
788
|
+
* what another tool would call to scaffold an app itself:
|
|
789
|
+
*
|
|
790
|
+
* ```ts
|
|
791
|
+
* import { packageManager, plan, writePlan } from '@rshono/create';
|
|
792
|
+
*
|
|
793
|
+
* const answers = { packageName: 'my-app', deploy: 'node', styling: 'css', formatter: 'prettier', linter: 'oxlint' };
|
|
794
|
+
* writePlan(plan(answers, packageManager('npm')), './my-app');
|
|
795
|
+
* ```
|
|
796
|
+
*
|
|
797
|
+
* `package.json` is assembled inside `plan`, so nothing here needs to be composed by hand.
|
|
812
798
|
*
|
|
813
799
|
* @packageDocumentation
|
|
814
800
|
*/
|
|
@@ -818,23 +804,22 @@ function inspectTarget(dir) {
|
|
|
818
804
|
|
|
819
805
|
|
|
820
806
|
|
|
821
|
-
|
|
822
807
|
var __webpack_exports__DEPLOY_TARGET_NAMES = __webpack_exports__.bp;
|
|
823
808
|
var __webpack_exports__ESLINT_TYPESCRIPT = __webpack_exports__.ml;
|
|
809
|
+
var __webpack_exports__FORMATTER_NAMES = __webpack_exports__.wC;
|
|
824
810
|
var __webpack_exports__FRAMEWORK_DEPS = __webpack_exports__.e7;
|
|
811
|
+
var __webpack_exports__LINTER_NAMES = __webpack_exports__.At;
|
|
825
812
|
var __webpack_exports__PACKAGE_MANAGERS = __webpack_exports__.Ab;
|
|
826
813
|
var __webpack_exports__QUALITY_PRESETS = __webpack_exports__.pm;
|
|
827
814
|
var __webpack_exports__RSHONO_RANGE = __webpack_exports__.s_;
|
|
828
815
|
var __webpack_exports__TOOL_VERSIONS = __webpack_exports__.RM;
|
|
829
|
-
var
|
|
816
|
+
var __webpack_exports__conflictingEntries = __webpack_exports__.dh;
|
|
830
817
|
var __webpack_exports__deployHint = __webpack_exports__.P8;
|
|
831
818
|
var __webpack_exports__detectPackageManager = __webpack_exports__.Lv;
|
|
832
|
-
var __webpack_exports__inspectTarget = __webpack_exports__.WL;
|
|
833
|
-
var __webpack_exports__isDeployTarget = __webpack_exports__.p1;
|
|
834
819
|
var __webpack_exports__isValidPackageName = __webpack_exports__.eW;
|
|
835
820
|
var __webpack_exports__packageManager = __webpack_exports__.VZ;
|
|
836
821
|
var __webpack_exports__plan = __webpack_exports__.et;
|
|
837
822
|
var __webpack_exports__selectFeatures = __webpack_exports__.N7;
|
|
838
823
|
var __webpack_exports__toPackageName = __webpack_exports__.PQ;
|
|
839
824
|
var __webpack_exports__writePlan = __webpack_exports__.pD;
|
|
840
|
-
export { __webpack_exports__DEPLOY_TARGET_NAMES as DEPLOY_TARGET_NAMES, __webpack_exports__ESLINT_TYPESCRIPT as ESLINT_TYPESCRIPT, __webpack_exports__FRAMEWORK_DEPS as FRAMEWORK_DEPS, __webpack_exports__PACKAGE_MANAGERS as PACKAGE_MANAGERS, __webpack_exports__QUALITY_PRESETS as QUALITY_PRESETS, __webpack_exports__RSHONO_RANGE as RSHONO_RANGE, __webpack_exports__TOOL_VERSIONS as TOOL_VERSIONS,
|
|
825
|
+
export { __webpack_exports__DEPLOY_TARGET_NAMES as DEPLOY_TARGET_NAMES, __webpack_exports__ESLINT_TYPESCRIPT as ESLINT_TYPESCRIPT, __webpack_exports__FORMATTER_NAMES as FORMATTER_NAMES, __webpack_exports__FRAMEWORK_DEPS as FRAMEWORK_DEPS, __webpack_exports__LINTER_NAMES as LINTER_NAMES, __webpack_exports__PACKAGE_MANAGERS as PACKAGE_MANAGERS, __webpack_exports__QUALITY_PRESETS as QUALITY_PRESETS, __webpack_exports__RSHONO_RANGE as RSHONO_RANGE, __webpack_exports__TOOL_VERSIONS as TOOL_VERSIONS, __webpack_exports__conflictingEntries as conflictingEntries, __webpack_exports__deployHint as deployHint, __webpack_exports__detectPackageManager as detectPackageManager, __webpack_exports__isValidPackageName as isValidPackageName, __webpack_exports__packageManager as packageManager, __webpack_exports__plan as plan, __webpack_exports__selectFeatures as selectFeatures, __webpack_exports__toPackageName as toPackageName, __webpack_exports__writePlan as writePlan };
|