@naturalcycles/dev-lib 20.16.1 → 20.18.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/cfg/biome.jsonc +5 -11
- package/cfg/oxlint.config.json +1 -0
- package/cfg/vitest.config.d.ts +6 -1
- package/cfg/vitest.config.js +65 -66
- package/dist/bin/dev-lib.js +21 -10
- package/dist/build.util.d.ts +2 -4
- package/dist/build.util.js +3 -1
- package/dist/commitlint.d.ts +15 -0
- package/dist/commitlint.js +106 -0
- package/dist/config.d.ts +20 -0
- package/dist/config.js +20 -0
- package/dist/lint.util.d.ts +2 -1
- package/dist/lint.util.js +9 -21
- package/package.json +1 -3
package/cfg/biome.jsonc
CHANGED
|
@@ -3,18 +3,12 @@
|
|
|
3
3
|
"root": false,
|
|
4
4
|
"files": {
|
|
5
5
|
"includes": [
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"!**/*.css",
|
|
11
|
-
"!**/*.scss",
|
|
12
|
-
"!**/tsconfig.json",
|
|
13
|
-
"!**/tsconfig.*.json",
|
|
6
|
+
"**/*.ts",
|
|
7
|
+
"**/*.tsx",
|
|
8
|
+
"**/*.js",
|
|
9
|
+
"**/*.jsx",
|
|
14
10
|
"!**/__exclude",
|
|
15
|
-
"!**/try.ts"
|
|
16
|
-
"!**/*.compact.json",
|
|
17
|
-
"!**/*.mock.json"
|
|
11
|
+
"!**/try.ts"
|
|
18
12
|
]
|
|
19
13
|
},
|
|
20
14
|
"formatter": {
|
package/cfg/oxlint.config.json
CHANGED
package/cfg/vitest.config.d.ts
CHANGED
|
@@ -10,10 +10,15 @@ import type { InlineConfig } from 'vitest/node'
|
|
|
10
10
|
// bail: 1,
|
|
11
11
|
})
|
|
12
12
|
|
|
13
|
+
Pass `import.meta.dirname` as cwd if running from a monorepo.
|
|
14
|
+
|
|
13
15
|
*/
|
|
14
16
|
export function defineVitestConfig(config?: Partial<ViteUserConfig>, cwd?: string): ViteUserConfig
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Pass `import.meta.dirname` as cwd if running from a monorepo.
|
|
20
|
+
*/
|
|
21
|
+
export function getSharedConfig(cwd?: string): InlineConfig
|
|
17
22
|
|
|
18
23
|
export const CollectReporter: any
|
|
19
24
|
export const SummaryReporter: any
|
package/cfg/vitest.config.js
CHANGED
|
@@ -37,13 +37,10 @@ if (silent) {
|
|
|
37
37
|
* })
|
|
38
38
|
*/
|
|
39
39
|
export function defineVitestConfig(config, cwd) {
|
|
40
|
-
const setupFiles = getSetupFiles(testType, cwd)
|
|
41
|
-
|
|
42
40
|
const mergedConfig = defineConfig({
|
|
43
41
|
...config,
|
|
44
42
|
test: {
|
|
45
|
-
...
|
|
46
|
-
setupFiles,
|
|
43
|
+
...getSharedConfig(cwd),
|
|
47
44
|
...config?.test,
|
|
48
45
|
},
|
|
49
46
|
})
|
|
@@ -70,65 +67,67 @@ export function defineVitestConfig(config, cwd) {
|
|
|
70
67
|
/**
|
|
71
68
|
* Shared config for Vitest.
|
|
72
69
|
*/
|
|
73
|
-
export
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
70
|
+
export function getSharedConfig(cwd) {
|
|
71
|
+
return {
|
|
72
|
+
pool,
|
|
73
|
+
maxWorkers,
|
|
74
|
+
isolate: false,
|
|
75
|
+
watch: false,
|
|
76
|
+
// dir: 'src',
|
|
77
|
+
restoreMocks: true,
|
|
78
|
+
silent,
|
|
79
|
+
setupFiles: getSetupFiles(testType, cwd),
|
|
80
|
+
logHeapUsage: true,
|
|
81
|
+
testTimeout: 60_000,
|
|
82
|
+
slowTestThreshold: isCI ? 500 : 300, // higher threshold in CI
|
|
83
|
+
sequence: {
|
|
84
|
+
sequencer: VitestAlphabeticSequencer,
|
|
85
|
+
// shuffle: {
|
|
86
|
+
// files: true,
|
|
87
|
+
// tests: false,
|
|
88
|
+
// },
|
|
89
|
+
// seed: 1, // this makes the order of tests deterministic (but still not alphabetic)
|
|
90
|
+
},
|
|
91
|
+
include,
|
|
92
|
+
exclude,
|
|
93
|
+
reporters: [
|
|
94
|
+
'default',
|
|
95
|
+
new SummaryReporter(),
|
|
96
|
+
junitReporterEnabled && [
|
|
97
|
+
'junit',
|
|
98
|
+
{
|
|
99
|
+
suiteName: `${testType} tests`,
|
|
100
|
+
// classNameTemplate: '{filename} - {classname}',
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
].filter(Boolean),
|
|
104
|
+
// outputFile location is specified for compatibility with the previous jest config
|
|
105
|
+
outputFile: junitReporterEnabled ? `./tmp/jest/${testType}.xml` : undefined,
|
|
106
|
+
coverage: {
|
|
107
|
+
enabled: coverageEnabled,
|
|
108
|
+
reporter: ['html', 'lcov', 'json', 'json-summary', !isCI && 'text'].filter(Boolean),
|
|
109
|
+
include: ['src/**/*.{ts,tsx}'],
|
|
110
|
+
exclude: [
|
|
111
|
+
'**/__exclude/**',
|
|
112
|
+
'scripts/**',
|
|
113
|
+
'public/**',
|
|
114
|
+
'src/index.{ts,tsx}',
|
|
115
|
+
'src/test/**',
|
|
116
|
+
'src/typings/**',
|
|
117
|
+
'src/{env,environment,environments}/**',
|
|
118
|
+
'src/bin/**',
|
|
119
|
+
'src/vendor/**',
|
|
120
|
+
'**/*.test.*',
|
|
121
|
+
'**/*.script.*',
|
|
122
|
+
'**/*.module.*',
|
|
123
|
+
'**/*.mock.*',
|
|
124
|
+
'**/*.page.{ts,tsx}',
|
|
125
|
+
'**/*.component.{ts,tsx}',
|
|
126
|
+
'**/*.directive.{ts,tsx}',
|
|
127
|
+
'**/*.modal.{ts,tsx}',
|
|
128
|
+
],
|
|
129
|
+
},
|
|
130
|
+
}
|
|
132
131
|
}
|
|
133
132
|
|
|
134
133
|
function doesItRunInIDE() {
|
|
@@ -184,14 +183,14 @@ function isRunningAllTests() {
|
|
|
184
183
|
return !hasPositionalArgs
|
|
185
184
|
}
|
|
186
185
|
|
|
187
|
-
function getSetupFiles(testType, cwd =
|
|
186
|
+
function getSetupFiles(testType, cwd = process.cwd()) {
|
|
188
187
|
// Set 'setupFiles' only if setup files exist
|
|
189
188
|
const setupFiles = []
|
|
190
189
|
if (fs.existsSync(`${cwd}/src/test/setupVitest.ts`)) {
|
|
191
|
-
setupFiles.push(
|
|
190
|
+
setupFiles.push(`${cwd}/src/test/setupVitest.ts`)
|
|
192
191
|
}
|
|
193
192
|
if (fs.existsSync(`${cwd}/src/test/setupVitest.${testType}.ts`)) {
|
|
194
|
-
setupFiles.push(
|
|
193
|
+
setupFiles.push(`${cwd}/src/test/setupVitest.${testType}.ts`)
|
|
195
194
|
}
|
|
196
195
|
return setupFiles
|
|
197
196
|
}
|
package/dist/bin/dev-lib.js
CHANGED
|
@@ -5,17 +5,23 @@ import { _assert } from '@naturalcycles/js-lib/error/assert.js';
|
|
|
5
5
|
import { fs2 } from '@naturalcycles/nodejs-lib/fs2';
|
|
6
6
|
import { runScript } from '@naturalcycles/nodejs-lib/runScript';
|
|
7
7
|
import { buildCopy, buildProd, runTSCInFolders } from '../build.util.js';
|
|
8
|
-
import {
|
|
8
|
+
import { runCommitlint } from '../commitlint.js';
|
|
9
|
+
import { eslintAll, lintAllCommand, lintStagedCommand, requireOxlintConfig, runBiome, runOxlint, runPrettier, stylelintAll, } from '../lint.util.js';
|
|
9
10
|
import { runTest } from '../test.util.js';
|
|
10
11
|
const commands = [
|
|
11
12
|
new Separator(), // build
|
|
13
|
+
{ name: 'check', fn: check, desc: '"Run all possible checks": lint, typecheck, then test.' },
|
|
14
|
+
{ name: 'bt', fn: bt, desc: 'Build & Test: run "typecheck" (via oxlint) and then "test".' },
|
|
12
15
|
{
|
|
13
16
|
name: 'typecheck',
|
|
14
|
-
fn:
|
|
15
|
-
desc: 'Run typecheck
|
|
17
|
+
fn: typecheckWithOxlint,
|
|
18
|
+
desc: 'Run typecheck via oxlint --type-aware',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: 'typecheck-with-tsc',
|
|
22
|
+
fn: typecheckWithTSC,
|
|
23
|
+
desc: 'Run typecheck (tsc) in folders (src, scripts, e2e) if there is tsconfig.json present. Deprecated, use oxlint type-checking instead.',
|
|
16
24
|
},
|
|
17
|
-
{ name: 'bt', fn: bt, desc: 'Build & Test: run "typecheck" (tsc) and then "test".' },
|
|
18
|
-
{ name: 'check', fn: lbt, desc: '"Run all possible checks": lint, typecheck, then test.' },
|
|
19
25
|
{
|
|
20
26
|
name: 'build',
|
|
21
27
|
fn: buildProd,
|
|
@@ -100,7 +106,7 @@ const commands = [
|
|
|
100
106
|
desc: 'Run stylelint with auto-fix disabled.',
|
|
101
107
|
},
|
|
102
108
|
{ name: 'stylelint-no-fix', cliOnly: true, fn: () => stylelintAll(false) },
|
|
103
|
-
{ name: 'commitlint', fn:
|
|
109
|
+
{ name: 'commitlint', fn: runCommitlint, desc: 'Run commitlint.', cliOnly: true },
|
|
104
110
|
new Separator(), // interactive-only
|
|
105
111
|
{
|
|
106
112
|
name: 'exit',
|
|
@@ -145,15 +151,20 @@ runScript(async () => {
|
|
|
145
151
|
}
|
|
146
152
|
await commandMap[cmd].fn();
|
|
147
153
|
});
|
|
148
|
-
async function
|
|
154
|
+
async function check() {
|
|
149
155
|
await lintAllCommand();
|
|
150
|
-
|
|
156
|
+
runTest();
|
|
151
157
|
}
|
|
152
158
|
async function bt() {
|
|
153
|
-
await
|
|
159
|
+
await typecheckWithOxlint();
|
|
154
160
|
runTest();
|
|
155
161
|
}
|
|
156
|
-
async function
|
|
162
|
+
async function typecheckWithOxlint() {
|
|
163
|
+
requireOxlintConfig();
|
|
164
|
+
const fix = !CI;
|
|
165
|
+
runOxlint(fix);
|
|
166
|
+
}
|
|
167
|
+
async function typecheckWithTSC() {
|
|
157
168
|
await runTSCInFolders(['src', 'scripts', 'e2e'], ['--noEmit']);
|
|
158
169
|
}
|
|
159
170
|
async function cleanDist() {
|
package/dist/build.util.d.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
export declare function buildProd(): Promise<void>;
|
|
2
2
|
/**
|
|
3
3
|
* Use 'src' to indicate root.
|
|
4
|
+
*
|
|
5
|
+
* @deprecated - oxlint should be used for type-checking instead, it's faster.
|
|
4
6
|
*/
|
|
5
7
|
export declare function runTSCInFolders(dirs: string[], args?: string[], parallel?: boolean): Promise<void>;
|
|
6
|
-
/**
|
|
7
|
-
* Pass 'src' to run in root.
|
|
8
|
-
*/
|
|
9
|
-
export declare function runTSCInFolder(dir: string, args?: string[]): Promise<void>;
|
|
10
8
|
export declare function runTSCProd(args?: string[]): Promise<void>;
|
|
11
9
|
export declare function buildCopy(): void;
|
package/dist/build.util.js
CHANGED
|
@@ -11,6 +11,8 @@ export async function buildProd() {
|
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
13
|
* Use 'src' to indicate root.
|
|
14
|
+
*
|
|
15
|
+
* @deprecated - oxlint should be used for type-checking instead, it's faster.
|
|
14
16
|
*/
|
|
15
17
|
export async function runTSCInFolders(dirs, args = [], parallel = true) {
|
|
16
18
|
if (parallel) {
|
|
@@ -25,7 +27,7 @@ export async function runTSCInFolders(dirs, args = [], parallel = true) {
|
|
|
25
27
|
/**
|
|
26
28
|
* Pass 'src' to run in root.
|
|
27
29
|
*/
|
|
28
|
-
|
|
30
|
+
async function runTSCInFolder(dir, args = []) {
|
|
29
31
|
let configDir = dir;
|
|
30
32
|
if (dir === 'src') {
|
|
31
33
|
configDir = '';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type DevLibCommitlintConfig } from './config.js';
|
|
2
|
+
/**
|
|
3
|
+
* Validates the commit message,
|
|
4
|
+
* which is read from a file, passed as process.argv.at(-1)
|
|
5
|
+
*/
|
|
6
|
+
export declare function runCommitlint(): void;
|
|
7
|
+
/**
|
|
8
|
+
* Commit message validator following Conventional Commits specification.
|
|
9
|
+
* https://www.conventionalcommits.org/
|
|
10
|
+
*/
|
|
11
|
+
export declare function validateCommitMessage(input: string, cfg?: DevLibCommitlintConfig): CommitMessageValidationResponse;
|
|
12
|
+
export interface CommitMessageValidationResponse {
|
|
13
|
+
valid: boolean;
|
|
14
|
+
errors: string[];
|
|
15
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { _assert } from '@naturalcycles/js-lib/error';
|
|
2
|
+
import { fs2 } from '@naturalcycles/nodejs-lib/fs2';
|
|
3
|
+
import { readDevLibConfigIfPresent } from './config.js';
|
|
4
|
+
const ALLOWED_TYPES = new Set([
|
|
5
|
+
'feat',
|
|
6
|
+
'fix',
|
|
7
|
+
'chore',
|
|
8
|
+
'refactor',
|
|
9
|
+
'docs',
|
|
10
|
+
'style',
|
|
11
|
+
'test',
|
|
12
|
+
'perf',
|
|
13
|
+
'ci',
|
|
14
|
+
'build',
|
|
15
|
+
'revert',
|
|
16
|
+
]);
|
|
17
|
+
const SUBJECT_MAX_LENGTH = 120; // Only applies to subject line (first line)
|
|
18
|
+
/**
|
|
19
|
+
* Validates the commit message,
|
|
20
|
+
* which is read from a file, passed as process.argv.at(-1)
|
|
21
|
+
*/
|
|
22
|
+
export function runCommitlint() {
|
|
23
|
+
// || '.git/COMMIT_EDITMSG' // fallback is unnecessary, first argument should be always present
|
|
24
|
+
const arg1 = process.argv.at(-1);
|
|
25
|
+
_assert(arg1, 'dev-lib commitlint2 is called with $1 (first argument) missing');
|
|
26
|
+
console.log({ arg1 });
|
|
27
|
+
fs2.requireFileToExist(arg1);
|
|
28
|
+
const msg = fs2.readText(arg1);
|
|
29
|
+
console.log({ msg });
|
|
30
|
+
const devLibCfg = readDevLibConfigIfPresent();
|
|
31
|
+
console.log({ devLibCfg });
|
|
32
|
+
const { valid, errors } = validateCommitMessage(msg, devLibCfg.commitlint);
|
|
33
|
+
if (valid) {
|
|
34
|
+
console.log('✓ Valid commit message');
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
console.error('✗ Invalid commit message:');
|
|
38
|
+
for (const err of errors) {
|
|
39
|
+
console.error(` - ${err}`);
|
|
40
|
+
}
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Commit message validator following Conventional Commits specification.
|
|
45
|
+
* https://www.conventionalcommits.org/
|
|
46
|
+
*/
|
|
47
|
+
export function validateCommitMessage(input, cfg = {}) {
|
|
48
|
+
const errors = [];
|
|
49
|
+
const msg = input.trim();
|
|
50
|
+
if (!msg) {
|
|
51
|
+
return { valid: false, errors: ['Commit message is empty'] };
|
|
52
|
+
}
|
|
53
|
+
const lines = msg.split('\n');
|
|
54
|
+
const subjectLine = lines[0];
|
|
55
|
+
// Step 1: Validate subject line format
|
|
56
|
+
// Pattern: type(scope)!: description OR type!: description OR type(scope): description OR type: description
|
|
57
|
+
const subjectPattern = /^(\w+)(?:\(([^)]+)\))?(!)?\s*:\s*(.+)$/;
|
|
58
|
+
const match = subjectLine.match(subjectPattern);
|
|
59
|
+
if (!match) {
|
|
60
|
+
errors.push(`Subject line must match format: type(scope): description\n` +
|
|
61
|
+
` Got: "${subjectLine}"\n` +
|
|
62
|
+
` Examples: "feat(auth): add login", "fix: resolve crash"`);
|
|
63
|
+
return { valid: false, errors };
|
|
64
|
+
}
|
|
65
|
+
const [, type, scope, _breaking, description] = match;
|
|
66
|
+
// Step 2: Validate type
|
|
67
|
+
if (!ALLOWED_TYPES.has(type)) {
|
|
68
|
+
errors.push(`Invalid type "${type}". Allowed types: ${[...ALLOWED_TYPES].join(', ')}`);
|
|
69
|
+
}
|
|
70
|
+
// Step 3: Validate subject line length
|
|
71
|
+
if (subjectLine.length > SUBJECT_MAX_LENGTH) {
|
|
72
|
+
errors.push(`Subject line too long: ${subjectLine.length} chars (max ${SUBJECT_MAX_LENGTH})`);
|
|
73
|
+
}
|
|
74
|
+
// Step 4: Validate description is not empty
|
|
75
|
+
if (!description?.trim()) {
|
|
76
|
+
errors.push('Description after colon cannot be empty');
|
|
77
|
+
}
|
|
78
|
+
// Step 5: Validate description doesn't start with capital letter (conventional style)
|
|
79
|
+
// Disabled: many existing commits use capitals
|
|
80
|
+
// if (description && /^[A-Z]/.test(description.trim())) {
|
|
81
|
+
// errors.push('Description should start with lowercase letter')
|
|
82
|
+
// }
|
|
83
|
+
// Step 6: Validate blank line between subject and body (if body exists)
|
|
84
|
+
if (lines.length > 1 && lines[1].trim() !== '') {
|
|
85
|
+
errors.push('There must be a blank line between subject and body');
|
|
86
|
+
}
|
|
87
|
+
// Note: No line length validation for body lines - they can be any length
|
|
88
|
+
// Step 7: scope validation
|
|
89
|
+
if (cfg.requireScope && !scope) {
|
|
90
|
+
errors.push('Scope is required');
|
|
91
|
+
}
|
|
92
|
+
if (scope && cfg.allowedScopes && !cfg.allowedScopes.includes(scope)) {
|
|
93
|
+
errors.push(`Scope must be one of the allowed scopes:\n${cfg.allowedScopes.join('\n')}`);
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
valid: errors.length === 0,
|
|
97
|
+
errors,
|
|
98
|
+
// parsed: {
|
|
99
|
+
// type,
|
|
100
|
+
// scope: scope || null,
|
|
101
|
+
// breaking: !!breaking,
|
|
102
|
+
// description: description?.trim(),
|
|
103
|
+
// body: lines.slice(2).join('\n').trim() || null,
|
|
104
|
+
// },
|
|
105
|
+
};
|
|
106
|
+
}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns an empty config if the file is absent.
|
|
3
|
+
*/
|
|
4
|
+
export declare function readDevLibConfigIfPresent(): DevLibConfig;
|
|
5
|
+
export interface DevLibConfig {
|
|
6
|
+
commitlint?: DevLibCommitlintConfig;
|
|
7
|
+
}
|
|
8
|
+
export interface DevLibCommitlintConfig {
|
|
9
|
+
/**
|
|
10
|
+
* Defaults to false.
|
|
11
|
+
* If set to true - commit scope becomes required.
|
|
12
|
+
*/
|
|
13
|
+
requireScope?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* If defined - commitlint (which is run on git precommit hook) will validate that
|
|
16
|
+
* the scope is one of the allowedScopes.
|
|
17
|
+
* Empty (not present) scope will pass this rule, as it depends on the `requireScope` option instead.
|
|
18
|
+
*/
|
|
19
|
+
allowedScopes?: string[];
|
|
20
|
+
}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { AjvSchema, j } from '@naturalcycles/nodejs-lib/ajv';
|
|
2
|
+
import { fs2 } from '@naturalcycles/nodejs-lib/fs2';
|
|
3
|
+
const devLibConfigPath = 'dev-lib.config.js';
|
|
4
|
+
/**
|
|
5
|
+
* Returns an empty config if the file is absent.
|
|
6
|
+
*/
|
|
7
|
+
export function readDevLibConfigIfPresent() {
|
|
8
|
+
const cfg = fs2.pathExists(devLibConfigPath) ? fs2.readJson(devLibConfigPath) : {};
|
|
9
|
+
return devLibConfigSchema.validate(cfg);
|
|
10
|
+
}
|
|
11
|
+
const devLibConfigSchema = AjvSchema.create(j.object({
|
|
12
|
+
commitlint: j.object
|
|
13
|
+
.infer({
|
|
14
|
+
requireScope: j.boolean().optional(),
|
|
15
|
+
allowedScopes: j.array(j.string()).optional(),
|
|
16
|
+
})
|
|
17
|
+
.optional(),
|
|
18
|
+
}), {
|
|
19
|
+
inputName: 'dev-lib.config.js',
|
|
20
|
+
});
|
package/dist/lint.util.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ interface EslintAllOptions {
|
|
|
12
12
|
*/
|
|
13
13
|
export declare function eslintAll(opt?: EslintAllOptions): void;
|
|
14
14
|
export declare function runOxlint(fix?: boolean): void;
|
|
15
|
+
export declare function requireOxlintConfig(): void;
|
|
16
|
+
export declare function hasOxlintConfig(): boolean;
|
|
15
17
|
interface RunPrettierOptions {
|
|
16
18
|
experimentalCli?: boolean;
|
|
17
19
|
fix?: boolean;
|
|
@@ -19,7 +21,6 @@ interface RunPrettierOptions {
|
|
|
19
21
|
export declare function runPrettier(opt?: RunPrettierOptions): void;
|
|
20
22
|
export declare function stylelintAll(fix?: boolean): void;
|
|
21
23
|
export declare function lintStagedCommand(): Promise<void>;
|
|
22
|
-
export declare function runCommitlintCommand(): void;
|
|
23
24
|
export declare function requireActionlintVersion(): void;
|
|
24
25
|
export declare function getActionLintVersion(): SemVerString | undefined;
|
|
25
26
|
export declare function runBiome(fix?: boolean): void;
|
package/dist/lint.util.js
CHANGED
|
@@ -7,7 +7,6 @@ import { _since } from '@naturalcycles/js-lib/datetime/time.util.js';
|
|
|
7
7
|
import { _assert } from '@naturalcycles/js-lib/error/assert.js';
|
|
8
8
|
import { _filterFalsyValues } from '@naturalcycles/js-lib/object/object.util.js';
|
|
9
9
|
import { semver2 } from '@naturalcycles/js-lib/semver';
|
|
10
|
-
import { git2 } from '@naturalcycles/nodejs-lib';
|
|
11
10
|
import { dimGrey, white } from '@naturalcycles/nodejs-lib/colors';
|
|
12
11
|
import { exec2 } from '@naturalcycles/nodejs-lib/exec2';
|
|
13
12
|
import { fs2 } from '@naturalcycles/nodejs-lib/fs2';
|
|
@@ -132,8 +131,8 @@ function runESLint(extensions = eslintExtensions.split(','), fix = true) {
|
|
|
132
131
|
});
|
|
133
132
|
}
|
|
134
133
|
export function runOxlint(fix = true) {
|
|
135
|
-
|
|
136
|
-
|
|
134
|
+
if (!hasOxlintConfig()) {
|
|
135
|
+
console.log('.oxlintrc.json is not found, skipping to run oxlint');
|
|
137
136
|
return;
|
|
138
137
|
}
|
|
139
138
|
const oxlintPath = findPackageBinPath('oxlint', 'oxlint');
|
|
@@ -151,6 +150,13 @@ export function runOxlint(fix = true) {
|
|
|
151
150
|
shell: false,
|
|
152
151
|
});
|
|
153
152
|
}
|
|
153
|
+
export function requireOxlintConfig() {
|
|
154
|
+
_assert(hasOxlintConfig(), '.oxlintrc.json config is not found');
|
|
155
|
+
}
|
|
156
|
+
export function hasOxlintConfig() {
|
|
157
|
+
const oxlintConfigPath = `.oxlintrc.json`;
|
|
158
|
+
return existsSync(oxlintConfigPath);
|
|
159
|
+
}
|
|
154
160
|
const prettierPaths = [
|
|
155
161
|
// Everything inside these folders
|
|
156
162
|
`./{${prettierDirs.join(',')}}/**/*.{${prettierExtensionsAll}}`,
|
|
@@ -224,24 +230,6 @@ export async function lintStagedCommand() {
|
|
|
224
230
|
if (!success)
|
|
225
231
|
process.exit(3);
|
|
226
232
|
}
|
|
227
|
-
export function runCommitlintCommand() {
|
|
228
|
-
const editMsg = process.argv.at(-1) || '.git/COMMIT_EDITMSG';
|
|
229
|
-
// console.log(editMsg)
|
|
230
|
-
const cwd = process.cwd();
|
|
231
|
-
const localConfig = `${cwd}/commitlint.config.js`;
|
|
232
|
-
const sharedConfig = `${cfgDir}/commitlint.config.js`;
|
|
233
|
-
const config = existsSync(localConfig) ? localConfig : sharedConfig;
|
|
234
|
-
const env = {
|
|
235
|
-
GIT_BRANCH: git2.getCurrentBranchName(),
|
|
236
|
-
};
|
|
237
|
-
const commitlintPath = findPackageBinPath('@commitlint/cli', 'commitlint');
|
|
238
|
-
exec2.spawn(`${commitlintPath} --edit ${editMsg} --config ${config}`, {
|
|
239
|
-
env,
|
|
240
|
-
passProcessEnv: true, // important to pass it through, to preserve $PATH
|
|
241
|
-
forceColor: false,
|
|
242
|
-
log: false,
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
233
|
async function runKTLint(fix = true) {
|
|
246
234
|
if (!existsSync(`node_modules/@naturalcycles/ktlint`))
|
|
247
235
|
return;
|
package/package.json
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naturalcycles/dev-lib",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "20.
|
|
4
|
+
"version": "20.18.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@biomejs/biome": "^2",
|
|
7
|
-
"@commitlint/cli": "^20",
|
|
8
|
-
"@commitlint/config-conventional": "^20",
|
|
9
7
|
"@eslint/js": "^9",
|
|
10
8
|
"@inquirer/prompts": "^8",
|
|
11
9
|
"@naturalcycles/js-lib": "^15",
|