@keit/create-base 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +98 -0
- package/dist/detect.d.ts +9 -0
- package/dist/detect.d.ts.map +1 -0
- package/dist/detect.js +28 -0
- package/dist/detect.js.map +1 -0
- package/dist/generator.d.ts +4 -0
- package/dist/generator.d.ts.map +1 -0
- package/dist/generator.js +105 -0
- package/dist/generator.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +63 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts.d.ts +26 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +231 -0
- package/dist/prompts.js.map +1 -0
- package/dist/scaffold.d.ts +3 -0
- package/dist/scaffold.d.ts.map +1 -0
- package/dist/scaffold.js +131 -0
- package/dist/scaffold.js.map +1 -0
- package/dist/utils.d.ts +3 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +5 -0
- package/dist/utils.js.map +1 -0
- package/dist/validate.d.ts +2 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +26 -0
- package/dist/validate.js.map +1 -0
- package/package.json +79 -0
- package/templates/library/src/index.ts +6 -0
- package/templates/library/src/lib/example.ts +22 -0
- package/templates/minimal/src/index.ts +10 -0
- package/templates/monorepo/packages/shared/src/index.ts +8 -0
- package/templates/monorepo/pnpm-workspace.yaml +5 -0
- package/templates/rest-api/src/index.ts +27 -0
- package/templates/rest-api/src/middleware/errorHandler.ts +27 -0
- package/templates/rest-api/src/routes/index.ts +15 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2011-2026 The Bootstrap Authors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# @keit/create-base
|
|
2
|
+
|
|
3
|
+
> Interactive CLI to scaffold modern TypeScript/JavaScript projects with Biome, Husky, Commitlint, and more.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
pnpm create @keit/base my-project
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- 🚀 **Multiple templates** — Minimal, REST API (Express), Library
|
|
14
|
+
- 🔧 **Tooling-only mode** — layer the tooling onto an existing project (Next.js, NestJS, etc.)
|
|
15
|
+
- 🌐 **TypeScript or JavaScript** — your choice per project
|
|
16
|
+
- ✅ **Always included** — Biome, Husky, Secretlint, lint-staged, commitlint, dotenv-vault, knip
|
|
17
|
+
- 📋 **Optional** — changelogen (changelog generation)
|
|
18
|
+
- 🔒 **Secure by default** — Secretlint blocks credential commits before they happen
|
|
19
|
+
- 💾 **Git ready** — initialises git, sets remote origin, and makes the first commit automatically
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
### New project
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pnpm create @keit/base my-project
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Add tooling to an existing project
|
|
32
|
+
|
|
33
|
+
Navigate into your existing project first, then run without a folder name:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
cd my-next-app
|
|
37
|
+
pnpm create @keit/base
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
This will add all config files and git hooks without touching your existing source files.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## What gets set up
|
|
45
|
+
|
|
46
|
+
| File | Purpose |
|
|
47
|
+
|---|---|
|
|
48
|
+
| `biome.json` | Formatter + linter (replaces ESLint + Prettier) |
|
|
49
|
+
| `tsconfig.json` | TypeScript configuration (TS projects only) |
|
|
50
|
+
| `.secretlintrc.json` | Blocks leaked credentials from being committed |
|
|
51
|
+
| `commitlint.config.js` | Enforces conventional commit message format |
|
|
52
|
+
| `knip.json` | Detects unused files, exports, and dependencies |
|
|
53
|
+
| `.env.example` | Documents required environment variables |
|
|
54
|
+
| `.gitignore` | Sane defaults for Node.js projects |
|
|
55
|
+
| `.gitattributes` | Forces LF line endings across all platforms |
|
|
56
|
+
| `.husky/pre-commit` | Runs Biome + Secretlint on staged files |
|
|
57
|
+
| `.husky/commit-msg` | Validates commit message format |
|
|
58
|
+
| `.husky/pre-push` | Type-checks before pushing (TS only) |
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Commit format
|
|
63
|
+
|
|
64
|
+
This template enforces [Conventional Commits](https://www.conventionalcommits.org/):
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
<type>(<scope>): <description>
|
|
68
|
+
|
|
69
|
+
feat(auth): add Google OAuth login
|
|
70
|
+
fix(api): handle null response from payment gateway
|
|
71
|
+
chore: update biome to v2.5
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
| Type | When to use |
|
|
75
|
+
|---|---|
|
|
76
|
+
| `feat` | New feature |
|
|
77
|
+
| `fix` | Bug fix |
|
|
78
|
+
| `chore` | Maintenance, deps, config |
|
|
79
|
+
| `docs` | Documentation only |
|
|
80
|
+
| `refactor` | Restructure, no behaviour change |
|
|
81
|
+
| `test` | Adding or fixing tests |
|
|
82
|
+
| `perf` | Performance improvement |
|
|
83
|
+
| `ci` | CI/CD pipeline changes |
|
|
84
|
+
| `style` | Formatting, whitespace |
|
|
85
|
+
| `revert` | Reverting a previous commit |
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Requirements
|
|
90
|
+
|
|
91
|
+
- Node.js >= 20.0.0
|
|
92
|
+
- pnpm >= 11.0.0
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## License
|
|
97
|
+
|
|
98
|
+
[MIT](./LICENSE) © Keit
|
package/dist/detect.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAyBlE"}
|
package/dist/detect.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
export function detectExistingProject(cwd) {
|
|
4
|
+
const pkgPath = join(cwd, "package.json");
|
|
5
|
+
// No package.json found — return empty, prompts will ask everything
|
|
6
|
+
if (!existsSync(pkgPath))
|
|
7
|
+
return {};
|
|
8
|
+
try {
|
|
9
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
10
|
+
const allDeps = {
|
|
11
|
+
...pkg.dependencies,
|
|
12
|
+
...pkg.devDependencies,
|
|
13
|
+
};
|
|
14
|
+
return {
|
|
15
|
+
name: pkg.name,
|
|
16
|
+
description: pkg.description,
|
|
17
|
+
// author can be a string or { name: string }
|
|
18
|
+
author: typeof pkg.author === "string" ? pkg.author : pkg.author?.name,
|
|
19
|
+
license: pkg.license,
|
|
20
|
+
hasTypeScript: "typescript" in allDeps,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// Malformed package.json — treat as empty
|
|
25
|
+
return {};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=detect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect.js","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAWjC,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IAE1C,oEAAoE;IACpE,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,CAAC;IAEpC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QACvD,MAAM,OAAO,GAAG;YACd,GAAG,GAAG,CAAC,YAAY;YACnB,GAAG,GAAG,CAAC,eAAe;SACvB,CAAC;QAEF,OAAO;YACL,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,WAAW,EAAE,GAAG,CAAC,WAAW;YAC5B,6CAA6C;YAC7C,MAAM,EAAE,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI;YACtE,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,aAAa,EAAE,YAAY,IAAI,OAAO;SACvC,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,0CAA0C;QAC1C,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Answers } from "./prompts.js";
|
|
2
|
+
export declare function generateExtraFiles(cwd: string, targetDir: string, answers: Answers): Promise<void>;
|
|
3
|
+
export declare function generateFiles(cwd: string, targetDir: string, answers: Answers, isToolingOnly: boolean): Promise<void>;
|
|
4
|
+
//# sourceMappingURL=generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../src/generator.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AA+C5C,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,iBA4DxF;AAsBD,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,OAAO,iBAKvB"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { copyFileSync, existsSync, mkdirSync, readdirSync, statSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import pc from "picocolors";
|
|
4
|
+
import { isVSCodeEditor } from "./utils.js";
|
|
5
|
+
// Reusable utility to safely replicate file structures recursively
|
|
6
|
+
async function copyFiles(items, sourceDir, targetDir) {
|
|
7
|
+
let fileCount = 0;
|
|
8
|
+
items.forEach((item) => {
|
|
9
|
+
try {
|
|
10
|
+
const sourcePath = join(sourceDir, item);
|
|
11
|
+
const destinationPath = join(targetDir, item);
|
|
12
|
+
// Only act on files, skipping directories naturally
|
|
13
|
+
if (statSync(sourcePath).isFile()) {
|
|
14
|
+
const destDirname = dirname(destinationPath);
|
|
15
|
+
// Ensure parent directory exists before writing
|
|
16
|
+
if (!existsSync(destDirname)) {
|
|
17
|
+
mkdirSync(destDirname, { recursive: true });
|
|
18
|
+
}
|
|
19
|
+
copyFileSync(sourcePath, destinationPath);
|
|
20
|
+
console.log(` ${pc.green("✓")} Copied file: ${pc.dim(item)}`);
|
|
21
|
+
fileCount++;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
console.error(pc.red(`✖ Resolution error during structural asset sync: ${item}`), error);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
if (fileCount > 0) {
|
|
30
|
+
console.log(pc.dim(` Synced ${fileCount} target asset files cleanly.`));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async function generateBaseFiles(cwd, targetDir) {
|
|
34
|
+
console.log(pc.cyan("📁 Cloning baseline environmental layouts..."));
|
|
35
|
+
const baseDir = join(cwd, "base");
|
|
36
|
+
if (!existsSync(baseDir))
|
|
37
|
+
return;
|
|
38
|
+
const baseItems = readdirSync(baseDir, { recursive: true });
|
|
39
|
+
console.log(`BaseDir: ${baseDir}; targetDir: ${targetDir}`);
|
|
40
|
+
await copyFiles(baseItems, baseDir, targetDir);
|
|
41
|
+
}
|
|
42
|
+
export async function generateExtraFiles(cwd, targetDir, answers) {
|
|
43
|
+
const isTypeScript = answers.language === "typescript";
|
|
44
|
+
const hasEditor = answers.editor !== "none";
|
|
45
|
+
const hasOptionalLibs = answers.extras && answers.extras.length > 0;
|
|
46
|
+
if (!isTypeScript && !hasEditor && !hasOptionalLibs) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
console.log(pc.cyan("🧩 Injecting contextual development tooling variations..."));
|
|
50
|
+
const extrasDir = join(cwd, "extras");
|
|
51
|
+
// - TypeScript Configs -
|
|
52
|
+
if (isTypeScript) {
|
|
53
|
+
console.log(pc.dim(" Applying explicit structural TypeScript configurations..."));
|
|
54
|
+
const tsDir = answers.template === "library"
|
|
55
|
+
? join(extrasDir, "typescript-lib")
|
|
56
|
+
: join(extrasDir, "typescript-base");
|
|
57
|
+
if (existsSync(tsDir)) {
|
|
58
|
+
const tsItems = readdirSync(tsDir, { recursive: true });
|
|
59
|
+
await copyFiles(tsItems, tsDir, targetDir);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// - Editor Profiles -
|
|
63
|
+
if (hasEditor) {
|
|
64
|
+
console.log(pc.dim(` Generating workspace rulesets targeting editor environment: ${answers.editor}...`));
|
|
65
|
+
const editorsDir = join(extrasDir, "editors");
|
|
66
|
+
const isVSCodeConfig = isVSCodeEditor(answers.editor);
|
|
67
|
+
const editorDir = isVSCodeConfig
|
|
68
|
+
? join(editorsDir, "vscode")
|
|
69
|
+
: answers.editor === "zed"
|
|
70
|
+
? join(editorsDir, "zed")
|
|
71
|
+
: null;
|
|
72
|
+
if (editorDir && existsSync(editorDir)) {
|
|
73
|
+
const editorItems = readdirSync(editorDir, { recursive: true });
|
|
74
|
+
await copyFiles(editorItems, editorDir, targetDir);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// - Optional Packages -
|
|
78
|
+
if (hasOptionalLibs) {
|
|
79
|
+
for (const extra of answers.extras) {
|
|
80
|
+
console.log(pc.dim(` Configuring optional runtime ecosystem plug-in: ${extra}...`));
|
|
81
|
+
const extraDir = join(extrasDir, extra);
|
|
82
|
+
if (existsSync(extraDir)) {
|
|
83
|
+
const extraItems = readdirSync(extraDir, { recursive: true });
|
|
84
|
+
await copyFiles(extraItems, extraDir, targetDir);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async function generateTemplateFiles(cwd, targetDir, answers, isToolingOnly) {
|
|
90
|
+
// We only scaffold source code if it is a brand new project.
|
|
91
|
+
if (!isToolingOnly) {
|
|
92
|
+
console.log(pc.cyan(`📦 Generating functional codebase matching template: ${answers.template}...`));
|
|
93
|
+
const templateDir = join(cwd, "templates", answers.template);
|
|
94
|
+
if (existsSync(templateDir)) {
|
|
95
|
+
const templateItems = readdirSync(templateDir, { recursive: true });
|
|
96
|
+
await copyFiles(templateItems, templateDir, targetDir);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
export async function generateFiles(cwd, targetDir, answers, isToolingOnly) {
|
|
101
|
+
await generateBaseFiles(cwd, targetDir);
|
|
102
|
+
await generateExtraFiles(cwd, targetDir, answers);
|
|
103
|
+
await generateTemplateFiles(cwd, targetDir, answers, isToolingOnly);
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../src/generator.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { existsSync, mkdirSync } from "node:fs";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import minimist from "minimist";
|
|
6
|
+
import pc from "picocolors";
|
|
7
|
+
import { detectExistingProject } from "./detect.js";
|
|
8
|
+
import { generateFiles } from "./generator.js";
|
|
9
|
+
import { runPrompts } from "./prompts.js";
|
|
10
|
+
import { scaffoldProjectMetadata } from "./scaffold.js";
|
|
11
|
+
import { validateArgv } from "./validate.js";
|
|
12
|
+
const argv = minimist(process.argv.slice(2), {
|
|
13
|
+
string: ["template", "language", "description", "author", "license", "git-remote", "editor"],
|
|
14
|
+
alias: {
|
|
15
|
+
t: "template",
|
|
16
|
+
l: "language",
|
|
17
|
+
d: "description",
|
|
18
|
+
a: "author",
|
|
19
|
+
e: "editor",
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
validateArgv(argv);
|
|
23
|
+
async function main() {
|
|
24
|
+
const projectArg = argv._[0];
|
|
25
|
+
const isCurrentFolder = !projectArg || projectArg === ".";
|
|
26
|
+
const executionDir = process.cwd();
|
|
27
|
+
const cliDir = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
28
|
+
console.log();
|
|
29
|
+
console.log(pc.bold(pc.cyan("@keit/create-base")));
|
|
30
|
+
console.log(pc.dim("Modern TypeScript/JavaScript project scaffolder"));
|
|
31
|
+
console.log();
|
|
32
|
+
const detected = isCurrentFolder ? detectExistingProject(executionDir) : {};
|
|
33
|
+
const answers = await runPrompts(isCurrentFolder, projectArg, argv, detected);
|
|
34
|
+
const isToolingOnly = isCurrentFolder && answers.folderPurpose === "existing";
|
|
35
|
+
const targetDir = isCurrentFolder ? executionDir : resolve(executionDir, answers.projectName);
|
|
36
|
+
if (isToolingOnly) {
|
|
37
|
+
console.log(pc.yellow("Running in tooling-only mode for an existing project."));
|
|
38
|
+
console.log(pc.dim(`Adding configurations to: ${targetDir}`));
|
|
39
|
+
console.log();
|
|
40
|
+
}
|
|
41
|
+
if (!isCurrentFolder) {
|
|
42
|
+
if (existsSync(targetDir)) {
|
|
43
|
+
console.log(pc.red(`✖ Folder "${answers.projectName}" already exists.`));
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
mkdirSync(targetDir, { recursive: true });
|
|
47
|
+
console.log(pc.green(`✔ Created folder: ${answers.projectName}`));
|
|
48
|
+
console.log();
|
|
49
|
+
}
|
|
50
|
+
console.log(pc.dim("Scaffolding project..."));
|
|
51
|
+
console.log();
|
|
52
|
+
await generateFiles(cliDir, targetDir, answers, isToolingOnly);
|
|
53
|
+
await scaffoldProjectMetadata(targetDir, answers, isToolingOnly);
|
|
54
|
+
console.log();
|
|
55
|
+
console.log(pc.bold(pc.green("🚀 Execution phase completed cleanly!")));
|
|
56
|
+
console.log(pc.dim(`Your environment workspace is ready at: ${targetDir}`));
|
|
57
|
+
console.log();
|
|
58
|
+
}
|
|
59
|
+
main().catch((err) => {
|
|
60
|
+
console.error(pc.red("Something went wrong:"), err);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
});
|
|
63
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { DetectedProject } from "./detect.js";
|
|
2
|
+
export type Language = "typescript" | "javascript";
|
|
3
|
+
export type Template = "minimal" | "rest-api" | "library" | "monorepo";
|
|
4
|
+
export type Editor = "vscode" | "cursor" | "windsurf" | "zed" | "none";
|
|
5
|
+
export type FolderPurpose = "new" | "existing";
|
|
6
|
+
export interface Answers {
|
|
7
|
+
projectName: string;
|
|
8
|
+
description: string;
|
|
9
|
+
author: string;
|
|
10
|
+
license: string;
|
|
11
|
+
language: Language;
|
|
12
|
+
template: Template;
|
|
13
|
+
extras: string[];
|
|
14
|
+
gitRemote: string;
|
|
15
|
+
editor: Editor;
|
|
16
|
+
folderPurpose?: FolderPurpose;
|
|
17
|
+
}
|
|
18
|
+
export declare const vscodeFamily: readonly ["vscode", "cursor", "windsurf"];
|
|
19
|
+
export declare const VALID_VALUES: {
|
|
20
|
+
readonly template: readonly ["minimal", "rest-api", "library", "monorepo"];
|
|
21
|
+
readonly language: readonly ["typescript", "javascript"];
|
|
22
|
+
readonly editor: readonly ["vscode", "cursor", "windsurf", "zed", "none"];
|
|
23
|
+
readonly license: readonly ["MIT", "ISC", "Apache-2.0", "UNLICENSED"];
|
|
24
|
+
};
|
|
25
|
+
export declare function runPrompts(isCurrentFolder: boolean, projectArg: string | undefined, argv: Record<string, string>, detected?: DetectedProject): Promise<Answers>;
|
|
26
|
+
//# sourceMappingURL=prompts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAInD,MAAM,MAAM,QAAQ,GAAG,YAAY,GAAG,YAAY,CAAC;AACnD,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,CAAC;AACvE,MAAM,MAAM,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,KAAK,GAAG,MAAM,CAAC;AACvE,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,UAAU,CAAC;AAE/C,MAAM,WAAW,OAAO;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAKD,eAAO,MAAM,YAAY,2CAA4C,CAAC;AAEtE,eAAO,MAAM,YAAY;;;;;CAKf,CAAC;AAIX,wBAAsB,UAAU,CAC9B,eAAe,EAAE,OAAO,EACxB,UAAU,EAAE,MAAM,GAAG,SAAS,EAE9B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAE5B,QAAQ,GAAE,eAAoB,GAC7B,OAAO,CAAC,OAAO,CAAC,CAuOlB"}
|
package/dist/prompts.js
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import pc from "picocolors";
|
|
2
|
+
import prompts from "prompts";
|
|
3
|
+
// ── Allowed values for CLI flag validation ────────────────────────────────────
|
|
4
|
+
// Single source of truth — imported by validate.ts so the two never drift apart
|
|
5
|
+
export const vscodeFamily = ["vscode", "cursor", "windsurf"];
|
|
6
|
+
export const VALID_VALUES = {
|
|
7
|
+
template: ["minimal", "rest-api", "library", "monorepo"],
|
|
8
|
+
language: ["typescript", "javascript"],
|
|
9
|
+
editor: [...vscodeFamily, "zed", "none"],
|
|
10
|
+
license: ["MIT", "ISC", "Apache-2.0", "UNLICENSED"],
|
|
11
|
+
};
|
|
12
|
+
// ── Prompt runner ─────────────────────────────────────────────────────────────
|
|
13
|
+
export async function runPrompts(isCurrentFolder, projectArg,
|
|
14
|
+
// CLI flags parsed by minimist (e.g. --template rest-api)
|
|
15
|
+
argv,
|
|
16
|
+
// Data detected from an existing package.json (empty object for new projects)
|
|
17
|
+
detected = {}) {
|
|
18
|
+
// Exit cleanly on Ctrl+C instead of throwing an unhandled rejection
|
|
19
|
+
const onCancel = () => {
|
|
20
|
+
console.log();
|
|
21
|
+
console.log(pc.red("✖ Cancelled."));
|
|
22
|
+
process.exit(0);
|
|
23
|
+
};
|
|
24
|
+
const answers = await prompts([
|
|
25
|
+
// ── Folder purpose ─────────────────────────────────────────────────────
|
|
26
|
+
{
|
|
27
|
+
// Only shown when no folder argument was given (i.e. the user ran the
|
|
28
|
+
// CLI inside an existing directory). Determines whether to scaffold a
|
|
29
|
+
// fresh project or just layer tooling configs onto what's already there.
|
|
30
|
+
type: isCurrentFolder ? "select" : null,
|
|
31
|
+
name: "folderPurpose",
|
|
32
|
+
message: "The target directory is the current folder. Is this for:",
|
|
33
|
+
choices: [
|
|
34
|
+
{ title: "A new project (initialize from scratch)", value: "new" },
|
|
35
|
+
{ title: "An existing project (add tooling configurations only)", value: "existing" },
|
|
36
|
+
],
|
|
37
|
+
initial: 0,
|
|
38
|
+
},
|
|
39
|
+
// ── Project identity ───────────────────────────────────────────────────
|
|
40
|
+
{
|
|
41
|
+
// Skipped when:
|
|
42
|
+
// • a folder name was passed as a positional argument, OR
|
|
43
|
+
// • the user chose "existing" (name is read from package.json instead)
|
|
44
|
+
type: (_prev, values) => {
|
|
45
|
+
if (!isCurrentFolder && projectArg && projectArg !== ".")
|
|
46
|
+
return null;
|
|
47
|
+
if (values.folderPurpose === "existing")
|
|
48
|
+
return null;
|
|
49
|
+
return "text";
|
|
50
|
+
},
|
|
51
|
+
name: "projectName",
|
|
52
|
+
message: "Project name:",
|
|
53
|
+
// Pre-fill with the detected package name if available
|
|
54
|
+
initial: detected.name ?? "my-project",
|
|
55
|
+
validate: (v) => (v.trim().length > 0 ? true : "Project name cannot be empty."),
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
// Skipped when:
|
|
59
|
+
// • --description flag was passed, OR
|
|
60
|
+
// • existing project (description read from package.json)
|
|
61
|
+
type: (_prev, values) => argv.description || values.folderPurpose === "existing" ? null : "text",
|
|
62
|
+
name: "description",
|
|
63
|
+
message: "Description:",
|
|
64
|
+
// Pre-fill from detected package.json if available
|
|
65
|
+
initial: detected.description ?? "",
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
// Skipped when:
|
|
69
|
+
// • --author flag was passed, OR
|
|
70
|
+
// • existing project (author read from package.json)
|
|
71
|
+
type: (_prev, values) => argv.author || values.folderPurpose === "existing" ? null : "text",
|
|
72
|
+
name: "author",
|
|
73
|
+
message: "Author:",
|
|
74
|
+
// Pre-fill from detected package.json if available
|
|
75
|
+
initial: detected.author ?? "",
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
// Skipped when:
|
|
79
|
+
// • --license flag was passed, OR
|
|
80
|
+
// • existing project (license read from package.json)
|
|
81
|
+
type: (_prev, values) => argv.license || values.folderPurpose === "existing" ? null : "select",
|
|
82
|
+
name: "license",
|
|
83
|
+
message: "License:",
|
|
84
|
+
choices: [
|
|
85
|
+
{ title: "MIT", value: "MIT" },
|
|
86
|
+
{ title: "ISC", value: "ISC" },
|
|
87
|
+
{ title: "Apache-2.0", value: "Apache-2.0" },
|
|
88
|
+
{ title: "Unlicensed", value: "UNLICENSED" },
|
|
89
|
+
],
|
|
90
|
+
// Pre-select the matching license if one was detected in package.json
|
|
91
|
+
initial: detected.license
|
|
92
|
+
? Math.max(0, ["MIT", "ISC", "Apache-2.0", "UNLICENSED"].indexOf(detected.license))
|
|
93
|
+
: 0,
|
|
94
|
+
},
|
|
95
|
+
// ── Project setup ──────────────────────────────────────────────────────
|
|
96
|
+
{
|
|
97
|
+
// Skipped when:
|
|
98
|
+
// • --language flag was passed, OR
|
|
99
|
+
// • existing project (language auto-detected from dependencies)
|
|
100
|
+
type: (_prev, values) => argv.language || values.folderPurpose === "existing" ? null : "select",
|
|
101
|
+
name: "language",
|
|
102
|
+
message: "Language:",
|
|
103
|
+
choices: [
|
|
104
|
+
{ title: "TypeScript", value: "typescript" },
|
|
105
|
+
{ title: "JavaScript", value: "javascript" },
|
|
106
|
+
],
|
|
107
|
+
// Pre-select TypeScript unless detect explicitly found no TypeScript dep
|
|
108
|
+
initial: detected.hasTypeScript === false ? 1 : 0,
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
// Skipped when:
|
|
112
|
+
// • --template flag was passed, OR
|
|
113
|
+
// • existing project (no template needed, only tooling is added)
|
|
114
|
+
type: (_prev, values) => argv.template || values.folderPurpose === "existing" ? null : "select",
|
|
115
|
+
name: "template",
|
|
116
|
+
message: "Template:",
|
|
117
|
+
choices: [
|
|
118
|
+
{
|
|
119
|
+
title: "Minimal",
|
|
120
|
+
value: "minimal",
|
|
121
|
+
description: "Blank Node.js app — bots, scripts, servers",
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
title: "REST API",
|
|
125
|
+
value: "rest-api",
|
|
126
|
+
description: "Express + basic routing structure",
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
title: "Library",
|
|
130
|
+
value: "library",
|
|
131
|
+
description: "npm-publishable package with exports and type declarations",
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
title: "Monorepo",
|
|
135
|
+
value: "monorepo",
|
|
136
|
+
description: "pnpm workspaces — Next.js + NestJS apps",
|
|
137
|
+
},
|
|
138
|
+
],
|
|
139
|
+
initial: 0,
|
|
140
|
+
},
|
|
141
|
+
// ── Editor ────────────────────────────────────────────────────────────
|
|
142
|
+
{
|
|
143
|
+
// Skipped when --editor flag was passed.
|
|
144
|
+
// The selected value determines which config directory gets generated:
|
|
145
|
+
// vscode / cursor / windsurf → .vscode/settings.json
|
|
146
|
+
// zed → .zed/settings.json
|
|
147
|
+
// none → no editor config (docs link printed instead)
|
|
148
|
+
type: argv.editor ? null : "select",
|
|
149
|
+
name: "editor",
|
|
150
|
+
message: "Editor / IDE:",
|
|
151
|
+
choices: [
|
|
152
|
+
{
|
|
153
|
+
title: "VS Code",
|
|
154
|
+
value: "vscode",
|
|
155
|
+
description: "Creates .vscode/settings.json",
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
title: "Cursor",
|
|
159
|
+
value: "cursor",
|
|
160
|
+
description: "Creates .vscode/settings.json",
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
title: "Windsurf",
|
|
164
|
+
value: "windsurf",
|
|
165
|
+
description: "Creates .vscode/settings.json",
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
title: "Zed",
|
|
169
|
+
value: "zed",
|
|
170
|
+
description: "Creates .zed/settings.json",
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
title: "None / Skip",
|
|
174
|
+
value: "none",
|
|
175
|
+
description: "No editor config — Biome docs link printed instead",
|
|
176
|
+
},
|
|
177
|
+
],
|
|
178
|
+
initial: 0,
|
|
179
|
+
},
|
|
180
|
+
// ── Optional extras ────────────────────────────────────────────────────
|
|
181
|
+
{
|
|
182
|
+
// Always shown. Space to toggle, Enter to confirm.
|
|
183
|
+
// Selected values are installed as devDependencies by the generator.
|
|
184
|
+
type: "multiselect",
|
|
185
|
+
name: "extras",
|
|
186
|
+
message: "Optional extras:",
|
|
187
|
+
choices: [
|
|
188
|
+
{
|
|
189
|
+
title: "changelogen",
|
|
190
|
+
value: "changelogen",
|
|
191
|
+
description: "Auto-generate CHANGELOG.md from conventional commits",
|
|
192
|
+
selected: true,
|
|
193
|
+
},
|
|
194
|
+
],
|
|
195
|
+
},
|
|
196
|
+
// ── Git remote ─────────────────────────────────────────────────────────
|
|
197
|
+
{
|
|
198
|
+
// Skipped when:
|
|
199
|
+
// • --git-remote flag was passed, OR
|
|
200
|
+
// • existing project (already has a git remote set up)
|
|
201
|
+
// Leave blank to skip — git remote add origin will not be run.
|
|
202
|
+
type: (_prev, values) => argv["git-remote"] || values.folderPurpose === "existing" ? null : "text",
|
|
203
|
+
name: "gitRemote",
|
|
204
|
+
message: "Git remote URL (leave blank to skip):",
|
|
205
|
+
initial: "",
|
|
206
|
+
},
|
|
207
|
+
], { onCancel });
|
|
208
|
+
// ── Resolve values for existing projects ───────────────────────────────────
|
|
209
|
+
// When folderPurpose === "existing", identity prompts were skipped entirely.
|
|
210
|
+
// We fall back to whatever was read from the existing package.json.
|
|
211
|
+
const isExisting = answers.folderPurpose === "existing";
|
|
212
|
+
// Fallback project name: positional arg → detected name → "my-project"
|
|
213
|
+
const fallbackName = projectArg && projectArg !== "." ? projectArg : (detected.name ?? "my-project");
|
|
214
|
+
// ── Merge: CLI flag > prompt answer > detected value > hardcoded default ──
|
|
215
|
+
return {
|
|
216
|
+
projectName: answers.projectName ?? fallbackName,
|
|
217
|
+
description: argv.description ?? answers.description ?? detected.description ?? "",
|
|
218
|
+
author: argv.author ?? answers.author ?? detected.author ?? "",
|
|
219
|
+
license: argv.license ?? answers.license ?? detected.license ?? "MIT",
|
|
220
|
+
language: argv.language ??
|
|
221
|
+
answers.language ??
|
|
222
|
+
// For existing projects, infer language from detected deps
|
|
223
|
+
(isExisting ? (detected.hasTypeScript ? "typescript" : "javascript") : "typescript"),
|
|
224
|
+
template: argv.template ?? answers.template ?? "minimal",
|
|
225
|
+
editor: argv.editor ?? answers.editor ?? "vscode",
|
|
226
|
+
extras: answers.extras ?? [],
|
|
227
|
+
gitRemote: argv["git-remote"] ?? answers.gitRemote ?? "",
|
|
228
|
+
folderPurpose: answers.folderPurpose,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
//# 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 @@
|
|
|
1
|
+
{"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AA4H5C,wBAAsB,uBAAuB,CAC3C,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,OAAO,GACrB,OAAO,CAAC,IAAI,CAAC,CA4Bf"}
|
package/dist/scaffold.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import pc from "picocolors";
|
|
5
|
+
function buildPackageJson(answers) {
|
|
6
|
+
const basePkg = {
|
|
7
|
+
name: answers.projectName,
|
|
8
|
+
version: "0.1.0",
|
|
9
|
+
description: answers.description,
|
|
10
|
+
author: answers.author,
|
|
11
|
+
license: answers.license,
|
|
12
|
+
type: "module",
|
|
13
|
+
scripts: {
|
|
14
|
+
format: "biome format --write .",
|
|
15
|
+
lint: "biome lint .",
|
|
16
|
+
check: "biome check --write .",
|
|
17
|
+
prepare: "husky",
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
const devDependencies = {
|
|
21
|
+
"@biomejs/biome": "^2.5.0",
|
|
22
|
+
"@commitlint/cli": "^21.0.2",
|
|
23
|
+
"@commitlint/config-conventional": "^21.0.2",
|
|
24
|
+
"@secretlint/secretlint-rule-preset-recommend": "^13.0.2",
|
|
25
|
+
"dotenv-vault": "^1.27.0",
|
|
26
|
+
husky: "^9.1.7",
|
|
27
|
+
knip: "^6.16.1",
|
|
28
|
+
"lint-staged": "^17.0.7",
|
|
29
|
+
secretlint: "^13.0.2",
|
|
30
|
+
};
|
|
31
|
+
if (answers.language === "typescript") {
|
|
32
|
+
devDependencies["typescript"] = "^6.0.3";
|
|
33
|
+
devDependencies["@types/node"] = "^25.9.3";
|
|
34
|
+
basePkg.scripts.typecheck = "tsc --noEmit";
|
|
35
|
+
if (answers.template === "library") {
|
|
36
|
+
basePkg.scripts.build = "tsc";
|
|
37
|
+
basePkg.scripts.dev = "tsc --watch";
|
|
38
|
+
basePkg.scripts.start = "node dist/index.js";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (answers.extras.includes("changelogen")) {
|
|
42
|
+
devDependencies["changelogen"] = "^0.6.2";
|
|
43
|
+
basePkg.scripts.release = "changelogen --release";
|
|
44
|
+
}
|
|
45
|
+
basePkg.devDependencies = devDependencies;
|
|
46
|
+
return JSON.stringify(basePkg, null, 2);
|
|
47
|
+
}
|
|
48
|
+
function mergeExistingPackageJson(targetDir, answers) {
|
|
49
|
+
const pkgPath = join(targetDir, "package.json");
|
|
50
|
+
const rawData = readFileSync(pkgPath, "utf-8");
|
|
51
|
+
const pkg = JSON.parse(rawData);
|
|
52
|
+
pkg.scripts = {
|
|
53
|
+
...pkg.scripts,
|
|
54
|
+
format: pkg.scripts?.format ?? "biome format --write .",
|
|
55
|
+
lint: pkg.scripts?.lint ?? "biome lint .",
|
|
56
|
+
check: pkg.scripts?.check ?? "biome check --write .",
|
|
57
|
+
prepare: pkg.scripts?.prepare ?? "husky",
|
|
58
|
+
};
|
|
59
|
+
if (answers.language === "typescript" && !pkg.scripts.typecheck) {
|
|
60
|
+
pkg.scripts.typecheck = "tsc --noEmit";
|
|
61
|
+
}
|
|
62
|
+
if (answers.extras.includes("changelogen")) {
|
|
63
|
+
pkg.scripts.release = pkg.scripts.release ?? "changelogen --release";
|
|
64
|
+
}
|
|
65
|
+
pkg.devDependencies = {
|
|
66
|
+
...pkg.devDependencies,
|
|
67
|
+
"@biomejs/biome": "^2.5.0",
|
|
68
|
+
"@commitlint/cli": "^21.0.2",
|
|
69
|
+
"@commitlint/config-conventional": "^21.0.2",
|
|
70
|
+
"@secretlint/secretlint-rule-preset-recommend": "^13.0.2",
|
|
71
|
+
"dotenv-vault": "^1.27.0",
|
|
72
|
+
husky: "^9.1.7",
|
|
73
|
+
knip: "^6.16.1",
|
|
74
|
+
"lint-staged": "^17.0.7",
|
|
75
|
+
secretlint: "^13.0.2",
|
|
76
|
+
};
|
|
77
|
+
if (answers.language === "typescript") {
|
|
78
|
+
pkg.devDependencies["typescript"] = pkg.devDependencies["typescript"] || "^6.0.3";
|
|
79
|
+
pkg.devDependencies["@types/node"] = pkg.devDependencies["@types/node"] || "^25.9.3";
|
|
80
|
+
}
|
|
81
|
+
if (answers.extras.includes("changelogen")) {
|
|
82
|
+
pkg.devDependencies["changelogen"] = pkg.devDependencies["changelogen"] || "^0.6.2";
|
|
83
|
+
}
|
|
84
|
+
return JSON.stringify(pkg, null, 2);
|
|
85
|
+
}
|
|
86
|
+
function buildReadme(answers) {
|
|
87
|
+
return `# ${answers.projectName}
|
|
88
|
+
|
|
89
|
+
> ${answers.description || "Scaffolded with @keit/create-base"}
|
|
90
|
+
|
|
91
|
+
## Development Scripts
|
|
92
|
+
|
|
93
|
+
- \`pnpm run check\` - Run full formatting, linting, and diagnostics via Biome
|
|
94
|
+
- \`pnpm run prepare\` - Setup local Git hardware hooks via Husky
|
|
95
|
+
${answers.language === "typescript" ? "- `pnpm run typecheck` - Validate explicit structural types\n" : ""}`;
|
|
96
|
+
}
|
|
97
|
+
function buildLicense(answers) {
|
|
98
|
+
const year = new Date().getFullYear();
|
|
99
|
+
const authorText = answers.author || "Contributors";
|
|
100
|
+
if (answers.license === "MIT") {
|
|
101
|
+
return `MIT License\n\nCopyright (c) ${year} ${authorText}\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.`;
|
|
102
|
+
}
|
|
103
|
+
if (answers.license === "UNLICENSED") {
|
|
104
|
+
return `Copyright (c) ${year} ${authorText}. All rights reserved.\nUnauthorized copying, modification, or distribution via any medium is strictly prohibited.\nProprietary and confidential.`;
|
|
105
|
+
}
|
|
106
|
+
return `${answers.license} License\n\nCopyright (c) ${year} ${authorText}`;
|
|
107
|
+
}
|
|
108
|
+
export async function scaffoldProjectMetadata(targetDir, answers, isToolingOnly) {
|
|
109
|
+
console.log(pc.cyan("⚙ Generating structural project configuration..."));
|
|
110
|
+
if (isToolingOnly && existsSync(join(targetDir, "package.json"))) {
|
|
111
|
+
console.log(pc.dim(" Merging tool chains into existing package.json..."));
|
|
112
|
+
writeFileSync(join(targetDir, "package.json"), mergeExistingPackageJson(targetDir, answers), "utf-8");
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
console.log(pc.dim(" Writing fresh package.json, README.md, and LICENSE..."));
|
|
116
|
+
writeFileSync(join(targetDir, "package.json"), buildPackageJson(answers), "utf-8");
|
|
117
|
+
writeFileSync(join(targetDir, "README.md"), buildReadme(answers), "utf-8");
|
|
118
|
+
writeFileSync(join(targetDir, "LICENSE"), buildLicense(answers), "utf-8");
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
console.log(pc.cyan("📦 Running dependency resolution step..."));
|
|
122
|
+
console.log(pc.dim(" Invoking pnpm install..."));
|
|
123
|
+
execSync("pnpm install", { cwd: targetDir, stdio: "inherit" });
|
|
124
|
+
console.log(`${pc.green("✔")} Manifest assets synced successfully.`);
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
console.error(pc.red("✖ External subprocess resolution via pnpm failed."), error);
|
|
128
|
+
process.exit(1);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=scaffold.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"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"}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAEtF"}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,OAAQ,YAAkC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC9D,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAOA,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAsB/D"}
|
package/dist/validate.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import pc from "picocolors";
|
|
2
|
+
import { VALID_VALUES } from "./prompts.js";
|
|
3
|
+
// ── CLI flag validator ────────────────────────────────────────────────────────
|
|
4
|
+
// Runs before prompts so invalid flags are caught immediately with a clear
|
|
5
|
+
// error message instead of silently passing wrong values into the generator.
|
|
6
|
+
export function validateArgv(argv) {
|
|
7
|
+
let hasError = false;
|
|
8
|
+
// VALID_VALUES is the single source of truth — defined in prompts.ts and
|
|
9
|
+
// reused here so the two never drift out of sync
|
|
10
|
+
for (const [flag, allowed] of Object.entries(VALID_VALUES)) {
|
|
11
|
+
const value = argv[flag];
|
|
12
|
+
// Skip flags that weren't passed at all
|
|
13
|
+
if (!value)
|
|
14
|
+
continue;
|
|
15
|
+
if (!allowed.includes(value)) {
|
|
16
|
+
console.log(pc.red(`✖ Invalid --${flag} value: "${value}"`));
|
|
17
|
+
console.log(pc.dim(` Allowed: ${allowed.join(", ")}`));
|
|
18
|
+
hasError = true;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (hasError) {
|
|
22
|
+
console.log();
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,iFAAiF;AACjF,2EAA2E;AAC3E,6EAA6E;AAE7E,MAAM,UAAU,YAAY,CAAC,IAA4B;IACvD,IAAI,QAAQ,GAAG,KAAK,CAAC;IAErB,yEAAyE;IACzE,iDAAiD;IACjD,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;QAC3D,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;QAEzB,wCAAwC;QACxC,IAAI,CAAC,KAAK;YAAE,SAAS;QAErB,IAAI,CAAE,OAA6B,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACpD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,eAAe,IAAI,YAAY,KAAK,GAAG,CAAC,CAAC,CAAC;YAC7D,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,cAAe,OAA6B,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YAC/E,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@keit/create-base",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Interactive CLI to scaffold modern TypeScript/JavaScript projects with Biome, Husky, Commitlint, and more",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"create",
|
|
7
|
+
"scaffold",
|
|
8
|
+
"template",
|
|
9
|
+
"typescript",
|
|
10
|
+
"javascript",
|
|
11
|
+
"biome",
|
|
12
|
+
"husky",
|
|
13
|
+
"commitlint",
|
|
14
|
+
"starter",
|
|
15
|
+
"boilerplate"
|
|
16
|
+
],
|
|
17
|
+
"author": "Keit",
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"type": "module",
|
|
20
|
+
"main": "./dist/index.js",
|
|
21
|
+
"bin": {
|
|
22
|
+
"create-base": "./dist/index.js"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist",
|
|
26
|
+
"templates"
|
|
27
|
+
],
|
|
28
|
+
"lint-staged": {
|
|
29
|
+
"*.{js,ts,jsx,tsx,json,css}": "biome check --write --no-errors-on-unmatched",
|
|
30
|
+
"*": "secretlint --secretlintignore .gitignore"
|
|
31
|
+
},
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=20.0.0",
|
|
34
|
+
"pnpm": ">=11.0.0"
|
|
35
|
+
},
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "https://github.com/Keit32/create-base"
|
|
39
|
+
},
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/Keit32/create-base/issues"
|
|
42
|
+
},
|
|
43
|
+
"homepage": "https://github.com/Keit32/create-base#readme",
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"execa": "^9.6.1",
|
|
49
|
+
"minimist": "^1.2.8",
|
|
50
|
+
"picocolors": "^1.1.1",
|
|
51
|
+
"prompts": "^2.4.2"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@biomejs/biome": "^2.5.0",
|
|
55
|
+
"@commitlint/cli": "^21.0.2",
|
|
56
|
+
"@commitlint/config-conventional": "^21.0.2",
|
|
57
|
+
"@secretlint/secretlint-rule-preset-recommend": "^13.0.2",
|
|
58
|
+
"@types/minimist": "^1.2.5",
|
|
59
|
+
"@types/node": "^25.9.3",
|
|
60
|
+
"@types/prompts": "^2.4.9",
|
|
61
|
+
"changelogen": "^0.6.2",
|
|
62
|
+
"dotenv-vault": "^1.27.0",
|
|
63
|
+
"husky": "^9.1.7",
|
|
64
|
+
"knip": "^6.16.1",
|
|
65
|
+
"lint-staged": "^17.0.7",
|
|
66
|
+
"secretlint": "^13.0.2",
|
|
67
|
+
"typescript": "^6.0.3"
|
|
68
|
+
},
|
|
69
|
+
"scripts": {
|
|
70
|
+
"build": "tsc",
|
|
71
|
+
"dev": "tsc --watch",
|
|
72
|
+
"start": "node dist/index.js",
|
|
73
|
+
"typecheck": "tsc --noEmit",
|
|
74
|
+
"format": "biome format --write .",
|
|
75
|
+
"lint": "biome lint .",
|
|
76
|
+
"check": "biome check --write .",
|
|
77
|
+
"release": "changelogen --release"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// ── Public API ────────────────────────────────────────────────────────────────
|
|
2
|
+
// Everything exported from here is available to consumers of this package.
|
|
3
|
+
// Be intentional — only export what you want to be part of your public API.
|
|
4
|
+
|
|
5
|
+
export type { GreetOptions } from "./lib/example.js";
|
|
6
|
+
export { greet } from "./lib/example.js";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// ── Example module ────────────────────────────────────────────────────────────
|
|
2
|
+
// Replace this with your actual library code.
|
|
3
|
+
// This file shows the recommended pattern: types + implementation in one module,
|
|
4
|
+
// exported cleanly through src/index.ts.
|
|
5
|
+
|
|
6
|
+
export interface GreetOptions {
|
|
7
|
+
/** Name to greet */
|
|
8
|
+
name: string;
|
|
9
|
+
/** Optional greeting prefix. Defaults to "Hello" */
|
|
10
|
+
prefix?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Returns a greeting string.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* greet({ name: "world" }) // "Hello, world!"
|
|
18
|
+
* greet({ name: "world", prefix: "Hi" }) // "Hi, world!"
|
|
19
|
+
*/
|
|
20
|
+
export function greet({ name, prefix = "Hello" }: GreetOptions): string {
|
|
21
|
+
return `${prefix}, ${name}!`;
|
|
22
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// ── Shared package ────────────────────────────────────────────────────────────
|
|
2
|
+
// Code exported from here is available to all apps in the monorepo:
|
|
3
|
+
//
|
|
4
|
+
// import { something } from "@__PROJECT_NAME__/shared"
|
|
5
|
+
//
|
|
6
|
+
// Add shared types, utilities, constants, and validation schemas here.
|
|
7
|
+
|
|
8
|
+
export const PROJECT_NAME = "__PROJECT_NAME__";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import "dotenv-vault/config";
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
import express from "express";
|
|
4
|
+
import { errorHandler } from "./middleware/errorHandler.js";
|
|
5
|
+
import { router } from "./routes/index.js";
|
|
6
|
+
|
|
7
|
+
const app = express();
|
|
8
|
+
const PORT = process.env.PORT ?? 3000;
|
|
9
|
+
|
|
10
|
+
// ── Middleware ────────────────────────────────────────────────────────────────
|
|
11
|
+
|
|
12
|
+
app.use(express.json());
|
|
13
|
+
app.use(express.urlencoded({ extended: true }));
|
|
14
|
+
|
|
15
|
+
// ── Routes ────────────────────────────────────────────────────────────────────
|
|
16
|
+
|
|
17
|
+
app.use("/api", router);
|
|
18
|
+
|
|
19
|
+
// ── Error handler (must be last) ──────────────────────────────────────────────
|
|
20
|
+
|
|
21
|
+
app.use(errorHandler);
|
|
22
|
+
|
|
23
|
+
// ── Start ─────────────────────────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
app.listen(PORT, () => {
|
|
26
|
+
console.log(`Server running on http://localhost:${PORT}`);
|
|
27
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ErrorRequestHandler, NextFunction, Request, Response } from "express";
|
|
2
|
+
|
|
3
|
+
// Extend Error to support an optional HTTP status code
|
|
4
|
+
interface AppError extends Error {
|
|
5
|
+
status?: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// Must have exactly 4 parameters for Express to treat it as an error handler
|
|
9
|
+
export const errorHandler: ErrorRequestHandler = (
|
|
10
|
+
err: AppError,
|
|
11
|
+
_req: Request,
|
|
12
|
+
res: Response,
|
|
13
|
+
// next is required in the signature even if unused
|
|
14
|
+
_next: NextFunction
|
|
15
|
+
) => {
|
|
16
|
+
const status = err.status ?? 500;
|
|
17
|
+
const message = err.message ?? "Internal Server Error";
|
|
18
|
+
|
|
19
|
+
console.error(`[${status}] ${message}`);
|
|
20
|
+
|
|
21
|
+
res.status(status).json({
|
|
22
|
+
error: {
|
|
23
|
+
status,
|
|
24
|
+
message,
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type Request, type Response, Router } from "express";
|
|
2
|
+
|
|
3
|
+
export const router = Router();
|
|
4
|
+
|
|
5
|
+
// ── Health check ──────────────────────────────────────────────────────────────
|
|
6
|
+
|
|
7
|
+
router.get("/health", (_req: Request, res: Response) => {
|
|
8
|
+
res.json({ status: "ok" });
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
// ── Add your routes below ─────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
router.get("/", (_req: Request, res: Response) => {
|
|
14
|
+
res.json({ message: "Hello from __PROJECT_NAME__!" });
|
|
15
|
+
});
|