@tinycld/bootstrap 1.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.
- package/README.md +297 -0
- package/dist/args.js +130 -0
- package/dist/args.js.map +1 -0
- package/dist/bootstrap-tooling.js +66 -0
- package/dist/bootstrap-tooling.js.map +1 -0
- package/dist/copy-template.js +96 -0
- package/dist/copy-template.js.map +1 -0
- package/dist/index.js +134 -0
- package/dist/index.js.map +1 -0
- package/dist/layout.js +40 -0
- package/dist/layout.js.map +1 -0
- package/dist/link-core.js +99 -0
- package/dist/link-core.js.map +1 -0
- package/dist/link-package.js +85 -0
- package/dist/link-package.js.map +1 -0
- package/dist/prompts.js +187 -0
- package/dist/prompts.js.map +1 -0
- package/dist/substitute.js +35 -0
- package/dist/substitute.js.map +1 -0
- package/dist/validate.js +65 -0
- package/dist/validate.js.map +1 -0
- package/package.json +46 -0
- package/templates/full/manifest.ts +21 -0
- package/templates/full/package.json +30 -0
- package/templates/full/pb-migrations/1800000000_create_{{PKG_SLUG}}.js +67 -0
- package/templates/full/server/go.mod +10 -0
- package/templates/full/server/register.go +20 -0
- package/templates/full/tinycld/{{PKG_SLUG}}/collections.ts +27 -0
- package/templates/full/tinycld/{{PKG_SLUG}}/provider.tsx +16 -0
- package/templates/full/tinycld/{{PKG_SLUG}}/screens/[id].tsx +23 -0
- package/templates/full/tinycld/{{PKG_SLUG}}/screens/_layout.tsx +5 -0
- package/templates/full/tinycld/{{PKG_SLUG}}/screens/index.tsx +28 -0
- package/templates/full/tinycld/{{PKG_SLUG}}/seed.ts +22 -0
- package/templates/full/tinycld/{{PKG_SLUG}}/sidebar.tsx +20 -0
- package/templates/full/tinycld/{{PKG_SLUG}}/types.ts +18 -0
- package/templates/settings-only/manifest.ts +15 -0
- package/templates/settings-only/package.json +23 -0
- package/templates/settings-only/tinycld/{{PKG_SLUG}}/settings/main.tsx +20 -0
- package/templates/settings-only/tinycld/{{PKG_SLUG}}/types.ts +5 -0
- package/templates/shared/.github/workflows/ci.yml +59 -0
- package/templates/shared/README.md +54 -0
- package/templates/shared/tests/manifest.test.ts +14 -0
- package/templates/shared/tsconfig.json +22 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { realpathSync } from 'node:fs';
|
|
3
|
+
import { dirname, relative } from 'node:path';
|
|
4
|
+
import { pathToFileURL } from 'node:url';
|
|
5
|
+
import { intro, outro } from '@clack/prompts';
|
|
6
|
+
import pc from 'picocolors';
|
|
7
|
+
import { ArgParseError, parseArgs } from "./args.js";
|
|
8
|
+
import { bootstrapTooling } from "./bootstrap-tooling.js";
|
|
9
|
+
import { copyTemplate, resolveTemplatesRoot } from "./copy-template.js";
|
|
10
|
+
import { detectLayout } from "./layout.js";
|
|
11
|
+
import { offerLinkPackage } from "./link-package.js";
|
|
12
|
+
import { runPrompts } from "./prompts.js";
|
|
13
|
+
export function runToolingMode(opts) {
|
|
14
|
+
const root = opts.root ?? process.cwd();
|
|
15
|
+
const present = bootstrapTooling({ ...opts, root });
|
|
16
|
+
// Mandatory members must clone — a missing app/core means a broken workspace.
|
|
17
|
+
for (const required of ['app', 'core']) {
|
|
18
|
+
if (!present.includes(required)) {
|
|
19
|
+
throw new Error(`Failed to clone required member '${required}'. Check network/auth and retry.`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
console.log(`Workspace skeleton ready at ${root} (members: ${present.join(', ')})`);
|
|
23
|
+
}
|
|
24
|
+
async function main() {
|
|
25
|
+
intro(pc.bold(pc.cyan('@tinycld/bootstrap')));
|
|
26
|
+
let args;
|
|
27
|
+
try {
|
|
28
|
+
args = parseArgs(process.argv.slice(2));
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
if (err instanceof ArgParseError) {
|
|
32
|
+
console.error(pc.red('Bad arguments:'));
|
|
33
|
+
for (const issue of err.issues) {
|
|
34
|
+
console.error(` --${issue.flag}: ${issue.reason}`);
|
|
35
|
+
}
|
|
36
|
+
process.exit(2);
|
|
37
|
+
}
|
|
38
|
+
throw err;
|
|
39
|
+
}
|
|
40
|
+
if (args.tooling) {
|
|
41
|
+
runToolingMode({ root: process.cwd(), members: args.with });
|
|
42
|
+
outro(pc.green(`Tooling-only workspace assembled (app + core${args.with?.length ? `, ${args.with.join(', ')}` : ''}). Run \`npm install\` at the root.`));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const answers = await runPrompts(args);
|
|
46
|
+
copyTemplate(resolveTemplatesRoot(import.meta.url), answers);
|
|
47
|
+
const linked = await offerLinkPackage({
|
|
48
|
+
packageName: answers.slug,
|
|
49
|
+
targetDir: answers.targetDir,
|
|
50
|
+
mode: resolveLinkMode(args),
|
|
51
|
+
});
|
|
52
|
+
const relTarget = relative(process.cwd(), answers.targetDir) || answers.targetDir;
|
|
53
|
+
outro(pc.green(`Scaffolded ${pc.bold(answers.slug)} at ${pc.bold(relTarget)}`));
|
|
54
|
+
// Re-derive the layout from the resolved target so the next-steps output
|
|
55
|
+
// matches whatever path the user actually ended up at (default detection,
|
|
56
|
+
// explicit --target, or interactive override). The wrapper's parent dir
|
|
57
|
+
// names where `cd ../tinycld` lands.
|
|
58
|
+
const layout = detectLayoutFromTarget(answers.targetDir, answers.slug);
|
|
59
|
+
printNextSteps({ slug: answers.slug, relTarget, linked, layout });
|
|
60
|
+
}
|
|
61
|
+
function detectLayoutFromTarget(targetDir, slug) {
|
|
62
|
+
// If cwd has a tinycld/ child (workspace mode) and target is a sibling of
|
|
63
|
+
// that tinycld, we're in attach mode. Otherwise the scaffolder created a
|
|
64
|
+
// wrapper under cwd and dropped tinycld inside it (bootstrap mode).
|
|
65
|
+
const detected = detectLayout(slug);
|
|
66
|
+
if (detected.mode === 'attach' && targetDir === detected.targetDir)
|
|
67
|
+
return 'attach';
|
|
68
|
+
if (detected.mode === 'bootstrap' && targetDir === detected.targetDir)
|
|
69
|
+
return 'bootstrap';
|
|
70
|
+
// User passed an explicit --target. Infer from the on-disk shape: if the
|
|
71
|
+
// parent of targetDir has a `tinycld` child, treat as attach.
|
|
72
|
+
const parent = dirname(targetDir);
|
|
73
|
+
const looksAttached = detectLayout(slug, parent).mode === 'attach';
|
|
74
|
+
return looksAttached ? 'attach' : 'bootstrap';
|
|
75
|
+
}
|
|
76
|
+
function resolveLinkMode(args) {
|
|
77
|
+
if (args.link === false)
|
|
78
|
+
return 'skip';
|
|
79
|
+
if (args.link === true)
|
|
80
|
+
return 'accept';
|
|
81
|
+
if (args.yes === true)
|
|
82
|
+
return 'accept';
|
|
83
|
+
return 'prompt';
|
|
84
|
+
}
|
|
85
|
+
function printNextSteps({ slug, relTarget, linked, layout }) {
|
|
86
|
+
const lines = ['', pc.bold('Next steps:'), ''];
|
|
87
|
+
let step = 1;
|
|
88
|
+
if (layout === 'bootstrap') {
|
|
89
|
+
// Highlight that the scaffolder also dropped a tinycld checkout
|
|
90
|
+
// alongside the new package. New users may not realize they just
|
|
91
|
+
// got a self-contained workspace.
|
|
92
|
+
lines.push(pc.dim(` Scaffolded a self-contained workspace alongside the package.\n The tinycld app shell lives at ./${dirname(relTarget)}/tinycld/.\n`));
|
|
93
|
+
}
|
|
94
|
+
lines.push(` ${pc.dim(`# ${step++}. Initialize git and push to GitHub`)}`);
|
|
95
|
+
lines.push(` cd ${relTarget}`);
|
|
96
|
+
lines.push(' git init');
|
|
97
|
+
lines.push(' git add .');
|
|
98
|
+
lines.push(" git commit -m 'chore: initial scaffold'");
|
|
99
|
+
lines.push(` gh repo create tinycld/${slug} --public --source=. --push`);
|
|
100
|
+
lines.push('');
|
|
101
|
+
if (!linked) {
|
|
102
|
+
lines.push(` ${pc.dim(`# ${step++}. Link into the tinycld app shell`)}`);
|
|
103
|
+
lines.push(' cd ../tinycld');
|
|
104
|
+
lines.push(` npm run packages:link ../${slug}`);
|
|
105
|
+
lines.push('');
|
|
106
|
+
}
|
|
107
|
+
lines.push(` ${pc.dim(`# ${step++}. Verify (biome + tsc run from the app shell and cover the linked package)`)}`);
|
|
108
|
+
if (linked)
|
|
109
|
+
lines.push(' cd ../tinycld');
|
|
110
|
+
lines.push(' npm run checks');
|
|
111
|
+
lines.push('');
|
|
112
|
+
lines.push(` ${pc.dim(`# ${step++}. Run the app (Expo + PocketBase, single-port dev proxy)`)}`);
|
|
113
|
+
lines.push(' npm run start');
|
|
114
|
+
lines.push('');
|
|
115
|
+
console.log(lines.join('\n'));
|
|
116
|
+
}
|
|
117
|
+
function isEntrypoint() {
|
|
118
|
+
const argv1 = process.argv[1];
|
|
119
|
+
if (!argv1)
|
|
120
|
+
return false;
|
|
121
|
+
try {
|
|
122
|
+
return import.meta.url === pathToFileURL(realpathSync(argv1)).href;
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (isEntrypoint()) {
|
|
129
|
+
main().catch((err) => {
|
|
130
|
+
console.error(pc.red('Error:'), err?.message ?? err);
|
|
131
|
+
process.exit(1);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,MAAM,YAAY,CAAA;AAC3B,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AACpD,OAAO,EAAgC,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACvF,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEzC,MAAM,UAAU,cAAc,CAAC,IAA6B;IACxD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,EAAE,CAAA;IACvC,MAAM,OAAO,GAAG,gBAAgB,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IACnD,8EAA8E;IAC9E,KAAK,MAAM,QAAQ,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC;QACrC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,oCAAoC,QAAQ,kCAAkC,CAAC,CAAA;QACnG,CAAC;IACL,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,+BAA+B,IAAI,cAAc,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AACvF,CAAC;AAED,KAAK,UAAU,IAAI;IACf,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAA;IAE7C,IAAI,IAAkC,CAAA;IACtC,IAAI,CAAC;QACD,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;IAC3C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,IAAI,GAAG,YAAY,aAAa,EAAE,CAAC;YAC/B,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAA;YACvC,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;gBAC7B,OAAO,CAAC,KAAK,CAAC,OAAO,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,MAAM,EAAE,CAAC,CAAA;YACvD,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACnB,CAAC;QACD,MAAM,GAAG,CAAA;IACb,CAAC;IAED,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACf,cAAc,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;QAC3D,KAAK,CACD,EAAE,CAAC,KAAK,CACJ,+CACI,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EACtD,qCAAqC,CACxC,CACJ,CAAA;QACD,OAAM;IACV,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAA;IAEtC,YAAY,CAAC,oBAAoB,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAA;IAE5D,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC;QAClC,WAAW,EAAE,OAAO,CAAC,IAAI;QACzB,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,IAAI,EAAE,eAAe,CAAC,IAAI,CAAC;KAC9B,CAAC,CAAA;IAEF,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,SAAS,CAAA;IACjF,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAA;IAE/E,yEAAyE;IACzE,0EAA0E;IAC1E,wEAAwE;IACxE,qCAAqC;IACrC,MAAM,MAAM,GAAG,sBAAsB,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IACtE,cAAc,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;AACrE,CAAC;AAED,SAAS,sBAAsB,CAAC,SAAiB,EAAE,IAAY;IAC3D,0EAA0E;IAC1E,yEAAyE;IACzE,oEAAoE;IACpE,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,CAAA;IACnC,IAAI,QAAQ,CAAC,IAAI,KAAK,QAAQ,IAAI,SAAS,KAAK,QAAQ,CAAC,SAAS;QAAE,OAAO,QAAQ,CAAA;IACnF,IAAI,QAAQ,CAAC,IAAI,KAAK,WAAW,IAAI,SAAS,KAAK,QAAQ,CAAC,SAAS;QAAE,OAAO,WAAW,CAAA;IACzF,yEAAyE;IACzE,8DAA8D;IAC9D,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAA;IACjC,MAAM,aAAa,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAA;IAClE,OAAO,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAA;AACjD,CAAC;AAED,SAAS,eAAe,CAAC,IAAkC;IACvD,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK;QAAE,OAAO,MAAM,CAAA;IACtC,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI;QAAE,OAAO,QAAQ,CAAA;IACvC,IAAI,IAAI,CAAC,GAAG,KAAK,IAAI;QAAE,OAAO,QAAQ,CAAA;IACtC,OAAO,QAAQ,CAAA;AACnB,CAAC;AASD,SAAS,cAAc,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAkB;IACvE,MAAM,KAAK,GAAa,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,EAAE,CAAC,CAAA;IACxD,IAAI,IAAI,GAAG,CAAC,CAAA;IAEZ,IAAI,MAAM,KAAK,WAAW,EAAE,CAAC;QACzB,gEAAgE;QAChE,iEAAiE;QACjE,kCAAkC;QAClC,KAAK,CAAC,IAAI,CACN,EAAE,CAAC,GAAG,CACF,sGAAsG,OAAO,CAAC,SAAS,CAAC,cAAc,CACzI,CACJ,CAAA;IACL,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,qCAAqC,CAAC,EAAE,CAAC,CAAA;IAC3E,KAAK,CAAC,IAAI,CAAC,QAAQ,SAAS,EAAE,CAAC,CAAA;IAC/B,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;IACxB,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;IACzB,KAAK,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAA;IACvD,KAAK,CAAC,IAAI,CAAC,4BAA4B,IAAI,6BAA6B,CAAC,CAAA;IACzE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAEd,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,mCAAmC,CAAC,EAAE,CAAC,CAAA;QACzE,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAA;QAC7B,KAAK,CAAC,IAAI,CAAC,8BAA8B,IAAI,EAAE,CAAC,CAAA;QAChD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAClB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,4EAA4E,CAAC,EAAE,CAAC,CAAA;IAClH,IAAI,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAA;IACzC,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;IAC9B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAEd,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,0DAA0D,CAAC,EAAE,CAAC,CAAA;IAChG,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAA;IAC7B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAEd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;AACjC,CAAC;AAED,SAAS,YAAY;IACjB,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAC7B,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAA;IACxB,IAAI,CAAC;QACD,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,aAAa,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA;IACtE,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,KAAK,CAAA;IAChB,CAAC;AACL,CAAC;AAED,IAAI,YAAY,EAAE,EAAE,CAAC;IACjB,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QACjB,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,OAAO,IAAI,GAAG,CAAC,CAAA;QACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACnB,CAAC,CAAC,CAAA;AACN,CAAC"}
|
package/dist/layout.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join, resolve } from 'node:path';
|
|
3
|
+
const APP_DIR_NAME = 'tinycld';
|
|
4
|
+
export function detectLayout(slug, cwd = process.cwd()) {
|
|
5
|
+
const candidateApp = join(cwd, APP_DIR_NAME);
|
|
6
|
+
if (looksLikeAppShell(candidateApp)) {
|
|
7
|
+
return {
|
|
8
|
+
mode: 'attach',
|
|
9
|
+
targetDir: resolve(cwd, slug),
|
|
10
|
+
appDir: candidateApp,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
const wrapperDir = resolve(cwd, `${APP_DIR_NAME}-${slug}`);
|
|
14
|
+
return {
|
|
15
|
+
mode: 'bootstrap',
|
|
16
|
+
targetDir: join(wrapperDir, slug),
|
|
17
|
+
appDir: join(wrapperDir, APP_DIR_NAME),
|
|
18
|
+
wrapperDir,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A directory "looks like" the tinycld app shell when it has a package.json
|
|
23
|
+
* declaring `name: "tinycld"`. The bare directory check would false-match any
|
|
24
|
+
* unrelated `tinycld` directory; the package.json check is fast (one read of
|
|
25
|
+
* a file we'd be reading anyway) and unambiguous now that the app shell's
|
|
26
|
+
* package.json `name` field has been renamed from "@tinycld/app" to "tinycld".
|
|
27
|
+
*/
|
|
28
|
+
export function looksLikeAppShell(dir) {
|
|
29
|
+
const pkgPath = join(dir, 'package.json');
|
|
30
|
+
if (!existsSync(pkgPath))
|
|
31
|
+
return false;
|
|
32
|
+
try {
|
|
33
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
34
|
+
return pkg?.name === 'tinycld';
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=layout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.js","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAuBzC,MAAM,YAAY,GAAG,SAAS,CAAA;AAE9B,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,MAAc,OAAO,CAAC,GAAG,EAAE;IAClE,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAA;IAC5C,IAAI,iBAAiB,CAAC,YAAY,CAAC,EAAE,CAAC;QAClC,OAAO;YACH,IAAI,EAAE,QAAQ;YACd,SAAS,EAAE,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC;YAC7B,MAAM,EAAE,YAAY;SACvB,CAAA;IACL,CAAC;IAED,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,YAAY,IAAI,IAAI,EAAE,CAAC,CAAA;IAC1D,OAAO;QACH,IAAI,EAAE,WAAW;QACjB,SAAS,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC;QACjC,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC;QACtC,UAAU;KACb,CAAA;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAW;IACzC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAA;IACzC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAA;IACtC,IAAI,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAA;QACtD,OAAO,GAAG,EAAE,IAAI,KAAK,SAAS,CAAA;IAClC,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,KAAK,CAAA;IAChB,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { dirname, join, relative } from 'node:path';
|
|
4
|
+
import { confirm, isCancel, log, spinner } from '@clack/prompts';
|
|
5
|
+
import pc from 'picocolors';
|
|
6
|
+
const CORE_REPO_URL = 'git@github.com:tinycld/core.git';
|
|
7
|
+
const APP_REPO_URL = 'git@github.com:tinycld/tinycld.git';
|
|
8
|
+
const CORE_DIR_NAME = 'core';
|
|
9
|
+
const APP_DIR_NAME = 'tinycld';
|
|
10
|
+
/**
|
|
11
|
+
* Returns true if the user chose to link (even if a subprocess failed —
|
|
12
|
+
* the error is already logged, and we don't want to follow up with
|
|
13
|
+
* "here are the manual steps" when the user already expressed intent).
|
|
14
|
+
* Returns false only if linking was declined or skipped.
|
|
15
|
+
*
|
|
16
|
+
* Linking happens against the tinycld **app shell** (sibling repo
|
|
17
|
+
* `tinycld/tinycld`), which owns `packages:link`. The `core` library
|
|
18
|
+
* sibling is also cloned because the app shell installs it via
|
|
19
|
+
* `file:../core` and the package's tsconfig points at `../core/...`.
|
|
20
|
+
*/
|
|
21
|
+
export async function offerLinkCore({ packageName, targetDir, mode }) {
|
|
22
|
+
if (mode === 'skip')
|
|
23
|
+
return false;
|
|
24
|
+
const parentDir = dirname(targetDir);
|
|
25
|
+
const coreDir = join(parentDir, CORE_DIR_NAME);
|
|
26
|
+
const appDir = join(parentDir, APP_DIR_NAME);
|
|
27
|
+
const coreExists = existsSync(coreDir);
|
|
28
|
+
const appExists = existsSync(appDir);
|
|
29
|
+
if (mode === 'prompt') {
|
|
30
|
+
const missing = [];
|
|
31
|
+
if (!coreExists)
|
|
32
|
+
missing.push(CORE_DIR_NAME);
|
|
33
|
+
if (!appExists)
|
|
34
|
+
missing.push(APP_DIR_NAME);
|
|
35
|
+
const prompt = missing.length === 0
|
|
36
|
+
? `Link ${pc.bold(packageName)} into ${pc.bold(APP_DIR_NAME)} now?`
|
|
37
|
+
: `Clone ${pc.bold(missing.join(' + '))} (shallow) and link ${pc.bold(packageName)} into ${pc.bold(APP_DIR_NAME)} now?`;
|
|
38
|
+
const answer = await confirm({ message: prompt, initialValue: true });
|
|
39
|
+
if (isCancel(answer) || answer !== true)
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
if (!coreExists) {
|
|
43
|
+
if (!cloneRepo(CORE_REPO_URL, coreDir))
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
log.info(`Using existing ${CORE_DIR_NAME} at ${coreDir}`);
|
|
48
|
+
}
|
|
49
|
+
if (!appExists) {
|
|
50
|
+
if (!cloneRepo(APP_REPO_URL, appDir))
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
log.info(`Using existing ${APP_DIR_NAME} at ${appDir}`);
|
|
55
|
+
}
|
|
56
|
+
const install = spinner();
|
|
57
|
+
install.start(`Installing ${APP_DIR_NAME} dependencies (bun install)`);
|
|
58
|
+
const inst = spawnSync('bun', ['install'], { cwd: appDir, stdio: 'pipe', encoding: 'utf8' });
|
|
59
|
+
if (inst.status !== 0) {
|
|
60
|
+
install.stop(pc.red('bun install failed'), 1);
|
|
61
|
+
log.error(inst.stderr.trim() || 'bun install exited non-zero');
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
install.stop(`Installed ${APP_DIR_NAME} dependencies`);
|
|
65
|
+
// packages:link in tinycld takes a sibling-directory locator and reads
|
|
66
|
+
// the package name from the sibling's package.json. Pass a path relative
|
|
67
|
+
// to the app shell so the symlink target stays portable.
|
|
68
|
+
const link = spinner();
|
|
69
|
+
link.start(`Linking ${packageName}`);
|
|
70
|
+
const locator = relative(appDir, targetDir) || targetDir;
|
|
71
|
+
const linkResult = spawnSync('bun', ['run', 'packages:link', locator], {
|
|
72
|
+
cwd: appDir,
|
|
73
|
+
stdio: 'pipe',
|
|
74
|
+
encoding: 'utf8',
|
|
75
|
+
});
|
|
76
|
+
if (linkResult.status !== 0) {
|
|
77
|
+
link.stop(pc.red('Link failed'), 1);
|
|
78
|
+
log.error(linkResult.stderr.trim() || 'packages:link exited non-zero');
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
link.stop(`Linked ${packageName} into ${APP_DIR_NAME}`);
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
function cloneRepo(url, dest) {
|
|
85
|
+
const s = spinner();
|
|
86
|
+
s.start(`Cloning ${url} into ${dest}`);
|
|
87
|
+
const result = spawnSync('git', ['clone', '--depth', '1', url, dest], {
|
|
88
|
+
stdio: 'pipe',
|
|
89
|
+
encoding: 'utf8',
|
|
90
|
+
});
|
|
91
|
+
if (result.status !== 0) {
|
|
92
|
+
s.stop(pc.red('Clone failed'), 1);
|
|
93
|
+
log.error(result.stderr.trim() || 'git clone exited non-zero');
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
s.stop(`Cloned ${dest}`);
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=link-core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link-core.js","sourceRoot":"","sources":["../src/link-core.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { dirname, join, relative } from 'node:path';
|
|
4
|
+
import { confirm, isCancel, log, spinner } from '@clack/prompts';
|
|
5
|
+
import pc from 'picocolors';
|
|
6
|
+
const APP_REPO_URL = 'git@github.com:tinycld/tinycld.git';
|
|
7
|
+
const APP_DIR_NAME = 'tinycld';
|
|
8
|
+
/**
|
|
9
|
+
* Returns true if the user chose to link (even if a subprocess failed —
|
|
10
|
+
* the error is already logged, and we don't want to follow up with
|
|
11
|
+
* "here are the manual steps" when the user already expressed intent).
|
|
12
|
+
* Returns false only if linking was declined or skipped.
|
|
13
|
+
*
|
|
14
|
+
* Linking happens against the tinycld **app shell** (sibling repo
|
|
15
|
+
* `tinycld/tinycld`), which owns `packages:link` and bundles `@tinycld/core`
|
|
16
|
+
* at `packages/@tinycld/core/`. This package's tsconfig
|
|
17
|
+
* (`"@tinycld/core/*": ["../tinycld/packages/@tinycld/core/*"]`) and its Go
|
|
18
|
+
* server's `replace tinycld.org/core => ../../tinycld/packages/@tinycld/core/server`
|
|
19
|
+
* directive both resolve into the bundled core inside the app shell.
|
|
20
|
+
*/
|
|
21
|
+
export async function offerLinkPackage({ packageName, targetDir, mode }) {
|
|
22
|
+
if (mode === 'skip')
|
|
23
|
+
return false;
|
|
24
|
+
const parentDir = dirname(targetDir);
|
|
25
|
+
const appDir = join(parentDir, APP_DIR_NAME);
|
|
26
|
+
const appExists = existsSync(appDir);
|
|
27
|
+
if (mode === 'prompt') {
|
|
28
|
+
const prompt = appExists
|
|
29
|
+
? `Link ${pc.bold(packageName)} into ${pc.bold(APP_DIR_NAME)} now?`
|
|
30
|
+
: `Clone ${pc.bold(APP_DIR_NAME)} (shallow) and link ${pc.bold(packageName)} into it now?`;
|
|
31
|
+
const answer = await confirm({ message: prompt, initialValue: true });
|
|
32
|
+
if (isCancel(answer) || answer !== true)
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
if (!appExists) {
|
|
36
|
+
if (!cloneRepo(APP_REPO_URL, appDir))
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
log.info(`Using existing ${APP_DIR_NAME} at ${appDir}`);
|
|
41
|
+
}
|
|
42
|
+
const install = spinner();
|
|
43
|
+
install.start(`Installing ${APP_DIR_NAME} dependencies (npm install)`);
|
|
44
|
+
const inst = spawnSync('npm', ['install'], { cwd: appDir, stdio: 'pipe', encoding: 'utf8' });
|
|
45
|
+
if (inst.status !== 0) {
|
|
46
|
+
install.stop(pc.red('npm install failed'), 1);
|
|
47
|
+
log.error(inst.stderr.trim() || 'npm install exited non-zero');
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
install.stop(`Installed ${APP_DIR_NAME} dependencies`);
|
|
51
|
+
// packages:link in tinycld takes a sibling-directory locator and reads
|
|
52
|
+
// the package name from the sibling's package.json. Pass a path relative
|
|
53
|
+
// to the app shell so the symlink target stays portable.
|
|
54
|
+
const link = spinner();
|
|
55
|
+
link.start(`Linking ${packageName}`);
|
|
56
|
+
const locator = relative(appDir, targetDir) || targetDir;
|
|
57
|
+
const linkResult = spawnSync('npm', ['run', 'packages:link', locator], {
|
|
58
|
+
cwd: appDir,
|
|
59
|
+
stdio: 'pipe',
|
|
60
|
+
encoding: 'utf8',
|
|
61
|
+
});
|
|
62
|
+
if (linkResult.status !== 0) {
|
|
63
|
+
link.stop(pc.red('Link failed'), 1);
|
|
64
|
+
log.error(linkResult.stderr.trim() || 'packages:link exited non-zero');
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
link.stop(`Linked ${packageName} into ${APP_DIR_NAME}`);
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
function cloneRepo(url, dest) {
|
|
71
|
+
const s = spinner();
|
|
72
|
+
s.start(`Cloning ${url} into ${dest}`);
|
|
73
|
+
const result = spawnSync('git', ['clone', '--depth', '1', url, dest], {
|
|
74
|
+
stdio: 'pipe',
|
|
75
|
+
encoding: 'utf8',
|
|
76
|
+
});
|
|
77
|
+
if (result.status !== 0) {
|
|
78
|
+
s.stop(pc.red('Clone failed'), 1);
|
|
79
|
+
log.error(result.stderr.trim() || 'git clone exited non-zero');
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
s.stop(`Cloned ${dest}`);
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=link-package.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link-package.js","sourceRoot":"","sources":["../src/link-package.ts"],"names":[],"mappings":"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"}
|
package/dist/prompts.js
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { relative, resolve } from 'node:path';
|
|
2
|
+
import { cancel, confirm, isCancel, select, text } from '@clack/prompts';
|
|
3
|
+
import { detectLayout } from "./layout.js";
|
|
4
|
+
import { validateDescription, validateIcon, validateName, validateNavOrder, validateShortcut, validateSlug, validateTargetDir, } from "./validate.js";
|
|
5
|
+
function cancelIf(value) {
|
|
6
|
+
if (isCancel(value)) {
|
|
7
|
+
cancel('Scaffolding cancelled.');
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
function fail(msg) {
|
|
13
|
+
cancel(msg);
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
function titleCase(slug) {
|
|
17
|
+
return slug
|
|
18
|
+
.split('-')
|
|
19
|
+
.filter(Boolean)
|
|
20
|
+
.map((w) => (w[0]?.toUpperCase() ?? '') + w.slice(1))
|
|
21
|
+
.join(' ');
|
|
22
|
+
}
|
|
23
|
+
export async function runPrompts(argv) {
|
|
24
|
+
const skipPrompts = argv.yes === true;
|
|
25
|
+
const slug = await resolveSlug(argv.slug, skipPrompts);
|
|
26
|
+
const name = await resolveString({
|
|
27
|
+
argvValue: argv.name,
|
|
28
|
+
validator: validateName,
|
|
29
|
+
skipPrompts,
|
|
30
|
+
defaultValue: titleCase(slug),
|
|
31
|
+
prompt: {
|
|
32
|
+
message: 'Human-readable name',
|
|
33
|
+
initialValue: titleCase(slug),
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
const description = await resolveString({
|
|
37
|
+
argvValue: argv.description,
|
|
38
|
+
validator: validateDescription,
|
|
39
|
+
skipPrompts,
|
|
40
|
+
defaultValue: `${titleCase(slug)} for your organization`,
|
|
41
|
+
prompt: {
|
|
42
|
+
message: 'One-sentence description',
|
|
43
|
+
placeholder: `${titleCase(slug)} for your organization`,
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
const preset = await resolvePreset(argv.preset, skipPrompts);
|
|
47
|
+
const answers = {
|
|
48
|
+
slug,
|
|
49
|
+
name,
|
|
50
|
+
description,
|
|
51
|
+
preset,
|
|
52
|
+
targetDir: '',
|
|
53
|
+
};
|
|
54
|
+
if (preset === 'full') {
|
|
55
|
+
answers.icon = await resolveString({
|
|
56
|
+
argvValue: argv.icon,
|
|
57
|
+
validator: validateIcon,
|
|
58
|
+
skipPrompts,
|
|
59
|
+
defaultValue: 'box',
|
|
60
|
+
prompt: { message: 'Lucide icon name', placeholder: 'box', initialValue: 'box' },
|
|
61
|
+
});
|
|
62
|
+
answers.navOrder = await resolveNavOrder(argv.navOrder, skipPrompts);
|
|
63
|
+
answers.navShortcut = await resolveString({
|
|
64
|
+
argvValue: argv.shortcut,
|
|
65
|
+
validator: validateShortcut,
|
|
66
|
+
skipPrompts,
|
|
67
|
+
defaultValue: '',
|
|
68
|
+
prompt: {
|
|
69
|
+
message: 'Keyboard shortcut (single letter, blank to skip)',
|
|
70
|
+
placeholder: '',
|
|
71
|
+
initialValue: '',
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
answers.includeServer = await resolveBool({
|
|
75
|
+
argvValue: argv.server,
|
|
76
|
+
skipPrompts,
|
|
77
|
+
defaultValue: true,
|
|
78
|
+
prompt: { message: 'Include a Go server?', initialValue: true },
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
answers.targetDir = await resolveTarget(argv.target, slug, skipPrompts);
|
|
82
|
+
return answers;
|
|
83
|
+
}
|
|
84
|
+
async function resolveSlug(fromArgv, skipPrompts) {
|
|
85
|
+
if (fromArgv) {
|
|
86
|
+
const err = validateSlug(fromArgv);
|
|
87
|
+
if (err)
|
|
88
|
+
fail(`Invalid slug "${fromArgv}": ${err}`);
|
|
89
|
+
return fromArgv;
|
|
90
|
+
}
|
|
91
|
+
if (skipPrompts)
|
|
92
|
+
fail('Missing slug. Provide it as a positional argument when using --yes.');
|
|
93
|
+
return cancelIf(await text({
|
|
94
|
+
message: 'Package slug (kebab-case, e.g. my-feature)',
|
|
95
|
+
validate: (v) => validateSlug(v) ?? undefined,
|
|
96
|
+
}));
|
|
97
|
+
}
|
|
98
|
+
async function resolveString({ argvValue, validator, skipPrompts, defaultValue, prompt, }) {
|
|
99
|
+
if (argvValue !== undefined) {
|
|
100
|
+
const err = validator(argvValue);
|
|
101
|
+
if (err)
|
|
102
|
+
fail(`Invalid ${prompt.message.toLowerCase()}: ${err}`);
|
|
103
|
+
return argvValue;
|
|
104
|
+
}
|
|
105
|
+
if (skipPrompts) {
|
|
106
|
+
const err = validator(defaultValue);
|
|
107
|
+
if (err)
|
|
108
|
+
fail(`Invalid default for ${prompt.message.toLowerCase()}: ${err}`);
|
|
109
|
+
return defaultValue;
|
|
110
|
+
}
|
|
111
|
+
return cancelIf(await text({
|
|
112
|
+
...prompt,
|
|
113
|
+
validate: (v) => validator(v) ?? undefined,
|
|
114
|
+
}));
|
|
115
|
+
}
|
|
116
|
+
async function resolvePreset(fromArgv, skipPrompts) {
|
|
117
|
+
if (fromArgv)
|
|
118
|
+
return fromArgv;
|
|
119
|
+
if (skipPrompts)
|
|
120
|
+
return 'full';
|
|
121
|
+
return cancelIf(await select({
|
|
122
|
+
message: 'Preset',
|
|
123
|
+
options: [
|
|
124
|
+
{
|
|
125
|
+
value: 'full',
|
|
126
|
+
label: 'full — data package (routes, collections, migrations, seed, optional Go server)',
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
value: 'settings-only',
|
|
130
|
+
label: 'settings-only — just a settings panel (like @tinycld/google-takeout-import)',
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
}));
|
|
134
|
+
}
|
|
135
|
+
async function resolveNavOrder(fromArgv, skipPrompts) {
|
|
136
|
+
if (fromArgv !== undefined) {
|
|
137
|
+
const err = validateNavOrder(String(fromArgv));
|
|
138
|
+
if (err)
|
|
139
|
+
fail(`Invalid nav order: ${err}`);
|
|
140
|
+
return fromArgv;
|
|
141
|
+
}
|
|
142
|
+
if (skipPrompts)
|
|
143
|
+
return 20;
|
|
144
|
+
const raw = cancelIf(await text({
|
|
145
|
+
message: 'Nav order (0–99)',
|
|
146
|
+
initialValue: '20',
|
|
147
|
+
validate: (v) => validateNavOrder(v) ?? undefined,
|
|
148
|
+
}));
|
|
149
|
+
return Number(raw);
|
|
150
|
+
}
|
|
151
|
+
async function resolveBool({ argvValue, skipPrompts, defaultValue, prompt }) {
|
|
152
|
+
if (argvValue !== undefined)
|
|
153
|
+
return argvValue;
|
|
154
|
+
if (skipPrompts)
|
|
155
|
+
return defaultValue;
|
|
156
|
+
return cancelIf(await confirm(prompt));
|
|
157
|
+
}
|
|
158
|
+
async function resolveTarget(fromArgv, slug, skipPrompts) {
|
|
159
|
+
// Explicit --target always wins. The user knows where they want it.
|
|
160
|
+
if (fromArgv !== undefined) {
|
|
161
|
+
const abs = resolve(fromArgv);
|
|
162
|
+
const err = validateTargetDir(abs);
|
|
163
|
+
if (err)
|
|
164
|
+
fail(`Invalid target directory: ${err}`);
|
|
165
|
+
return abs;
|
|
166
|
+
}
|
|
167
|
+
// No --target: pick a sensible default based on the cwd's existing layout.
|
|
168
|
+
// If cwd already has a tinycld/ app shell child, attach the new package
|
|
169
|
+
// alongside it as `<cwd>/<slug>`. Otherwise bootstrap a wrapper workspace
|
|
170
|
+
// under `<cwd>/tinycld-<slug>/` and place the package inside it.
|
|
171
|
+
const layout = detectLayout(slug);
|
|
172
|
+
const defaultAbs = layout.targetDir;
|
|
173
|
+
const defaultDisplay = `./${relative(process.cwd(), defaultAbs) || slug}`;
|
|
174
|
+
if (skipPrompts) {
|
|
175
|
+
const err = validateTargetDir(defaultAbs);
|
|
176
|
+
if (err)
|
|
177
|
+
fail(`Invalid default target directory: ${err}`);
|
|
178
|
+
return defaultAbs;
|
|
179
|
+
}
|
|
180
|
+
const raw = cancelIf(await text({
|
|
181
|
+
message: 'Target directory',
|
|
182
|
+
initialValue: defaultDisplay,
|
|
183
|
+
validate: (v) => validateTargetDir(resolve(v)) ?? undefined,
|
|
184
|
+
}));
|
|
185
|
+
return resolve(raw);
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export function buildPlaceholders(answers) {
|
|
2
|
+
const slug = answers.slug;
|
|
3
|
+
return {
|
|
4
|
+
'{{PKG_SLUG}}': slug,
|
|
5
|
+
'{{PKG_NAME}}': answers.name,
|
|
6
|
+
'{{PKG_SCOPED}}': slug, // kept for back-compat; identical to PKG_SLUG
|
|
7
|
+
'{{PKG_PASCAL}}': toPascalCase(slug),
|
|
8
|
+
'{{PKG_CAMEL}}': toCamelCase(slug),
|
|
9
|
+
'{{PKG_SNAKE}}': slug.replace(/-/g, '_'),
|
|
10
|
+
'{{PKG_DESCRIPTION}}': answers.description,
|
|
11
|
+
'{{PKG_ICON}}': answers.icon ?? 'box',
|
|
12
|
+
'{{PKG_NAV_ORDER}}': String(answers.navOrder ?? 20),
|
|
13
|
+
'{{PKG_NAV_SHORTCUT}}': answers.navShortcut ?? '',
|
|
14
|
+
'{{GO_MODULE}}': `tinycld.org/packages/${slug}`,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export function substitute(content, placeholders) {
|
|
18
|
+
let out = content;
|
|
19
|
+
for (const [token, value] of Object.entries(placeholders)) {
|
|
20
|
+
out = out.replaceAll(token, value);
|
|
21
|
+
}
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
24
|
+
function toPascalCase(slug) {
|
|
25
|
+
return slug
|
|
26
|
+
.split('-')
|
|
27
|
+
.filter(Boolean)
|
|
28
|
+
.map((part) => (part[0]?.toUpperCase() ?? '') + part.slice(1).toLowerCase())
|
|
29
|
+
.join('');
|
|
30
|
+
}
|
|
31
|
+
function toCamelCase(slug) {
|
|
32
|
+
const pascal = toPascalCase(slug);
|
|
33
|
+
return (pascal[0]?.toLowerCase() ?? '') + pascal.slice(1);
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=substitute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"substitute.js","sourceRoot":"","sources":["../src/substitute.ts"],"names":[],"mappings":"AAcA,MAAM,UAAU,iBAAiB,CAAC,OAAgB;IAC9C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAA;IACzB,OAAO;QACH,cAAc,EAAE,IAAI;QACpB,cAAc,EAAE,OAAO,CAAC,IAAI;QAC5B,gBAAgB,EAAE,IAAI,EAAE,8CAA8C;QACtE,gBAAgB,EAAE,YAAY,CAAC,IAAI,CAAC;QACpC,eAAe,EAAE,WAAW,CAAC,IAAI,CAAC;QAClC,eAAe,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC;QACxC,qBAAqB,EAAE,OAAO,CAAC,WAAW;QAC1C,cAAc,EAAE,OAAO,CAAC,IAAI,IAAI,KAAK;QACrC,mBAAmB,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;QACnD,sBAAsB,EAAE,OAAO,CAAC,WAAW,IAAI,EAAE;QACjD,eAAe,EAAE,wBAAwB,IAAI,EAAE;KAClD,CAAA;AACL,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,OAAe,EAAE,YAA4B;IACpE,IAAI,GAAG,GAAG,OAAO,CAAA;IACjB,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;QACxD,GAAG,GAAG,GAAG,CAAC,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;IACtC,CAAC;IACD,OAAO,GAAG,CAAA;AACd,CAAC;AAED,SAAS,YAAY,CAAC,IAAY;IAC9B,OAAO,IAAI;SACN,KAAK,CAAC,GAAG,CAAC;SACV,MAAM,CAAC,OAAO,CAAC;SACf,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;SAC3E,IAAI,CAAC,EAAE,CAAC,CAAA;AACjB,CAAC;AAED,SAAS,WAAW,CAAC,IAAY;IAC7B,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAA;IACjC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;AAC7D,CAAC"}
|