@kabran-tecnologia/kabran-config 1.12.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -81,6 +81,9 @@ export async function runTest(level, config, args) {
|
|
|
81
81
|
|
|
82
82
|
console.log('\n' + '='.repeat(50));
|
|
83
83
|
console.log(`Running L${levelNumber(level)} tests: ${level}`);
|
|
84
|
+
if (testConfig.doppler) {
|
|
85
|
+
console.log('[Doppler] Secrets injection enabled');
|
|
86
|
+
}
|
|
84
87
|
console.log('='.repeat(50));
|
|
85
88
|
|
|
86
89
|
// Setup phase (if defined)
|
|
@@ -4,13 +4,19 @@
|
|
|
4
4
|
* Loads project configuration from kabran.config.mjs/js/json with fallback to defaults.
|
|
5
5
|
* Enables projects to customize validator behavior without modifying kabran-config.
|
|
6
6
|
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Smart detection of tools (ESLint, TypeScript, Prettier, Vitest, Playwright)
|
|
9
|
+
* - Automatic Doppler integration for secrets injection in tests
|
|
10
|
+
* - Convention over configuration - works out of the box
|
|
11
|
+
*
|
|
7
12
|
* @module config-loader
|
|
8
13
|
*/
|
|
9
14
|
|
|
10
|
-
import {existsSync} from 'node:fs';
|
|
15
|
+
import {existsSync, readFileSync} from 'node:fs';
|
|
11
16
|
import {readFile} from 'node:fs/promises';
|
|
12
17
|
import {join} from 'node:path';
|
|
13
18
|
import {pathToFileURL} from 'node:url';
|
|
19
|
+
import {execSync} from 'node:child_process';
|
|
14
20
|
|
|
15
21
|
/**
|
|
16
22
|
* Default configuration values.
|
|
@@ -30,6 +36,140 @@ export const DEFAULTS = {
|
|
|
30
36
|
},
|
|
31
37
|
};
|
|
32
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Config file patterns for each tool.
|
|
41
|
+
*/
|
|
42
|
+
const TOOL_CONFIGS = {
|
|
43
|
+
eslint: ['eslint.config.mjs', 'eslint.config.js', 'eslint.config.cjs', '.eslintrc.js', '.eslintrc.json', '.eslintrc.cjs'],
|
|
44
|
+
typescript: ['tsconfig.json'],
|
|
45
|
+
prettier: ['prettier.config.mjs', 'prettier.config.js', '.prettierrc', '.prettierrc.json', '.prettierrc.js'],
|
|
46
|
+
vitest: ['vitest.config.ts', 'vitest.config.mts', 'vitest.config.js', 'vitest.config.mjs'],
|
|
47
|
+
playwright: ['playwright.config.ts', 'playwright.config.js'],
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Check if any of the config files exist for a tool.
|
|
52
|
+
* @param {string} cwd - Working directory
|
|
53
|
+
* @param {string[]} configFiles - List of possible config file names
|
|
54
|
+
* @returns {boolean} True if any config file exists
|
|
55
|
+
*/
|
|
56
|
+
function hasToolConfig(cwd, configFiles) {
|
|
57
|
+
return configFiles.some(file => existsSync(join(cwd, file)));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Check if Doppler is configured for the current directory.
|
|
62
|
+
* @param {string} cwd - Working directory
|
|
63
|
+
* @returns {boolean} True if Doppler token is configured
|
|
64
|
+
*/
|
|
65
|
+
function hasDopplerConfigured(cwd) {
|
|
66
|
+
try {
|
|
67
|
+
const result = execSync('doppler configure get token', {
|
|
68
|
+
cwd,
|
|
69
|
+
stdio: 'pipe',
|
|
70
|
+
encoding: 'utf-8',
|
|
71
|
+
timeout: 5000,
|
|
72
|
+
});
|
|
73
|
+
return result.trim().length > 0;
|
|
74
|
+
} catch {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Wrap command with Doppler if configured.
|
|
81
|
+
* @param {string} cmd - Command to wrap
|
|
82
|
+
* @param {boolean} useDoppler - Whether to use Doppler
|
|
83
|
+
* @returns {string} Wrapped command
|
|
84
|
+
*/
|
|
85
|
+
export function wrapWithDoppler(cmd, useDoppler) {
|
|
86
|
+
return useDoppler ? `doppler run -- ${cmd}` : cmd;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Detect available tools and generate smart defaults.
|
|
91
|
+
* Only configures commands for tools that are actually set up in the project.
|
|
92
|
+
* @param {string} cwd - Working directory
|
|
93
|
+
* @returns {object} Detected defaults for CLI commands
|
|
94
|
+
*/
|
|
95
|
+
export function detectToolDefaults(cwd) {
|
|
96
|
+
const defaults = {
|
|
97
|
+
check: {},
|
|
98
|
+
test: {},
|
|
99
|
+
build: {},
|
|
100
|
+
ci: { steps: [] },
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const hasDoppler = hasDopplerConfigured(cwd);
|
|
104
|
+
|
|
105
|
+
// L1: Static Analysis
|
|
106
|
+
if (hasToolConfig(cwd, TOOL_CONFIGS.eslint)) {
|
|
107
|
+
defaults.check.lint = 'npx eslint .';
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (hasToolConfig(cwd, TOOL_CONFIGS.typescript)) {
|
|
111
|
+
defaults.check.types = 'npx tsc --noEmit';
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (hasToolConfig(cwd, TOOL_CONFIGS.prettier)) {
|
|
115
|
+
defaults.check.format = 'npx prettier --check .';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// L2: Unit Tests (with Doppler support)
|
|
119
|
+
if (hasToolConfig(cwd, TOOL_CONFIGS.vitest)) {
|
|
120
|
+
const cmd = 'npx vitest run';
|
|
121
|
+
defaults.test.unit = {
|
|
122
|
+
command: wrapWithDoppler(cmd, hasDoppler),
|
|
123
|
+
doppler: hasDoppler,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// L3: Integration Tests (with Doppler support)
|
|
128
|
+
const integrationConfig = join(cwd, 'vitest.integration.config.ts');
|
|
129
|
+
if (existsSync(integrationConfig)) {
|
|
130
|
+
const cmd = 'npx vitest run --config vitest.integration.config.ts';
|
|
131
|
+
defaults.test.integration = {
|
|
132
|
+
command: wrapWithDoppler(cmd, hasDoppler),
|
|
133
|
+
doppler: hasDoppler,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// L4: E2E Tests (with Doppler support)
|
|
138
|
+
if (hasToolConfig(cwd, TOOL_CONFIGS.playwright)) {
|
|
139
|
+
const cmd = 'npx playwright test';
|
|
140
|
+
defaults.test.e2e = {
|
|
141
|
+
command: wrapWithDoppler(cmd, hasDoppler),
|
|
142
|
+
doppler: hasDoppler,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Build - check if npm run build exists in package.json
|
|
147
|
+
const packageJsonPath = join(cwd, 'package.json');
|
|
148
|
+
if (existsSync(packageJsonPath)) {
|
|
149
|
+
try {
|
|
150
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
151
|
+
if (packageJson.scripts?.build) {
|
|
152
|
+
defaults.build.command = 'npm run build';
|
|
153
|
+
}
|
|
154
|
+
} catch {
|
|
155
|
+
// Ignore parse errors
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// CI steps - add detected tools
|
|
160
|
+
if (Object.keys(defaults.check).length > 0) {
|
|
161
|
+
defaults.ci.steps.push('check');
|
|
162
|
+
}
|
|
163
|
+
if (defaults.test.unit) {
|
|
164
|
+
defaults.ci.steps.push('test:unit');
|
|
165
|
+
}
|
|
166
|
+
if (defaults.build.command) {
|
|
167
|
+
defaults.ci.steps.push('build');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return defaults;
|
|
171
|
+
}
|
|
172
|
+
|
|
33
173
|
/**
|
|
34
174
|
* Configuration file names to search for, in priority order.
|
|
35
175
|
*/
|
|
@@ -91,27 +231,38 @@ async function loadJsConfig(configPath) {
|
|
|
91
231
|
/**
|
|
92
232
|
* Load project configuration with fallback to defaults.
|
|
93
233
|
*
|
|
94
|
-
*
|
|
95
|
-
* 1. kabran.config.mjs
|
|
96
|
-
* 2.
|
|
97
|
-
* 3.
|
|
234
|
+
* Configuration priority (highest to lowest):
|
|
235
|
+
* 1. Project config (kabran.config.mjs/js/json)
|
|
236
|
+
* 2. Detected tool defaults (based on existing config files)
|
|
237
|
+
* 3. Static defaults (validators)
|
|
98
238
|
*
|
|
99
|
-
*
|
|
239
|
+
* Features:
|
|
240
|
+
* - Smart detection of ESLint, TypeScript, Prettier, Vitest, Playwright
|
|
241
|
+
* - Automatic Doppler integration for secrets in tests
|
|
242
|
+
* - Project-specific overrides take precedence
|
|
100
243
|
*
|
|
101
244
|
* @param {string} [cwd=process.cwd()] - Directory to search for config
|
|
102
245
|
* @returns {Promise<object>} Merged configuration
|
|
103
246
|
*
|
|
104
247
|
* @example
|
|
248
|
+
* // Zero-config: auto-detects tools in project
|
|
105
249
|
* const config = await loadConfig();
|
|
106
|
-
*
|
|
250
|
+
* // If project has vitest.config.ts, config.test.unit.command is set
|
|
107
251
|
*
|
|
108
252
|
* @example
|
|
109
|
-
* // With custom config in kabran.config.mjs:
|
|
110
|
-
* // export default {
|
|
253
|
+
* // With custom config in kabran.config.mjs (overrides detected defaults):
|
|
254
|
+
* // export default { test: { unit: { command: 'npm test' } } }
|
|
111
255
|
* const config = await loadConfig('/path/to/project');
|
|
112
|
-
* console.log(config.readme.required); // ['Setup', 'API']
|
|
113
256
|
*/
|
|
114
257
|
export async function loadConfig(cwd = process.cwd()) {
|
|
258
|
+
// 1. Start with static defaults (validators)
|
|
259
|
+
let config = {...DEFAULTS};
|
|
260
|
+
|
|
261
|
+
// 2. Merge detected tool defaults (CLI commands)
|
|
262
|
+
const toolDefaults = detectToolDefaults(cwd);
|
|
263
|
+
config = deepMerge(config, toolDefaults);
|
|
264
|
+
|
|
265
|
+
// 3. Merge project-specific configuration (highest priority)
|
|
115
266
|
for (const fileName of CONFIG_FILES) {
|
|
116
267
|
const configPath = join(cwd, fileName);
|
|
117
268
|
|
|
@@ -125,15 +276,15 @@ export async function loadConfig(cwd = process.cwd()) {
|
|
|
125
276
|
projectConfig = await loadJsConfig(configPath);
|
|
126
277
|
}
|
|
127
278
|
|
|
128
|
-
return deepMerge(
|
|
279
|
+
return deepMerge(config, projectConfig);
|
|
129
280
|
} catch (error) {
|
|
130
|
-
// Log warning but continue with defaults
|
|
281
|
+
// Log warning but continue with detected defaults
|
|
131
282
|
console.warn(`Warning: Failed to load ${fileName}: ${error.message}`);
|
|
132
283
|
}
|
|
133
284
|
}
|
|
134
285
|
}
|
|
135
286
|
|
|
136
|
-
return
|
|
287
|
+
return config;
|
|
137
288
|
}
|
|
138
289
|
|
|
139
290
|
/**
|
package/src/scripts/setup.mjs
CHANGED
|
@@ -427,6 +427,7 @@ export function setupConfigs(projectDir, templatesDir, options) {
|
|
|
427
427
|
// Other configs (same for all types)
|
|
428
428
|
const otherConfigs = [
|
|
429
429
|
{name: 'prettier.config.mjs', src: 'prettier.config.mjs'},
|
|
430
|
+
{name: '.prettierignore', src: '.prettierignore'},
|
|
430
431
|
{name: 'commitlint.config.mjs', src: 'commitlint.config.mjs'},
|
|
431
432
|
{name: 'lint-staged.config.mjs', src: 'lint-staged.config.mjs'},
|
|
432
433
|
];
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Dependencies
|
|
2
|
+
node_modules
|
|
3
|
+
|
|
4
|
+
# Build outputs
|
|
5
|
+
dist
|
|
6
|
+
build
|
|
7
|
+
out
|
|
8
|
+
.next
|
|
9
|
+
.nuxt
|
|
10
|
+
|
|
11
|
+
# Cache directories
|
|
12
|
+
.cache
|
|
13
|
+
.vite
|
|
14
|
+
.turbo
|
|
15
|
+
.parcel-cache
|
|
16
|
+
|
|
17
|
+
# Test coverage
|
|
18
|
+
coverage
|
|
19
|
+
|
|
20
|
+
# Package manager locks (optional - some prefer to format these)
|
|
21
|
+
pnpm-lock.yaml
|
|
22
|
+
package-lock.json
|
|
23
|
+
yarn.lock
|
|
24
|
+
|
|
25
|
+
# Auto-generated files
|
|
26
|
+
*.min.js
|
|
27
|
+
*.min.css
|
|
28
|
+
|
|
29
|
+
# IDE and editor
|
|
30
|
+
.idea
|
|
31
|
+
.vscode
|
|
32
|
+
|
|
33
|
+
# OS files
|
|
34
|
+
.DS_Store
|
|
35
|
+
Thumbs.db
|