@tukuyomil032/bricklayer 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -4
- package/dist/create/file-writer.js +2 -17
- package/dist/create/index.js +4 -10
- package/dist/create/installer.js +6 -14
- package/dist/create/package-versions.js +0 -2
- package/dist/create/prompts.js +9 -23
- package/dist/create/templates.js +35 -21
- package/dist/index.js +0 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,17 +16,33 @@ Quickly generate a well-structured TypeScript CLI project with best practices bu
|
|
|
16
16
|
## Installation
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
-
npm install -g bricklayer
|
|
19
|
+
npm install -g @tukuyomil032/bricklayer
|
|
20
|
+
|
|
21
|
+
# or
|
|
22
|
+
pnpm add -g @tukuyomil032/bricklayer
|
|
23
|
+
|
|
20
24
|
# or
|
|
21
|
-
|
|
25
|
+
yarn global add @tukuyomil032/bricklayer
|
|
26
|
+
|
|
22
27
|
# or
|
|
23
|
-
|
|
28
|
+
bun add -g @tukuyomil032/bricklayer
|
|
24
29
|
```
|
|
25
30
|
|
|
26
31
|
## Usage
|
|
27
32
|
|
|
28
33
|
```bash
|
|
34
|
+
# When treating the current directory during command execution as the project's root folder:
|
|
29
35
|
bricklayer create
|
|
36
|
+
|
|
37
|
+
# If you want to specify the project's root folder yourself (we generally recommend using this option):
|
|
38
|
+
# Use the arrow keys (up and down) and the Enter key to navigate to the project's root folder.
|
|
39
|
+
bricklayer create -d
|
|
40
|
+
|
|
41
|
+
# You can also specify a project folder directly by entering a relative path after the `-d` option.
|
|
42
|
+
bricklayer create -d ~/Documents/dev/CLI/my-test-project
|
|
43
|
+
|
|
44
|
+
# available aliases
|
|
45
|
+
bl create
|
|
30
46
|
```
|
|
31
47
|
|
|
32
48
|
Follow the interactive prompts to configure your project:
|
|
@@ -34,8 +50,10 @@ Follow the interactive prompts to configure your project:
|
|
|
34
50
|
- Project name
|
|
35
51
|
- Module system (ESM / CommonJS)
|
|
36
52
|
- Package manager
|
|
53
|
+
- Automatically install dependencies(create lockfile)
|
|
37
54
|
- Git repository details
|
|
38
55
|
- Optional tools (Prettier, ESLint)
|
|
56
|
+
- husky(pre-commit, pre-push)
|
|
39
57
|
|
|
40
58
|
## Generated Project Structure
|
|
41
59
|
|
|
@@ -45,7 +63,7 @@ your-cli/
|
|
|
45
63
|
│ ├── commands/
|
|
46
64
|
│ │ └── hello.ts
|
|
47
65
|
│ └── index.ts
|
|
48
|
-
├── .husky/
|
|
66
|
+
├── .husky/ #options
|
|
49
67
|
│ ├── pre-commit
|
|
50
68
|
│ └── pre-push
|
|
51
69
|
├── .gitignore
|
|
@@ -16,77 +16,62 @@ export async function writeProjectFiles(targetDir, answers, versions) {
|
|
|
16
16
|
'src/commands/hello.ts',
|
|
17
17
|
'README.md',
|
|
18
18
|
'.gitignore',
|
|
19
|
-
// husky hooks are optional and added conditionally below
|
|
20
19
|
'.prettierignore',
|
|
21
20
|
'.npmignore',
|
|
22
21
|
'.editorconfig',
|
|
23
22
|
'LICENSE',
|
|
24
23
|
];
|
|
25
|
-
// Always include ESLint and Prettier config files by default
|
|
26
24
|
tasks.push('.prettierrc');
|
|
27
25
|
tasks.push('eslint.config.js');
|
|
28
26
|
// Add .npmrc when using pnpm
|
|
29
27
|
const shouldAddNpmrc = answers.packageManager === 'pnpm';
|
|
30
|
-
if (shouldAddNpmrc)
|
|
28
|
+
if (shouldAddNpmrc) {
|
|
31
29
|
tasks.push('.npmrc');
|
|
32
|
-
|
|
30
|
+
}
|
|
33
31
|
if (answers.useHusky) {
|
|
34
32
|
tasks.unshift('.husky/pre-push');
|
|
35
33
|
tasks.unshift('.husky/pre-commit');
|
|
36
34
|
}
|
|
37
35
|
progressBar.start(tasks.length, 0);
|
|
38
36
|
let completed = 0;
|
|
39
|
-
// Create directory structure
|
|
40
37
|
await fs.mkdir(targetDir, { recursive: true });
|
|
41
38
|
await fs.mkdir(path.join(targetDir, 'src', 'commands'), { recursive: true });
|
|
42
39
|
if (answers.useHusky) {
|
|
43
40
|
await fs.mkdir(path.join(targetDir, '.husky'), { recursive: true });
|
|
44
41
|
}
|
|
45
|
-
// Write package.json
|
|
46
42
|
const pkg = templates.generatePackageJson(answers, versions);
|
|
47
43
|
await fs.writeFile(path.join(targetDir, 'package.json'), JSON.stringify(pkg, null, 2));
|
|
48
44
|
progressBar.update(++completed);
|
|
49
|
-
// Write tsconfig.json
|
|
50
45
|
const tsconfig = templates.generateTsConfig(answers);
|
|
51
46
|
await fs.writeFile(path.join(targetDir, 'tsconfig.json'), JSON.stringify(tsconfig, null, 2));
|
|
52
47
|
progressBar.update(++completed);
|
|
53
|
-
// Write source files
|
|
54
48
|
await fs.writeFile(path.join(targetDir, 'src', 'index.ts'), templates.generateIndexTs(answers));
|
|
55
49
|
progressBar.update(++completed);
|
|
56
50
|
await fs.writeFile(path.join(targetDir, 'src', 'commands', 'hello.ts'), templates.generateHelloCommandTs());
|
|
57
51
|
progressBar.update(++completed);
|
|
58
|
-
// Write README
|
|
59
52
|
await fs.writeFile(path.join(targetDir, 'README.md'), templates.generateReadme(answers));
|
|
60
53
|
progressBar.update(++completed);
|
|
61
|
-
// Write .gitignore
|
|
62
54
|
await fs.writeFile(path.join(targetDir, '.gitignore'), templates.generateGitignore());
|
|
63
55
|
progressBar.update(++completed);
|
|
64
|
-
// Write Husky hooks (only if requested)
|
|
65
56
|
if (answers.useHusky) {
|
|
66
57
|
await fs.writeFile(path.join(targetDir, '.husky', 'pre-commit'), templates.generatePreCommitHook());
|
|
67
58
|
progressBar.update(++completed);
|
|
68
59
|
await fs.writeFile(path.join(targetDir, '.husky', 'pre-push'), templates.generatePrePushHook());
|
|
69
60
|
progressBar.update(++completed);
|
|
70
61
|
}
|
|
71
|
-
// Always add .prettierignore
|
|
72
62
|
await fs.writeFile(path.join(targetDir, '.prettierignore'), templates.generatePrettierIgnore());
|
|
73
63
|
progressBar.update(++completed);
|
|
74
|
-
// Always add .npmignore
|
|
75
64
|
await fs.writeFile(path.join(targetDir, '.npmignore'), templates.generateNpmIgnore());
|
|
76
65
|
progressBar.update(++completed);
|
|
77
|
-
// Conditionally add .npmrc for pnpm
|
|
78
66
|
if (shouldAddNpmrc) {
|
|
79
67
|
await fs.writeFile(path.join(targetDir, '.npmrc'), templates.generateNpmrc());
|
|
80
68
|
progressBar.update(++completed);
|
|
81
69
|
}
|
|
82
|
-
// Always add .editorconfig
|
|
83
70
|
await fs.writeFile(path.join(targetDir, '.editorconfig'), templates.generateEditorConfig());
|
|
84
71
|
progressBar.update(++completed);
|
|
85
|
-
// Write LICENSE
|
|
86
72
|
const licenseText = await templates.generateLicenseText(answers.license, answers.author, new Date().getFullYear());
|
|
87
73
|
await fs.writeFile(path.join(targetDir, 'LICENSE'), licenseText);
|
|
88
74
|
progressBar.update(++completed);
|
|
89
|
-
// Write Prettier and ESLint configs (default included)
|
|
90
75
|
await fs.writeFile(path.join(targetDir, '.prettierrc'), templates.generatePrettierConfig());
|
|
91
76
|
progressBar.update(++completed);
|
|
92
77
|
await fs.writeFile(path.join(targetDir, 'eslint.config.js'), templates.generateEslintConfig());
|
package/dist/create/index.js
CHANGED
|
@@ -14,36 +14,32 @@ export function createCommand() {
|
|
|
14
14
|
.option('-d, --destination [path]', 'Project destination directory');
|
|
15
15
|
cmd.action(async (options) => {
|
|
16
16
|
console.log(chalk.green('Welcome to bricklayer — TypeScript CLI scaffold generator'));
|
|
17
|
-
// Show spinner
|
|
18
17
|
const initSpinner = ora('Initializing project setup...').start();
|
|
19
|
-
// Small delay for better UX
|
|
20
18
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
21
19
|
initSpinner.stop();
|
|
22
|
-
// Determine destination behavior
|
|
23
20
|
const flagProvided = Boolean(options.destination);
|
|
24
21
|
const flagHasArg = typeof options.destination === 'string';
|
|
25
22
|
const askDestination = flagProvided && !flagHasArg;
|
|
26
|
-
// Prompt once: if -d present, always skip the `name` question; if -d without arg, also ask destination interactively first
|
|
27
23
|
const answers = await promptProjectDetails({ skipName: flagProvided, askDestination });
|
|
28
|
-
// Resolve target directory
|
|
29
24
|
let target;
|
|
30
25
|
if (flagHasArg) {
|
|
31
26
|
const dest = options.destination.replace(/^~/, os.homedir());
|
|
32
27
|
target = path.resolve(dest);
|
|
33
|
-
if (!answers.name)
|
|
28
|
+
if (!answers.name) {
|
|
34
29
|
answers.name = path.basename(target);
|
|
30
|
+
}
|
|
35
31
|
}
|
|
36
32
|
else if (answers.destination) {
|
|
37
33
|
const dest = answers.destination.replace(/^~/, os.homedir());
|
|
38
34
|
target = path.resolve(dest);
|
|
39
|
-
if (!answers.name)
|
|
35
|
+
if (!answers.name) {
|
|
40
36
|
answers.name = path.basename(target);
|
|
37
|
+
}
|
|
41
38
|
}
|
|
42
39
|
else {
|
|
43
40
|
const baseDir = process.cwd();
|
|
44
41
|
target = path.resolve(baseDir, answers.name);
|
|
45
42
|
}
|
|
46
|
-
// Fetch latest package versions
|
|
47
43
|
const versionSpinner = ora('Fetching latest package versions...').start();
|
|
48
44
|
let versions;
|
|
49
45
|
try {
|
|
@@ -58,14 +54,12 @@ export function createCommand() {
|
|
|
58
54
|
try {
|
|
59
55
|
await writeProjectFiles(target, answers, versions);
|
|
60
56
|
fileSpinner.succeed('Project scaffold created at ' + target);
|
|
61
|
-
// Install dependencies if user opted in
|
|
62
57
|
if (answers.autoInstall) {
|
|
63
58
|
await installDependencies(target, answers.packageManager);
|
|
64
59
|
}
|
|
65
60
|
else {
|
|
66
61
|
console.log(chalk.yellow('Dependencies were not installed automatically.'));
|
|
67
62
|
}
|
|
68
|
-
// Show next steps
|
|
69
63
|
console.log(chalk.blue('Next steps:'));
|
|
70
64
|
console.log(` - cd ${answers.name}`);
|
|
71
65
|
const buildCmd = answers.packageManager === 'pnpm'
|
package/dist/create/installer.js
CHANGED
|
@@ -25,7 +25,6 @@ export async function installDependencies(targetDir, packageManager) {
|
|
|
25
25
|
const bin = mgr;
|
|
26
26
|
if (!(await isCommandAvailable(bin))) {
|
|
27
27
|
spinner.fail(`${bin} not found on PATH.`);
|
|
28
|
-
// Try sensible fallback order
|
|
29
28
|
const fallbacks = ['pnpm', 'npm'];
|
|
30
29
|
let usedFallback = null;
|
|
31
30
|
for (const f of fallbacks) {
|
|
@@ -72,20 +71,15 @@ function runCommandWithProgress(command, cwd) {
|
|
|
72
71
|
barsize: 40,
|
|
73
72
|
}, cliProgress.Presets.shades_classic);
|
|
74
73
|
bar.start(100, 0);
|
|
75
|
-
// Progress state
|
|
76
74
|
let progress = 0;
|
|
77
75
|
let lastRenderedFloor = 0;
|
|
78
76
|
const start = Date.now();
|
|
79
|
-
// Interval drives internal progress target; we only redraw when integer percent changes
|
|
80
77
|
let lastOutputAt = 0;
|
|
81
|
-
const tickInterval = 150;
|
|
82
|
-
const maxHold = 95;
|
|
78
|
+
const tickInterval = 150;
|
|
79
|
+
const maxHold = 95;
|
|
83
80
|
const timer = setInterval(() => {
|
|
84
81
|
const elapsed = Date.now() - start;
|
|
85
|
-
// Ease-out target that slowly approaches maxHold
|
|
86
82
|
const target = maxHold * (1 - Math.exp(-elapsed / 6000));
|
|
87
|
-
// Advance progress a bit toward target, ensuring monotonic increase
|
|
88
|
-
// If we've recently seen installer output, move faster
|
|
89
83
|
const sinceOutput = lastOutputAt ? Date.now() - lastOutputAt : Infinity;
|
|
90
84
|
const speedMultiplier = sinceOutput < 1000 ? 2.0 : 1.0;
|
|
91
85
|
progress = Math.min(target, progress + 0.6 * speedMultiplier);
|
|
@@ -103,11 +97,10 @@ function runCommandWithProgress(command, cwd) {
|
|
|
103
97
|
const stderrChunks = [];
|
|
104
98
|
const onOutput = () => {
|
|
105
99
|
lastOutputAt = Date.now();
|
|
106
|
-
// Aggressively advance progress toward maxHold on real installer output
|
|
107
100
|
const remaining = maxHold - progress;
|
|
108
|
-
if (remaining <= 0)
|
|
101
|
+
if (remaining <= 0) {
|
|
109
102
|
return;
|
|
110
|
-
|
|
103
|
+
}
|
|
111
104
|
const advance = Math.min(remaining, Math.max(4, Math.round(remaining * 0.18)));
|
|
112
105
|
progress = progress + advance;
|
|
113
106
|
const floor = Math.floor(progress);
|
|
@@ -139,7 +132,6 @@ function runCommandWithProgress(command, cwd) {
|
|
|
139
132
|
});
|
|
140
133
|
child.on('close', (code) => {
|
|
141
134
|
clearInterval(timer);
|
|
142
|
-
// Smoothly ramp to 100% to avoid a sudden jump
|
|
143
135
|
const finishInterval = 40; // ms
|
|
144
136
|
const finishTimer = setInterval(() => {
|
|
145
137
|
const remaining = 100 - progress;
|
|
@@ -150,14 +142,14 @@ function runCommandWithProgress(command, cwd) {
|
|
|
150
142
|
}
|
|
151
143
|
catch { }
|
|
152
144
|
clearInterval(finishTimer);
|
|
153
|
-
if (code === 0)
|
|
145
|
+
if (code === 0) {
|
|
154
146
|
return resolve();
|
|
147
|
+
}
|
|
155
148
|
const out = Buffer.concat(stdoutChunks).toString('utf8');
|
|
156
149
|
const errOut = Buffer.concat(stderrChunks).toString('utf8');
|
|
157
150
|
const e = new Error(`Command exited with code ${code}\n${errOut || out}`);
|
|
158
151
|
return reject(e);
|
|
159
152
|
}
|
|
160
|
-
// advance by a fraction of remaining to create ease-out
|
|
161
153
|
progress = progress + Math.max(1, Math.round(remaining * 0.18));
|
|
162
154
|
const floor = Math.floor(progress);
|
|
163
155
|
if (floor > lastRenderedFloor) {
|
|
@@ -37,7 +37,6 @@ export async function getLatestVersions() {
|
|
|
37
37
|
'chalk',
|
|
38
38
|
'ora',
|
|
39
39
|
'yargs',
|
|
40
|
-
// include package manager packages to record their latest versions
|
|
41
40
|
'pnpm',
|
|
42
41
|
'npm',
|
|
43
42
|
'yarn',
|
|
@@ -50,7 +49,6 @@ export async function getLatestVersions() {
|
|
|
50
49
|
versions[pkg] = await fetchLatestVersion(pkg);
|
|
51
50
|
}
|
|
52
51
|
catch (err) {
|
|
53
|
-
// Fallback to a reasonable default if fetch fails
|
|
54
52
|
console.warn(`Failed to fetch version for ${pkg}, using fallback:`, err);
|
|
55
53
|
versions[pkg] = 'latest';
|
|
56
54
|
}
|
package/dist/create/prompts.js
CHANGED
|
@@ -88,7 +88,7 @@ export async function promptProjectDetails(opts = {}) {
|
|
|
88
88
|
];
|
|
89
89
|
const totalQuestions = questions.length;
|
|
90
90
|
const answers = {};
|
|
91
|
-
console.log('');
|
|
91
|
+
console.log('');
|
|
92
92
|
const uiWith = inquirer;
|
|
93
93
|
const bottomBar = uiWith.ui && uiWith.ui.BottomBar
|
|
94
94
|
? new uiWith.ui.BottomBar()
|
|
@@ -100,22 +100,18 @@ export async function promptProjectDetails(opts = {}) {
|
|
|
100
100
|
}
|
|
101
101
|
catch (err) {
|
|
102
102
|
void err;
|
|
103
|
-
// fallback: write using readline
|
|
104
103
|
readline.clearLine(process.stdout, 0);
|
|
105
104
|
readline.cursorTo(process.stdout, 0);
|
|
106
105
|
process.stdout.write(progressLine + '\n');
|
|
107
106
|
}
|
|
108
107
|
};
|
|
109
|
-
// Compute effective total: subtract skipped name, add destination prompt if requested
|
|
110
108
|
const effectiveTotal = totalQuestions - (opts.skipName ? 1 : 0) + (opts.askDestination ? 1 : 0);
|
|
111
109
|
let progressCount = 0;
|
|
112
110
|
updateProgress(progressCount);
|
|
113
|
-
// If askDestination is requested, prompt for it first using an interactive tree navigator
|
|
114
111
|
if (opts.askDestination) {
|
|
115
112
|
const chooseDirectoryInteractive = async (startDir) => {
|
|
116
113
|
let current = startDir;
|
|
117
114
|
while (true) {
|
|
118
|
-
// list visible directories (exclude hidden)
|
|
119
115
|
let entries = [];
|
|
120
116
|
try {
|
|
121
117
|
entries = fs.readdirSync(current).filter((name) => {
|
|
@@ -135,16 +131,12 @@ export async function promptProjectDetails(opts = {}) {
|
|
|
135
131
|
{ display: '.. (go up)', value: '__UP__' },
|
|
136
132
|
...entries.map((e) => ({ display: e + path.sep, value: e })),
|
|
137
133
|
];
|
|
138
|
-
// Add a small circle at the start of each displayed choice to indicate it's selectable
|
|
139
134
|
choices.forEach((c) => {
|
|
140
135
|
c.display = `◯ ${c.display}`;
|
|
141
136
|
});
|
|
142
|
-
// Enquirer expects choice objects with `name` (unique id) and `message` (display)
|
|
143
137
|
const select = new Select({
|
|
144
138
|
name: 'dir',
|
|
145
139
|
message: `destination: (navigate folders, Enter to choose)`,
|
|
146
|
-
// Enquirer Select returns the `name` of the chosen item.
|
|
147
|
-
// Use `name` as the internal id (value) and `message` for display.
|
|
148
140
|
choices: choices.map((c) => ({ name: c.value, message: c.display })),
|
|
149
141
|
pageSize: 15,
|
|
150
142
|
});
|
|
@@ -153,12 +145,10 @@ export async function promptProjectDetails(opts = {}) {
|
|
|
153
145
|
val = await select.run();
|
|
154
146
|
}
|
|
155
147
|
catch (err) {
|
|
156
|
-
// Enquirer may throw when TTY not available; surface a friendly error
|
|
157
148
|
console.error('Selection aborted or failed:', err instanceof Error ? err.message : String(err));
|
|
158
149
|
throw err;
|
|
159
150
|
}
|
|
160
151
|
if (val === '__SELECT__') {
|
|
161
|
-
// Use Enquirer's Input so the default/current path is actual editable text
|
|
162
152
|
while (true) {
|
|
163
153
|
const input = new Input({
|
|
164
154
|
message: 'destination: (edit or accept)',
|
|
@@ -184,29 +174,29 @@ export async function promptProjectDetails(opts = {}) {
|
|
|
184
174
|
],
|
|
185
175
|
},
|
|
186
176
|
]);
|
|
187
|
-
if (confirm.confirmSel === 'confirm')
|
|
177
|
+
if (confirm.confirmSel === 'confirm') {
|
|
188
178
|
return proposed;
|
|
189
|
-
|
|
179
|
+
}
|
|
180
|
+
if (confirm.confirmSel === 'reenter') {
|
|
190
181
|
continue;
|
|
191
|
-
|
|
192
|
-
|
|
182
|
+
}
|
|
183
|
+
if (confirm.confirmSel === 'back') {
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
193
186
|
}
|
|
194
187
|
continue;
|
|
195
188
|
}
|
|
196
189
|
if (val === '__UP__') {
|
|
197
190
|
const parent = path.dirname(current);
|
|
198
191
|
if (parent === current) {
|
|
199
|
-
// already root
|
|
200
192
|
continue;
|
|
201
193
|
}
|
|
202
194
|
current = parent;
|
|
203
195
|
continue;
|
|
204
196
|
}
|
|
205
|
-
// descend into selected subdirectory
|
|
206
197
|
current = path.join(current, val);
|
|
207
198
|
}
|
|
208
199
|
};
|
|
209
|
-
// Count the destination question once and show progress before navigation
|
|
210
200
|
progressCount++;
|
|
211
201
|
updateProgress(progressCount);
|
|
212
202
|
const dest = await chooseDirectoryInteractive(process.cwd());
|
|
@@ -215,16 +205,13 @@ export async function promptProjectDetails(opts = {}) {
|
|
|
215
205
|
console.log('→ Selected: ' + chalk.green(dest));
|
|
216
206
|
}
|
|
217
207
|
}
|
|
218
|
-
// Build list of questions to ask (skip name if requested)
|
|
219
208
|
const toAsk = opts.skipName ? questions.slice(1) : questions.slice();
|
|
220
209
|
for (let i = 0; i < toAsk.length; i++) {
|
|
221
210
|
const question = toAsk[i];
|
|
222
|
-
// Update the single progress bottom bar just before each prompt
|
|
223
211
|
progressCount++;
|
|
224
212
|
updateProgress(progressCount);
|
|
225
213
|
const answer = await inquirer.prompt([question]);
|
|
226
214
|
Object.assign(answers, answer);
|
|
227
|
-
// Display selected value in color for clarity (above the bottom bar)
|
|
228
215
|
const key = question.name;
|
|
229
216
|
const val = answer[key];
|
|
230
217
|
if (typeof val === 'string') {
|
|
@@ -237,7 +224,6 @@ export async function promptProjectDetails(opts = {}) {
|
|
|
237
224
|
console.log('→ Selected: ' + (val ? chalk.green('yes') : chalk.yellow('no')));
|
|
238
225
|
}
|
|
239
226
|
}
|
|
240
|
-
// Finalize progress
|
|
241
227
|
updateProgress(effectiveTotal);
|
|
242
228
|
try {
|
|
243
229
|
bottomBar.updateBottomBar(`Project Scaffolding Progress: [${effectiveTotal}/${effectiveTotal}] Done.`);
|
|
@@ -246,6 +232,6 @@ export async function promptProjectDetails(opts = {}) {
|
|
|
246
232
|
catch (err) {
|
|
247
233
|
void err;
|
|
248
234
|
}
|
|
249
|
-
console.log('');
|
|
235
|
+
console.log('');
|
|
250
236
|
return answers;
|
|
251
237
|
}
|
package/dist/create/templates.js
CHANGED
|
@@ -208,9 +208,8 @@ export function generatePackageJson(answers, versions) {
|
|
|
208
208
|
return 'bun run build';
|
|
209
209
|
return `${m} run build`;
|
|
210
210
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
: buildCmdForManager(mgr);
|
|
211
|
+
// When Husky is enabled, keep prepare as just 'husky' (user requested).
|
|
212
|
+
const prepareScript = answers.useHusky ? 'husky' : buildCmdForManager(mgr);
|
|
214
213
|
return {
|
|
215
214
|
name: answers.npmPackageName || answers.name,
|
|
216
215
|
private: false,
|
|
@@ -232,6 +231,7 @@ export function generatePackageJson(answers, versions) {
|
|
|
232
231
|
typecheck: 'tsc --noEmit',
|
|
233
232
|
lint: 'eslint "src/**/*.ts"',
|
|
234
233
|
'lint:fix': 'eslint "src/**/*.ts" --fix',
|
|
234
|
+
'lint-staged': 'lint-staged',
|
|
235
235
|
format: 'prettier --write "src/**/*.ts"',
|
|
236
236
|
'format:check': 'prettier --check "src/**/*.ts"',
|
|
237
237
|
}, answers.useHusky ? {} : {}),
|
|
@@ -355,26 +355,41 @@ export function generateEslintConfig() {
|
|
|
355
355
|
import globals from 'globals';
|
|
356
356
|
import tseslint from 'typescript-eslint';
|
|
357
357
|
import json from '@eslint/json';
|
|
358
|
-
import { defineConfig } from 'eslint/config';
|
|
359
358
|
|
|
360
|
-
export default
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
359
|
+
export default [
|
|
360
|
+
{
|
|
361
|
+
ignores: ['dist/**'],
|
|
362
|
+
},
|
|
363
|
+
|
|
364
|
+
{
|
|
365
|
+
files: ['**/*.{js,mjs,cjs}'],
|
|
366
|
+
languageOptions: {
|
|
367
|
+
globals: globals.node,
|
|
368
|
+
},
|
|
369
|
+
...js.configs.recommended,
|
|
370
|
+
},
|
|
371
|
+
|
|
372
|
+
{
|
|
373
|
+
files: ['**/*.{ts,mts,cts}'],
|
|
374
|
+
languageOptions: {
|
|
375
|
+
globals: globals.node,
|
|
376
|
+
parser: tseslint.parser,
|
|
368
377
|
},
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
files: ['**/*.json'],
|
|
372
|
-
plugins: { json },
|
|
373
|
-
language: 'json/json',
|
|
374
|
-
extends: ['json/recommended'],
|
|
378
|
+
plugins: {
|
|
379
|
+
'@typescript-eslint': tseslint.plugin,
|
|
375
380
|
},
|
|
376
|
-
|
|
377
|
-
|
|
381
|
+
rules: {
|
|
382
|
+
...tseslint.configs.recommended.rules,
|
|
383
|
+
},
|
|
384
|
+
},
|
|
385
|
+
|
|
386
|
+
{
|
|
387
|
+
files: ['**/*.json'],
|
|
388
|
+
language: 'json/json',
|
|
389
|
+
plugins: { json },
|
|
390
|
+
...json.configs.recommended,
|
|
391
|
+
},
|
|
392
|
+
];
|
|
378
393
|
`;
|
|
379
394
|
}
|
|
380
395
|
export async function generateLicenseText(license, author, year) {
|
|
@@ -402,4 +417,3 @@ export async function generateLicenseText(license, author, year) {
|
|
|
402
417
|
.replace(fullnameRegex, author)
|
|
403
418
|
.replace(nameRegex, author);
|
|
404
419
|
}
|
|
405
|
-
// Note: .eslintignore generation removed in favor of eslint.config.js ignores
|
package/dist/index.js
CHANGED