@rtorcato/js-tooling 2.5.1 ā 2.6.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/dist/cli/commands/setup-presets.js +193 -0
- package/dist/cli/commands/setup.js +46 -6
- package/dist/cli/index.js +148 -30
- package/package.json +1 -1
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
export const PRESET_NAMES = [
|
|
2
|
+
'library',
|
|
3
|
+
'web-app',
|
|
4
|
+
'node-api',
|
|
5
|
+
'nextjs-app',
|
|
6
|
+
'react-app',
|
|
7
|
+
];
|
|
8
|
+
const BASE = {
|
|
9
|
+
linting: { tool: 'biome' },
|
|
10
|
+
formatting: { tool: 'biome' },
|
|
11
|
+
testing: { framework: 'vitest', environment: 'node' },
|
|
12
|
+
gitHooks: true,
|
|
13
|
+
commitLint: true,
|
|
14
|
+
semanticRelease: false,
|
|
15
|
+
securityAutomation: true,
|
|
16
|
+
};
|
|
17
|
+
export function buildPresetConfig(name, projectName) {
|
|
18
|
+
switch (name) {
|
|
19
|
+
case 'library':
|
|
20
|
+
return {
|
|
21
|
+
...BASE,
|
|
22
|
+
projectName,
|
|
23
|
+
projectType: 'library',
|
|
24
|
+
typescript: { enabled: true, config: 'base' },
|
|
25
|
+
semanticRelease: true,
|
|
26
|
+
bundler: 'tsup',
|
|
27
|
+
};
|
|
28
|
+
case 'web-app':
|
|
29
|
+
return {
|
|
30
|
+
...BASE,
|
|
31
|
+
projectName,
|
|
32
|
+
projectType: 'web-app',
|
|
33
|
+
typescript: { enabled: true, config: 'base' },
|
|
34
|
+
testing: { framework: 'vitest', environment: 'browser' },
|
|
35
|
+
bundler: 'vite',
|
|
36
|
+
};
|
|
37
|
+
case 'node-api':
|
|
38
|
+
return {
|
|
39
|
+
...BASE,
|
|
40
|
+
projectName,
|
|
41
|
+
projectType: 'node-api',
|
|
42
|
+
typescript: { enabled: true, config: 'node' },
|
|
43
|
+
bundler: 'esbuild',
|
|
44
|
+
};
|
|
45
|
+
case 'nextjs-app':
|
|
46
|
+
return {
|
|
47
|
+
...BASE,
|
|
48
|
+
projectName,
|
|
49
|
+
projectType: 'nextjs-app',
|
|
50
|
+
typescript: { enabled: true, config: 'next' },
|
|
51
|
+
linting: { tool: 'eslint', eslintConfig: 'nextjs' },
|
|
52
|
+
formatting: { tool: 'prettier' },
|
|
53
|
+
bundler: 'none',
|
|
54
|
+
};
|
|
55
|
+
case 'react-app':
|
|
56
|
+
return {
|
|
57
|
+
...BASE,
|
|
58
|
+
projectName,
|
|
59
|
+
projectType: 'react-app',
|
|
60
|
+
typescript: { enabled: true, config: 'react' },
|
|
61
|
+
testing: { framework: 'vitest', environment: 'browser' },
|
|
62
|
+
bundler: 'vite',
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export const CONFIG_SCHEMA = {
|
|
67
|
+
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
|
68
|
+
$id: 'https://rtorcato.github.io/js-tooling/schemas/project-config.json',
|
|
69
|
+
title: 'ProjectConfig',
|
|
70
|
+
description: '@rtorcato/js-tooling setup configuration',
|
|
71
|
+
type: 'object',
|
|
72
|
+
additionalProperties: false,
|
|
73
|
+
required: [
|
|
74
|
+
'projectName',
|
|
75
|
+
'projectType',
|
|
76
|
+
'typescript',
|
|
77
|
+
'linting',
|
|
78
|
+
'formatting',
|
|
79
|
+
'testing',
|
|
80
|
+
'gitHooks',
|
|
81
|
+
'commitLint',
|
|
82
|
+
'semanticRelease',
|
|
83
|
+
'securityAutomation',
|
|
84
|
+
'bundler',
|
|
85
|
+
],
|
|
86
|
+
properties: {
|
|
87
|
+
projectName: { type: 'string', minLength: 1 },
|
|
88
|
+
projectType: {
|
|
89
|
+
type: 'string',
|
|
90
|
+
enum: ['library', 'web-app', 'node-api', 'nextjs-app', 'react-app'],
|
|
91
|
+
},
|
|
92
|
+
typescript: {
|
|
93
|
+
type: 'object',
|
|
94
|
+
additionalProperties: false,
|
|
95
|
+
required: ['enabled', 'config'],
|
|
96
|
+
properties: {
|
|
97
|
+
enabled: { type: 'boolean' },
|
|
98
|
+
config: { type: 'string', enum: ['base', 'react', 'next', 'node', 'express'] },
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
linting: {
|
|
102
|
+
type: 'object',
|
|
103
|
+
additionalProperties: false,
|
|
104
|
+
required: ['tool'],
|
|
105
|
+
properties: {
|
|
106
|
+
tool: { type: 'string', enum: ['biome', 'eslint', 'both', 'none'] },
|
|
107
|
+
eslintConfig: { type: 'string', enum: ['base', 'nextjs'] },
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
formatting: {
|
|
111
|
+
type: 'object',
|
|
112
|
+
additionalProperties: false,
|
|
113
|
+
required: ['tool'],
|
|
114
|
+
properties: { tool: { type: 'string', enum: ['biome', 'prettier', 'none'] } },
|
|
115
|
+
},
|
|
116
|
+
testing: {
|
|
117
|
+
type: 'object',
|
|
118
|
+
additionalProperties: false,
|
|
119
|
+
required: ['framework'],
|
|
120
|
+
properties: {
|
|
121
|
+
framework: { type: 'string', enum: ['vitest', 'jest', 'playwright', 'none'] },
|
|
122
|
+
environment: { type: 'string', enum: ['node', 'browser', 'both'] },
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
gitHooks: { type: 'boolean' },
|
|
126
|
+
commitLint: { type: 'boolean' },
|
|
127
|
+
semanticRelease: { type: 'boolean' },
|
|
128
|
+
securityAutomation: { type: 'boolean' },
|
|
129
|
+
bundler: { type: 'string', enum: ['tsup', 'esbuild', 'vite', 'none'] },
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
const ALLOWED_KEYS = new Set(CONFIG_SCHEMA.required);
|
|
133
|
+
export function validateProjectConfig(input) {
|
|
134
|
+
const errors = [];
|
|
135
|
+
if (typeof input !== 'object' || input === null || Array.isArray(input)) {
|
|
136
|
+
return { valid: false, errors: ['Config must be a JSON object'] };
|
|
137
|
+
}
|
|
138
|
+
const obj = input;
|
|
139
|
+
for (const key of Object.keys(obj)) {
|
|
140
|
+
if (!ALLOWED_KEYS.has(key))
|
|
141
|
+
errors.push(`Unknown field: ${key}`);
|
|
142
|
+
}
|
|
143
|
+
for (const required of CONFIG_SCHEMA.required) {
|
|
144
|
+
if (!(required in obj))
|
|
145
|
+
errors.push(`Missing required field: ${required}`);
|
|
146
|
+
}
|
|
147
|
+
return { valid: errors.length === 0, errors };
|
|
148
|
+
}
|
|
149
|
+
export function computeFileList(config) {
|
|
150
|
+
const files = ['package.json'];
|
|
151
|
+
files.push('.editorconfig', '.nvmrc', 'knip.json');
|
|
152
|
+
if (config.typescript.enabled) {
|
|
153
|
+
files.push('tsconfig.json', 'reset.d.ts');
|
|
154
|
+
}
|
|
155
|
+
if (config.linting.tool === 'biome' || config.linting.tool === 'both') {
|
|
156
|
+
files.push('biome.jsonc');
|
|
157
|
+
}
|
|
158
|
+
if (config.linting.tool === 'eslint' || config.linting.tool === 'both') {
|
|
159
|
+
files.push('eslint.config.mjs');
|
|
160
|
+
}
|
|
161
|
+
if (config.linting.tool === 'eslint') {
|
|
162
|
+
files.push('prettier.config.mjs');
|
|
163
|
+
}
|
|
164
|
+
if (config.testing.framework === 'vitest') {
|
|
165
|
+
files.push('vitest.config.ts', 'vitest.setup.ts');
|
|
166
|
+
}
|
|
167
|
+
if (config.testing.framework === 'jest') {
|
|
168
|
+
files.push('jest.config.mjs');
|
|
169
|
+
}
|
|
170
|
+
if (config.testing.framework === 'playwright') {
|
|
171
|
+
files.push('playwright.config.ts');
|
|
172
|
+
}
|
|
173
|
+
if (config.gitHooks) {
|
|
174
|
+
files.push('.husky/pre-commit', '.gitignore');
|
|
175
|
+
}
|
|
176
|
+
if (config.commitLint) {
|
|
177
|
+
files.push('.husky/commit-msg', 'commitlint.config.mjs');
|
|
178
|
+
}
|
|
179
|
+
files.push('.github/workflows/ci.yml');
|
|
180
|
+
if (config.securityAutomation) {
|
|
181
|
+
files.push('.github/dependabot.yml', '.github/workflows/codeql.yml');
|
|
182
|
+
}
|
|
183
|
+
if (config.bundler === 'tsup')
|
|
184
|
+
files.push('tsup.config.ts');
|
|
185
|
+
else if (config.bundler === 'esbuild')
|
|
186
|
+
files.push('build.mjs');
|
|
187
|
+
else if (config.bundler === 'vite')
|
|
188
|
+
files.push('vite.config.ts');
|
|
189
|
+
if (config.semanticRelease)
|
|
190
|
+
files.push('release.config.mjs');
|
|
191
|
+
files.push('README.md');
|
|
192
|
+
return files;
|
|
193
|
+
}
|
|
@@ -1,17 +1,58 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
1
2
|
import chalk from 'chalk';
|
|
2
3
|
import fs from 'fs-extra';
|
|
3
4
|
import inquirer from 'inquirer';
|
|
4
|
-
import path from 'node:path';
|
|
5
5
|
import { generateConfigs } from '../generators/index.js';
|
|
6
6
|
import { installDependencies } from '../utils/install.js';
|
|
7
|
+
import { buildPresetConfig, computeFileList, CONFIG_SCHEMA, PRESET_NAMES, validateProjectConfig, } from './setup-presets.js';
|
|
8
|
+
async function resolveConfig(options) {
|
|
9
|
+
if (options.config && options.preset) {
|
|
10
|
+
console.warn(chalk.yellow('ā ļø Both --config and --preset given; --config wins.\n'));
|
|
11
|
+
}
|
|
12
|
+
if (options.config) {
|
|
13
|
+
const configPath = path.resolve(options.config);
|
|
14
|
+
if (!(await fs.pathExists(configPath))) {
|
|
15
|
+
throw new Error(`Config file not found: ${configPath}`);
|
|
16
|
+
}
|
|
17
|
+
const raw = await fs.readJson(configPath);
|
|
18
|
+
const { valid, errors } = validateProjectConfig(raw);
|
|
19
|
+
if (!valid) {
|
|
20
|
+
throw new Error(`Invalid config:\n - ${errors.join('\n - ')}`);
|
|
21
|
+
}
|
|
22
|
+
return raw;
|
|
23
|
+
}
|
|
24
|
+
if (options.preset) {
|
|
25
|
+
if (!PRESET_NAMES.includes(options.preset)) {
|
|
26
|
+
throw new Error(`Unknown preset: ${options.preset}. Available: ${PRESET_NAMES.join(', ')}`);
|
|
27
|
+
}
|
|
28
|
+
const projectName = path.basename(path.resolve(options.directory));
|
|
29
|
+
return buildPresetConfig(options.preset, projectName);
|
|
30
|
+
}
|
|
31
|
+
return promptForConfig();
|
|
32
|
+
}
|
|
7
33
|
export async function setupProject(options) {
|
|
34
|
+
if (options.configSchema) {
|
|
35
|
+
console.log(JSON.stringify(CONFIG_SCHEMA, null, 2));
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
8
38
|
const targetDir = path.resolve(options.directory);
|
|
9
|
-
|
|
10
|
-
|
|
39
|
+
const interactive = !options.config && !options.preset;
|
|
40
|
+
const dryRun = options.dryRun === true;
|
|
41
|
+
if (interactive && !dryRun) {
|
|
42
|
+
console.log(chalk.cyan('\nš ļø Welcome to JS Tooling Setup!\n'));
|
|
43
|
+
console.log(chalk.gray(`Setting up tooling in: ${targetDir}\n`));
|
|
44
|
+
}
|
|
11
45
|
try {
|
|
12
|
-
// Check if directory exists and is writable
|
|
13
46
|
await fs.ensureDir(targetDir);
|
|
14
|
-
const config = await
|
|
47
|
+
const config = await resolveConfig(options);
|
|
48
|
+
if (dryRun) {
|
|
49
|
+
const files = computeFileList(config);
|
|
50
|
+
console.log(JSON.stringify({ directory: targetDir, config, files }, null, 2));
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (!interactive) {
|
|
54
|
+
console.log(chalk.cyan(`\nš ļø Scaffolding ${config.projectType} in ${targetDir}\n`));
|
|
55
|
+
}
|
|
15
56
|
console.log(chalk.cyan('\nš Generating configuration files...\n'));
|
|
16
57
|
await generateConfigs(config, targetDir);
|
|
17
58
|
if (!options.skipInstall) {
|
|
@@ -19,7 +60,6 @@ export async function setupProject(options) {
|
|
|
19
60
|
await installDependencies(config, targetDir);
|
|
20
61
|
}
|
|
21
62
|
console.log(chalk.green('\nā
Setup completed successfully!\n'));
|
|
22
|
-
// Show next steps
|
|
23
63
|
showNextSteps(config, targetDir);
|
|
24
64
|
}
|
|
25
65
|
catch (error) {
|
package/dist/cli/index.js
CHANGED
|
@@ -28,6 +28,10 @@ program
|
|
|
28
28
|
.description('š Setup tooling for a new or existing project')
|
|
29
29
|
.option('-d, --directory <path>', 'Target directory for setup', process.cwd())
|
|
30
30
|
.option('--skip-install', 'Skip installing dependencies')
|
|
31
|
+
.option('--preset <name>', 'Skip prompts; use defaults for a project type')
|
|
32
|
+
.option('--config <path>', 'Skip prompts; read a JSON ProjectConfig from <path>')
|
|
33
|
+
.option('--dry-run', 'Print the resolved config and file list, write nothing')
|
|
34
|
+
.option('--config-schema', 'Print the JSON Schema for ProjectConfig and exit')
|
|
31
35
|
.action(setupProject);
|
|
32
36
|
program
|
|
33
37
|
.command('copy <config>')
|
|
@@ -52,41 +56,155 @@ program
|
|
|
52
56
|
console.error(chalk.red(`\nā Error copying configuration: ${error}\n`));
|
|
53
57
|
}
|
|
54
58
|
});
|
|
59
|
+
const TOOL_CATALOG = [
|
|
60
|
+
{
|
|
61
|
+
name: 'TypeScript',
|
|
62
|
+
description: 'Base, React, Next.js, Node.js, Express tsconfig presets',
|
|
63
|
+
exports: [
|
|
64
|
+
'@rtorcato/js-tooling/typescript/base',
|
|
65
|
+
'@rtorcato/js-tooling/typescript/react',
|
|
66
|
+
'@rtorcato/js-tooling/typescript/next',
|
|
67
|
+
'@rtorcato/js-tooling/typescript/node',
|
|
68
|
+
'@rtorcato/js-tooling/typescript/express',
|
|
69
|
+
'@rtorcato/js-tooling/typescript/test',
|
|
70
|
+
'@rtorcato/js-tooling/typescript/reset',
|
|
71
|
+
],
|
|
72
|
+
fixTarget: 'tsconfig',
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: 'ESLint',
|
|
76
|
+
description: 'Base and Next.js ESLint configurations',
|
|
77
|
+
exports: ['@rtorcato/js-tooling/eslint/base', '@rtorcato/js-tooling/eslint/nextjs'],
|
|
78
|
+
fixTarget: 'eslint',
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: 'Biome',
|
|
82
|
+
description: 'Fast formatter and linter configuration',
|
|
83
|
+
exports: ['@rtorcato/js-tooling/biome'],
|
|
84
|
+
fixTarget: 'biome',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: 'Prettier',
|
|
88
|
+
description: 'Code formatter configuration',
|
|
89
|
+
exports: ['@rtorcato/js-tooling/prettier'],
|
|
90
|
+
fixTarget: 'prettier',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: 'Vitest',
|
|
94
|
+
description: 'Testing framework configuration',
|
|
95
|
+
exports: [
|
|
96
|
+
'@rtorcato/js-tooling/vitest/config',
|
|
97
|
+
'@rtorcato/js-tooling/vitest/react',
|
|
98
|
+
'@rtorcato/js-tooling/vitest/setup',
|
|
99
|
+
],
|
|
100
|
+
fixTarget: 'vitest',
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: 'Jest',
|
|
104
|
+
description: 'Testing framework presets for browser and Node.js',
|
|
105
|
+
exports: [
|
|
106
|
+
'@rtorcato/js-tooling/jest-presets/browser/jest-preset',
|
|
107
|
+
'@rtorcato/js-tooling/jest-presets/node/jest-preset',
|
|
108
|
+
],
|
|
109
|
+
fixTarget: null,
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: 'Playwright',
|
|
113
|
+
description: 'End-to-end testing configuration',
|
|
114
|
+
exports: ['@rtorcato/js-tooling/playwright'],
|
|
115
|
+
fixTarget: null,
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: 'Commitlint',
|
|
119
|
+
description: 'Conventional commit linting',
|
|
120
|
+
exports: ['@rtorcato/js-tooling/commitlint/config'],
|
|
121
|
+
fixTarget: 'commitlint',
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
name: 'Husky',
|
|
125
|
+
description: 'Git hooks for pre-commit validation',
|
|
126
|
+
exports: [],
|
|
127
|
+
fixTarget: 'husky',
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
name: 'lint-staged',
|
|
131
|
+
description: 'Run linters on staged files (pairs with Husky)',
|
|
132
|
+
exports: [],
|
|
133
|
+
fixTarget: 'husky',
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
name: 'Semantic Release',
|
|
137
|
+
description: 'Automated versioning and publishing',
|
|
138
|
+
exports: [
|
|
139
|
+
'@rtorcato/js-tooling/semantic-release',
|
|
140
|
+
'@rtorcato/js-tooling/semantic-release/github',
|
|
141
|
+
'@rtorcato/js-tooling/semantic-release/docker',
|
|
142
|
+
],
|
|
143
|
+
fixTarget: 'semantic-release',
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
name: 'tsup',
|
|
147
|
+
description: 'TypeScript bundler configuration',
|
|
148
|
+
exports: ['@rtorcato/js-tooling/tsup'],
|
|
149
|
+
fixTarget: null,
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
name: 'esbuild',
|
|
153
|
+
description: 'Fast JavaScript bundler configuration',
|
|
154
|
+
exports: ['@rtorcato/js-tooling/esbuild'],
|
|
155
|
+
fixTarget: null,
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
name: 'Vite',
|
|
159
|
+
description: 'Modern web app build tool configuration',
|
|
160
|
+
exports: ['@rtorcato/js-tooling/vite'],
|
|
161
|
+
fixTarget: null,
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
name: 'EditorConfig',
|
|
165
|
+
description: 'Cross-editor formatting consistency (.editorconfig)',
|
|
166
|
+
exports: [],
|
|
167
|
+
fixTarget: 'editorconfig',
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
name: '.nvmrc',
|
|
171
|
+
description: 'Pin Node version per repository',
|
|
172
|
+
exports: [],
|
|
173
|
+
fixTarget: 'nvmrc',
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
name: 'knip',
|
|
177
|
+
description: 'Find unused files, exports, and dependencies',
|
|
178
|
+
exports: [],
|
|
179
|
+
fixTarget: 'knip',
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
name: 'Dependabot',
|
|
183
|
+
description: 'Weekly automated dependency updates',
|
|
184
|
+
exports: [],
|
|
185
|
+
fixTarget: 'dependabot',
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
name: 'CodeQL',
|
|
189
|
+
description: 'GitHub security scanning workflow',
|
|
190
|
+
exports: [],
|
|
191
|
+
fixTarget: 'codeql',
|
|
192
|
+
},
|
|
193
|
+
];
|
|
55
194
|
program
|
|
56
195
|
.command('list')
|
|
57
196
|
.alias('ls')
|
|
58
197
|
.description('š List all available tooling configurations')
|
|
59
|
-
.
|
|
198
|
+
.option('--json', 'Emit machine-readable JSON output')
|
|
199
|
+
.action((options) => {
|
|
200
|
+
if (options.json) {
|
|
201
|
+
console.log(JSON.stringify({ tools: TOOL_CATALOG }, null, 2));
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
60
204
|
console.log(chalk.cyan('\nš ļø Available tooling configurations:\n'));
|
|
61
|
-
const
|
|
62
|
-
{
|
|
63
|
-
|
|
64
|
-
desc: 'Base, React, Next.js, Node.js, Express configurations',
|
|
65
|
-
},
|
|
66
|
-
{ name: 'ESLint', desc: 'Base and Next.js ESLint configurations' },
|
|
67
|
-
{ name: 'Biome', desc: 'Fast formatter and linter configuration' },
|
|
68
|
-
{ name: 'Prettier', desc: 'Code formatter configuration' },
|
|
69
|
-
{ name: 'Vitest', desc: 'Testing framework configuration' },
|
|
70
|
-
{
|
|
71
|
-
name: 'Jest',
|
|
72
|
-
desc: 'Testing framework presets for browser and Node.js',
|
|
73
|
-
},
|
|
74
|
-
{ name: 'Playwright', desc: 'End-to-end testing configuration' },
|
|
75
|
-
{ name: 'Commitlint', desc: 'Conventional commit linting' },
|
|
76
|
-
{ name: 'Husky', desc: 'Git hooks for pre-commit validation' },
|
|
77
|
-
{ name: 'lint-staged', desc: 'Run linters on staged files (pairs with Husky)' },
|
|
78
|
-
{ name: 'Semantic Release', desc: 'Automated versioning and publishing' },
|
|
79
|
-
{ name: 'tsup', desc: 'TypeScript bundler configuration' },
|
|
80
|
-
{ name: 'esbuild', desc: 'Fast JavaScript bundler configuration' },
|
|
81
|
-
{ name: 'EditorConfig', desc: 'Cross-editor formatting consistency (.editorconfig)' },
|
|
82
|
-
{ name: '.nvmrc', desc: 'Pin Node version per repository' },
|
|
83
|
-
{ name: 'knip', desc: 'Find unused files, exports, and dependencies' },
|
|
84
|
-
{ name: 'Dependabot', desc: 'Weekly automated dependency updates' },
|
|
85
|
-
{ name: 'CodeQL', desc: 'GitHub security scanning workflow' },
|
|
86
|
-
];
|
|
87
|
-
configs.forEach(({ name, desc }) => {
|
|
88
|
-
console.log(` ${chalk.green('ā')} ${chalk.bold(name)}: ${chalk.gray(desc)}`);
|
|
89
|
-
});
|
|
205
|
+
for (const { name, description } of TOOL_CATALOG) {
|
|
206
|
+
console.log(` ${chalk.green('ā')} ${chalk.bold(name)}: ${chalk.gray(description)}`);
|
|
207
|
+
}
|
|
90
208
|
console.log(chalk.dim('\nš” Run `js-tooling setup` for a new project'));
|
|
91
209
|
console.log(chalk.dim(' or `js-tooling fix` to apply missing pieces to an existing one\n'));
|
|
92
210
|
});
|