@tukuyomil032/bricklayer 1.0.43 → 1.0.44

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.
@@ -1,8 +1,9 @@
1
+ import cliProgress from 'cli-progress';
1
2
  import fs from 'fs/promises';
2
3
  import path from 'path';
3
- import cliProgress from 'cli-progress';
4
4
  import * as templates from './templates.js';
5
5
  export async function writeProjectFiles(targetDir, answers, versions) {
6
+ const useBiome = answers.linterFormatter === 'biome';
6
7
  const progressBar = new cliProgress.SingleBar({
7
8
  format: 'Creating files |{bar}| {percentage}% | {value}/{total} files',
8
9
  barCompleteChar: '\u2588',
@@ -16,13 +17,18 @@ export async function writeProjectFiles(targetDir, answers, versions) {
16
17
  'src/commands/hello.ts',
17
18
  'README.md',
18
19
  '.gitignore',
19
- '.prettierignore',
20
20
  '.npmignore',
21
21
  '.editorconfig',
22
22
  'LICENSE',
23
23
  ];
24
- tasks.push('.prettierrc');
25
- tasks.push('eslint.config.js');
24
+ if (useBiome) {
25
+ tasks.push('biome.json');
26
+ }
27
+ else {
28
+ tasks.push('.prettierignore');
29
+ tasks.push('.prettierrc');
30
+ tasks.push('eslint.config.js');
31
+ }
26
32
  // Add .npmrc when using pnpm
27
33
  const shouldAddNpmrc = answers.packageManager === 'pnpm';
28
34
  if (shouldAddNpmrc) {
@@ -54,13 +60,15 @@ export async function writeProjectFiles(targetDir, answers, versions) {
54
60
  await fs.writeFile(path.join(targetDir, '.gitignore'), templates.generateGitignore());
55
61
  progressBar.update(++completed);
56
62
  if (answers.useHusky) {
57
- await fs.writeFile(path.join(targetDir, '.husky', 'pre-commit'), templates.generatePreCommitHook());
63
+ await fs.writeFile(path.join(targetDir, '.husky', 'pre-commit'), templates.generatePreCommitHook(answers.packageManager));
58
64
  progressBar.update(++completed);
59
- await fs.writeFile(path.join(targetDir, '.husky', 'pre-push'), templates.generatePrePushHook());
65
+ await fs.writeFile(path.join(targetDir, '.husky', 'pre-push'), templates.generatePrePushHook(answers.packageManager, answers.linterFormatter));
66
+ progressBar.update(++completed);
67
+ }
68
+ if (!useBiome) {
69
+ await fs.writeFile(path.join(targetDir, '.prettierignore'), templates.generatePrettierIgnore());
60
70
  progressBar.update(++completed);
61
71
  }
62
- await fs.writeFile(path.join(targetDir, '.prettierignore'), templates.generatePrettierIgnore());
63
- progressBar.update(++completed);
64
72
  await fs.writeFile(path.join(targetDir, '.npmignore'), templates.generateNpmIgnore());
65
73
  progressBar.update(++completed);
66
74
  if (shouldAddNpmrc) {
@@ -72,10 +80,16 @@ export async function writeProjectFiles(targetDir, answers, versions) {
72
80
  const licenseText = await templates.generateLicenseText(answers.license, answers.author, new Date().getFullYear());
73
81
  await fs.writeFile(path.join(targetDir, 'LICENSE'), licenseText);
74
82
  progressBar.update(++completed);
75
- await fs.writeFile(path.join(targetDir, '.prettierrc'), templates.generatePrettierConfig());
76
- progressBar.update(++completed);
77
- await fs.writeFile(path.join(targetDir, 'eslint.config.js'), templates.generateEslintConfig());
78
- progressBar.update(++completed);
83
+ if (useBiome) {
84
+ await fs.writeFile(path.join(targetDir, 'biome.json'), templates.generateBiomeConfig());
85
+ progressBar.update(++completed);
86
+ }
87
+ else {
88
+ await fs.writeFile(path.join(targetDir, '.prettierrc'), templates.generatePrettierConfig());
89
+ progressBar.update(++completed);
90
+ await fs.writeFile(path.join(targetDir, 'eslint.config.js'), templates.generateEslintConfig());
91
+ progressBar.update(++completed);
92
+ }
79
93
  progressBar.stop();
80
94
  console.log('');
81
95
  }
@@ -1,12 +1,12 @@
1
- import path from 'path';
2
- import os from 'os';
3
1
  import chalk from 'chalk';
4
- import ora from 'ora';
5
2
  import { Command } from 'commander';
6
- import { promptProjectDetails } from './prompts.js';
3
+ import ora from 'ora';
4
+ import os from 'os';
5
+ import path from 'path';
7
6
  import { writeProjectFiles } from './file-writer.js';
8
7
  import { installDependencies } from './installer.js';
9
8
  import { getLatestVersions } from './package-versions.js';
9
+ import { promptProjectDetails } from './prompts.js';
10
10
  export function createCommand() {
11
11
  const cmd = new Command('create');
12
12
  cmd
@@ -1,7 +1,7 @@
1
1
  import { exec as execCb, spawn } from 'child_process';
2
- import { promisify } from 'util';
3
- import ora from 'ora';
4
2
  import cliProgress from 'cli-progress';
3
+ import ora from 'ora';
4
+ import { promisify } from 'util';
5
5
  const exec = promisify(execCb);
6
6
  const INSTALL_COMMANDS = {
7
7
  npm: 'npm install',
@@ -34,6 +34,7 @@ export async function getLatestVersions() {
34
34
  'typescript-eslint',
35
35
  '@eslint/json',
36
36
  'prettier',
37
+ '@biomejs/biome',
37
38
  'lint-staged',
38
39
  'commander',
39
40
  'inquirer',
@@ -1,13 +1,12 @@
1
- import inquirer from 'inquirer';
2
- import Enquirer from 'enquirer';
3
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
4
- const Select = Enquirer.Select || Enquirer.default?.Select;
5
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
- const Input = Enquirer.Input || Enquirer.default?.Input;
7
1
  import chalk from 'chalk';
8
- import readline from 'readline';
2
+ import Enquirer from 'enquirer';
9
3
  import fs from 'fs';
4
+ import inquirer from 'inquirer';
10
5
  import path from 'path';
6
+ import readline from 'readline';
7
+ const enquirerModule = Enquirer;
8
+ const Select = enquirerModule.Select || enquirerModule.default?.Select;
9
+ const Input = enquirerModule.Input || enquirerModule.default?.Input;
11
10
  export async function promptProjectDetails(opts = {}) {
12
11
  const questions = [
13
12
  {
@@ -30,6 +29,16 @@ export async function promptProjectDetails(opts = {}) {
30
29
  choices: ['npm', 'pnpm', 'yarn', 'bun'],
31
30
  default: 'npm',
32
31
  },
32
+ {
33
+ type: 'list',
34
+ name: 'linterFormatter',
35
+ message: 'Linter / formatter setup:',
36
+ choices: [
37
+ { name: 'ESLint + Prettier', value: 'eslint+prettier' },
38
+ { name: 'Biome', value: 'biome' },
39
+ ],
40
+ default: 'eslint+prettier',
41
+ },
33
42
  {
34
43
  type: 'confirm',
35
44
  name: 'autoInstall',
@@ -92,9 +101,12 @@ export async function promptProjectDetails(opts = {}) {
92
101
  const answers = {};
93
102
  console.log('');
94
103
  const uiWith = inquirer;
104
+ const noop = () => {
105
+ // Intentionally no-op when BottomBar UI is unavailable.
106
+ };
95
107
  const bottomBar = uiWith.ui && uiWith.ui.BottomBar
96
108
  ? new uiWith.ui.BottomBar()
97
- : { updateBottomBar: () => { }, close: () => { } };
109
+ : { updateBottomBar: noop, close: noop };
98
110
  const updateProgress = (n) => {
99
111
  const progressLine = `Project Scaffolding Progress: [${n}/${totalQuestions}]`;
100
112
  try {
@@ -136,6 +148,9 @@ export async function promptProjectDetails(opts = {}) {
136
148
  choices.forEach((c) => {
137
149
  c.display = `◯ ${c.display}`;
138
150
  });
151
+ if (!Select || !Input) {
152
+ throw new Error('Enquirer Select/Input could not be resolved from the enquirer module.');
153
+ }
139
154
  const select = new Select({
140
155
  name: 'dir',
141
156
  message: `destination: (navigate folders, Enter to choose)`,
@@ -153,14 +153,22 @@ const staticTemplates = {
153
153
  ],
154
154
  };
155
155
  const hooksTemplates = {
156
- 'pre-commit': ['#!/bin/sh', '. "$(dirname "$0")/_/husky.sh"', '', 'pnpm run lint-staged'],
157
- 'pre-push': [
158
- '#!/bin/sh',
159
- '. "$(dirname "$0")/_/husky.sh"',
160
- '',
161
- 'pnpm run lint && pnpm run format:check',
162
- ],
156
+ pnpm: {
157
+ 'pre-commit': ['#!/bin/sh', '. "$(dirname "$0")/_/husky.sh"', '', 'pnpm run lint-staged'],
158
+ },
159
+ npm: {
160
+ 'pre-commit': ['#!/bin/sh', '. "$(dirname "$0")/_/husky.sh"', '', 'npm run lint-staged'],
161
+ },
162
+ yarn: {
163
+ 'pre-commit': ['#!/bin/sh', '. "$(dirname "$0")/_/husky.sh"', '', 'yarn lint-staged'],
164
+ },
165
+ bun: {
166
+ 'pre-commit': ['#!/bin/sh', '. "$(dirname "$0")/_/husky.sh"', '', 'bun run lint-staged'],
167
+ },
163
168
  };
169
+ function isBiomeSetup(answers) {
170
+ return answers.linterFormatter === 'biome';
171
+ }
164
172
  // Generate scripts object with OS-specific postbuild handling
165
173
  function generateScriptsWithPermissions(baseScripts) {
166
174
  // Add postbuild script to handle file permissions across platforms
@@ -173,6 +181,7 @@ function generateScriptsWithPermissions(baseScripts) {
173
181
  }
174
182
  // license texts are provided from src/create/licenses.ts
175
183
  export function generatePackageJson(answers, versions) {
184
+ const useBiome = isBiomeSetup(answers);
176
185
  const devDeps = {
177
186
  typescript: versions?.['typescript'] || '^5.7.2',
178
187
  'ts-node': versions?.['ts-node'] || '^10.9.1',
@@ -180,16 +189,20 @@ export function generatePackageJson(answers, versions) {
180
189
  '@types/cli-progress': versions?.['@types/cli-progress'] || '^3.11.6',
181
190
  'lint-staged': versions?.['lint-staged'] || '^15.2.11',
182
191
  };
183
- // Include ESLint and Prettier by default in generated projects
184
- devDeps['eslint'] = versions?.['eslint'] || '^9.39.2';
185
- devDeps['eslint-config-prettier'] = versions?.['eslint-config-prettier'] || '^10.1.8';
186
- devDeps['eslint-plugin-prettier'] = versions?.['eslint-plugin-prettier'] || '^5.5.4';
187
- devDeps['@typescript-eslint/parser'] = versions?.['@typescript-eslint/parser'] || '^8.52.0';
188
- devDeps['@typescript-eslint/eslint-plugin'] =
189
- versions?.['@typescript-eslint/eslint-plugin'] || '^8.52.0';
190
- devDeps['typescript-eslint'] = versions?.['typescript-eslint'] || '^8.52.0';
191
- devDeps['@eslint/json'] = versions?.['@eslint/json'] || '^0.1.1';
192
- devDeps['prettier'] = versions?.['prettier'] || '^3.7.4';
192
+ if (useBiome) {
193
+ devDeps['@biomejs/biome'] = versions?.['@biomejs/biome'] || '^1.9.4';
194
+ }
195
+ else {
196
+ devDeps['eslint'] = versions?.['eslint'] || '^9.39.2';
197
+ devDeps['eslint-config-prettier'] = versions?.['eslint-config-prettier'] || '^10.1.8';
198
+ devDeps['eslint-plugin-prettier'] = versions?.['eslint-plugin-prettier'] || '^5.5.4';
199
+ devDeps['@typescript-eslint/parser'] = versions?.['@typescript-eslint/parser'] || '^8.52.0';
200
+ devDeps['@typescript-eslint/eslint-plugin'] =
201
+ versions?.['@typescript-eslint/eslint-plugin'] || '^8.52.0';
202
+ devDeps['typescript-eslint'] = versions?.['typescript-eslint'] || '^8.52.0';
203
+ devDeps['@eslint/json'] = versions?.['@eslint/json'] || '^0.1.1';
204
+ devDeps['prettier'] = versions?.['prettier'] || '^3.7.4';
205
+ }
193
206
  // Husky should only be added when requested (useHusky)
194
207
  if (answers.useHusky) {
195
208
  devDeps['husky'] = versions?.['husky'] || '^9.1.7';
@@ -227,6 +240,35 @@ export function generatePackageJson(answers, versions) {
227
240
  }
228
241
  // When Husky is enabled, keep prepare as just 'husky' (user requested).
229
242
  const prepareScript = answers.useHusky ? 'husky' : buildCmdForManager(mgr);
243
+ const baseScripts = {
244
+ build: 'tsc -p tsconfig.json',
245
+ prepare: prepareScript,
246
+ prepublishOnly: buildCmdForManager(mgr),
247
+ dev: 'ts-node --esm src/index.ts',
248
+ start: 'node dist/index.js',
249
+ typecheck: 'tsc --noEmit',
250
+ 'lint-staged': 'lint-staged',
251
+ };
252
+ const lintScripts = useBiome
253
+ ? {
254
+ format: 'biome format --write .',
255
+ lint: 'biome lint --write .',
256
+ 'biome:check': 'biome check .',
257
+ 'biome:fix': 'biome check . --write',
258
+ }
259
+ : {
260
+ lint: 'eslint "src/**/*.ts"',
261
+ 'lint:fix': 'eslint "src/**/*.ts" --fix',
262
+ format: 'prettier --write "src/**/*.ts"',
263
+ 'format:check': 'prettier --check "src/**/*.ts"',
264
+ };
265
+ const lintStagedConfig = useBiome
266
+ ? {
267
+ '*.{js,jsx,ts,tsx,json,jsonc,md}': ['biome check --write'],
268
+ }
269
+ : {
270
+ '*.ts': ['eslint --fix', 'prettier --write'],
271
+ };
230
272
  return {
231
273
  name: answers.npmPackageName || answers.name,
232
274
  private: false,
@@ -239,19 +281,10 @@ export function generatePackageJson(answers, versions) {
239
281
  [answers.name]: './dist/index.js',
240
282
  },
241
283
  files: ['dist', 'README.md'],
242
- scripts: generateScriptsWithPermissions(Object.assign({
243
- build: 'tsc -p tsconfig.json',
244
- prepare: prepareScript,
245
- prepublishOnly: buildCmdForManager(mgr),
246
- dev: 'ts-node --esm src/index.ts',
247
- start: 'node dist/index.js',
248
- typecheck: 'tsc --noEmit',
249
- lint: 'eslint "src/**/*.ts"',
250
- 'lint:fix': 'eslint "src/**/*.ts" --fix',
251
- 'lint-staged': 'lint-staged',
252
- format: 'prettier --write "src/**/*.ts"',
253
- 'format:check': 'prettier --check "src/**/*.ts"',
254
- }, answers.useHusky ? {} : {})),
284
+ scripts: generateScriptsWithPermissions({
285
+ ...baseScripts,
286
+ ...lintScripts,
287
+ }),
255
288
  keywords: ['cli', 'scaffold', 'typescript', 'generator'],
256
289
  author: answers.author,
257
290
  license: answers.license,
@@ -265,9 +298,7 @@ export function generatePackageJson(answers, versions) {
265
298
  homepage: `https://github.com/${answers.gitOwner}/${answers.gitRepo}#readme`,
266
299
  dependencies: deps,
267
300
  devDependencies: devDeps,
268
- 'lint-staged': {
269
- '*.ts': ['eslint --fix', 'prettier --write'],
270
- },
301
+ 'lint-staged': lintStagedConfig,
271
302
  packageManager: `${mgr}@${exactVersion(pkgManagerVersions[mgr] || '10.27.0')}`,
272
303
  };
273
304
  }
@@ -326,14 +357,29 @@ export function generateGitignore() {
326
357
  ? staticTemplates.gitignore.join('\n')
327
358
  : staticTemplates.gitignore;
328
359
  }
329
- export function generatePreCommitHook() {
330
- const hook = hooksTemplates['pre-commit'];
331
- return Array.isArray(hook) ? hook.join('\n') : hook;
360
+ function pickManagerKey(mgr) {
361
+ const m = (mgr || 'pnpm').toLowerCase();
362
+ if (m === 'npm' || m === 'yarn' || m === 'bun' || m === 'pnpm')
363
+ return m;
364
+ return 'pnpm';
332
365
  }
333
- export function generatePrePushHook() {
334
- const hook = hooksTemplates['pre-push'];
366
+ export function generatePreCommitHook(packageManager) {
367
+ const key = pickManagerKey(packageManager);
368
+ const hook = hooksTemplates[key]['pre-commit'];
335
369
  return Array.isArray(hook) ? hook.join('\n') : hook;
336
370
  }
371
+ export function generatePrePushHook(packageManager, linterFormatter = 'eslint+prettier') {
372
+ const key = pickManagerKey(packageManager);
373
+ const runScript = key === 'yarn'
374
+ ? (script) => `yarn ${script}`
375
+ : key === 'bun'
376
+ ? (script) => `bun run ${script}`
377
+ : (script) => `${key} run ${script}`;
378
+ const checkCommand = linterFormatter === 'biome'
379
+ ? 'pnpm run biome:check'
380
+ : `${runScript('lint')} && ${runScript('format:check')}`;
381
+ return ['#!/bin/sh', '. "$(dirname "$0")/_/husky.sh"', '', checkCommand].join('\n');
382
+ }
337
383
  export function generatePrettierConfig() {
338
384
  return `{
339
385
  "semi": true,
@@ -419,6 +465,33 @@ export default [
419
465
  ];
420
466
  `;
421
467
  }
468
+ export function generateBiomeConfig() {
469
+ const config = {
470
+ $schema: 'https://biomejs.dev/schemas/1.9.4/schema.json',
471
+ formatter: {
472
+ enabled: true,
473
+ indentStyle: 'space',
474
+ indentWidth: 2,
475
+ lineWidth: 100,
476
+ },
477
+ linter: {
478
+ enabled: true,
479
+ rules: {
480
+ recommended: true,
481
+ },
482
+ },
483
+ javascript: {
484
+ formatter: {
485
+ semicolons: 'always',
486
+ quoteStyle: 'single',
487
+ },
488
+ },
489
+ files: {
490
+ ignore: ['dist', 'node_modules'],
491
+ },
492
+ };
493
+ return `${JSON.stringify(config, null, 2)}\n`;
494
+ }
422
495
  export async function generateLicenseText(license, author, year) {
423
496
  // Try reading per-license text files (more readable than JSON storage)
424
497
  const keyMap = {
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ const program = new Command();
5
5
  program
6
6
  .name('brick')
7
7
  .description('Interactive CLI to scaffold TypeScript CLI projects')
8
- .version('1.0.43');
8
+ .version('1.0.6');
9
9
  program.addCommand(createCommand());
10
10
  program.addCommand(sampleCommand());
11
11
  program.parseAsync(process.argv).catch((err) => {
package/dist/sample.js CHANGED
@@ -1,5 +1,5 @@
1
- import { Command } from 'commander';
2
1
  import chalk from 'chalk';
2
+ import { Command } from 'commander';
3
3
  export function sampleCommand() {
4
4
  const cmd = new Command('sample');
5
5
  cmd.description('A sample subcommand demonstrating project structure separation');
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tukuyomil032/bricklayer",
3
3
  "private": false,
4
- "version": "1.0.43",
4
+ "version": "1.0.44",
5
5
  "description": "Interactive TypeScript CLI project scaffolder",
6
6
  "type": "module",
7
7
  "main": "./dist/index.js",
@@ -18,14 +18,12 @@
18
18
  "postbuild": "node -e \"require('fs').chmodSync('dist/index.js', 0o755)\"",
19
19
  "prepare": "husky",
20
20
  "prepublishOnly": "pnpm run build",
21
- "dev": "ts-node --esm src/index.ts",
22
- "start": "node dist/index.js",
21
+ "dev": "node dist/index.js",
23
22
  "typecheck": "tsc --noEmit",
24
- "lint": "eslint \"src/**/*.ts\"",
25
- "lint:fix": "eslint \"src/**/*.ts\" --fix",
26
- "lint-staged": "lint-staged",
27
- "format": "prettier --write \"src/**/*.ts\"",
28
- "format:check": "prettier --check \"src/**/*.ts\""
23
+ "format": "biome format --write",
24
+ "lint": "biome lint --write",
25
+ "biome:check": "biome check",
26
+ "lint-staged": "lint-staged"
29
27
  },
30
28
  "keywords": [
31
29
  "cli",
@@ -52,28 +50,21 @@
52
50
  "ora": "^8.1.1"
53
51
  },
54
52
  "devDependencies": {
55
- "@eslint/js": "^9.39.2",
56
- "@eslint/json": "^0.14.0",
53
+ "@biomejs/biome": "2.4.9",
57
54
  "@types/cli-progress": "^3.11.6",
58
55
  "@types/inquirer": "^9.0.9",
59
56
  "@types/node": "^22.10.5",
60
- "@typescript-eslint/eslint-plugin": "^8.52.0",
61
- "@typescript-eslint/parser": "^8.52.0",
62
- "eslint": "^9.39.2",
63
- "eslint-config-prettier": "^10.1.8",
64
- "eslint-plugin-prettier": "^5.5.4",
65
57
  "globals": "^17.1.0",
66
58
  "husky": "^9.1.7",
67
59
  "lint-staged": "^16.2.7",
68
- "prettier": "^3.7.4",
69
60
  "ts-node": "^10.9.1",
70
61
  "typescript": "^5.7.2",
71
62
  "typescript-eslint": "^8.53.1"
72
63
  },
73
64
  "lint-staged": {
74
65
  "*.ts": [
75
- "eslint --fix",
76
- "prettier --write"
66
+ "biome format --write",
67
+ "biome lint --write"
77
68
  ]
78
69
  },
79
70
  "packageManager": "pnpm@10.27.0"