@averay/codeformat 0.2.0 → 0.2.1
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/.editorconfig +1 -1
- package/README.md +4 -6
- package/bin-codeformat.ts +179 -0
- package/eslint.config.js +24 -0
- package/lib/cssPatterns.ts +7 -0
- package/package.json +32 -30
- package/rulesets/eslint/ruleset-shared.ts +9 -5
- package/rulesets/eslint/ruleset-typescript.ts +30 -17
- package/rulesets/stylelint/ruleset-css.ts +21 -5
- package/rulesets/stylelint/ruleset-scss.ts +7 -8
- package/src/makeStylelintConfig.ts +13 -5
- package/{stylelint.config.cjs → stylelint.config.js} +2 -2
- package/bin-codeformat.sh +0 -35
- /package/{LICENSE → LICENCE} +0 -0
package/.editorconfig
CHANGED
package/README.md
CHANGED
|
@@ -35,13 +35,11 @@ export default [
|
|
|
35
35
|
|
|
36
36
|
### Stylelint
|
|
37
37
|
|
|
38
|
-
Create a `stylelint.config.
|
|
38
|
+
Create a `stylelint.config.js` file and create the configuration:
|
|
39
39
|
|
|
40
40
|
```js
|
|
41
|
-
// stylelint.config.
|
|
42
|
-
|
|
41
|
+
// stylelint.config.js
|
|
42
|
+
import { makeStylelintConfig } from '@averay/codeformat';
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
export default makeStylelintConfig();
|
|
45
45
|
```
|
|
46
|
-
|
|
47
|
-
_(Stylelint does not currently support ESM so a `.cjs` file with CommonJS import & export syntax must be used)_
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { parseArgs } from 'node:util';
|
|
6
|
+
|
|
7
|
+
import { spawn } from 'bun';
|
|
8
|
+
|
|
9
|
+
type Action = 'check' | 'fix';
|
|
10
|
+
|
|
11
|
+
// Parse input
|
|
12
|
+
const { values: options, positionals } = parseArgs({
|
|
13
|
+
args: Bun.argv,
|
|
14
|
+
options: {
|
|
15
|
+
verbose: { type: 'boolean', default: false },
|
|
16
|
+
debug: { type: 'boolean', default: false },
|
|
17
|
+
help: { type: 'boolean', default: false },
|
|
18
|
+
dir: { type: 'string', short: 'd', default: process.cwd() },
|
|
19
|
+
},
|
|
20
|
+
strict: true,
|
|
21
|
+
allowPositionals: true,
|
|
22
|
+
});
|
|
23
|
+
const { dir: projectDir } = options;
|
|
24
|
+
const [, scriptName, selectedAction, ...undefinedArgs] = positionals as [string, string, ...string[]];
|
|
25
|
+
|
|
26
|
+
const output = {
|
|
27
|
+
usage(exitCode: number = 0): never {
|
|
28
|
+
console.error(`Usage:
|
|
29
|
+
${scriptName} check [root-path]
|
|
30
|
+
${scriptName} fix [root-path]`);
|
|
31
|
+
process.exit(exitCode);
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
debug(message: string, additionalValues: unknown[] = []): void {
|
|
35
|
+
if (options.debug) {
|
|
36
|
+
console.debug(message, ...additionalValues);
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
verbose(message: string, additionalValues: unknown[] = []): void {
|
|
41
|
+
if (options.verbose) {
|
|
42
|
+
console.debug(message, ...additionalValues);
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
error(message: string, additionalValues: unknown[] = [], exitCode: number = 1): never {
|
|
47
|
+
console.error(message, ...additionalValues);
|
|
48
|
+
process.exit(exitCode);
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
async function bunx(command: string, args: string[]): Promise<void> {
|
|
53
|
+
output.verbose('Running command:', [command, ...args]);
|
|
54
|
+
|
|
55
|
+
const proc = spawn(['bun', '--bun', 'x', command, ...args], {
|
|
56
|
+
cwd: projectDir,
|
|
57
|
+
stdio: ['inherit', 'inherit', 'inherit'],
|
|
58
|
+
});
|
|
59
|
+
const exitCode = await proc.exited;
|
|
60
|
+
if (exitCode !== 0) {
|
|
61
|
+
process.exit(exitCode);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function withExts(base: string, exts: string[]): string[] {
|
|
66
|
+
return exts.map((ext) => `${base}.${ext}`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function findFirstFile(suffixes: string[]): string | undefined {
|
|
70
|
+
for (const suffix of suffixes) {
|
|
71
|
+
const filePath = path.join(projectDir, suffix);
|
|
72
|
+
if (existsSync(filePath)) {
|
|
73
|
+
const relativeFilePath = path.isAbsolute(projectDir) ? path.relative(projectDir, filePath) : filePath;
|
|
74
|
+
output.debug('Found config file:', [filePath]);
|
|
75
|
+
return relativeFilePath;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function ifConfig<T>(pathname: string | undefined, callback: (pathname: string) => T): T | undefined {
|
|
82
|
+
return pathname == null ? undefined : callback(pathname);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (options.help) {
|
|
86
|
+
output.usage();
|
|
87
|
+
}
|
|
88
|
+
if (undefinedArgs.length > 0) {
|
|
89
|
+
output.error('Unexpected additional arguments.', [undefinedArgs]);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const configPaths = {
|
|
93
|
+
prettier: findFirstFile([
|
|
94
|
+
'.prettierrc',
|
|
95
|
+
...withExts('prettier.config', ['js', 'ts', 'mjs', 'mts', 'cjs', 'cts']),
|
|
96
|
+
...withExts('.prettierrc', ['json', 'yml', 'yaml', 'json5', 'js', 'ts', 'mjs', 'mts', 'cjs', 'cts', 'toml']),
|
|
97
|
+
]),
|
|
98
|
+
eslint: findFirstFile(withExts('eslint.config', ['js', 'mjs', 'cjs', 'ts', 'mts', 'cts'])),
|
|
99
|
+
typeScript: findFirstFile(['tsconfig.json']),
|
|
100
|
+
stylelint: findFirstFile(withExts('stylelint.config', ['cjs', 'mjs', 'js'])),
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
interface Tool {
|
|
104
|
+
actions: Partial<Record<Action, string[]>> | undefined;
|
|
105
|
+
args: Partial<{
|
|
106
|
+
debug: string[];
|
|
107
|
+
}>;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const tools: Record<string, Tool> = {
|
|
111
|
+
prettier: {
|
|
112
|
+
actions: ifConfig(configPaths.prettier, (configPath) => ({
|
|
113
|
+
check: ['--check', '--config', configPath, projectDir],
|
|
114
|
+
fix: ['--write', '--config', configPath, projectDir],
|
|
115
|
+
})),
|
|
116
|
+
args: {
|
|
117
|
+
debug: ['--log-level', 'debug'],
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
tsc: {
|
|
121
|
+
actions: ifConfig(configPaths.typeScript, (configPath) => ({
|
|
122
|
+
check: ['--noEmit', '--project', configPath],
|
|
123
|
+
fix: ['--project', configPath],
|
|
124
|
+
})),
|
|
125
|
+
args: {},
|
|
126
|
+
},
|
|
127
|
+
eslint: {
|
|
128
|
+
actions: ifConfig(configPaths.eslint, (configPath) => ({
|
|
129
|
+
check: ['--config', configPath, projectDir],
|
|
130
|
+
fix: ['--fix', '--config', configPath, projectDir],
|
|
131
|
+
})),
|
|
132
|
+
args: {
|
|
133
|
+
debug: ['--debug'],
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
stylelint: {
|
|
137
|
+
actions: ifConfig(configPaths.stylelint, (configPath) => ({
|
|
138
|
+
check: ['--allow-empty-input', '--config', configPath, `${projectDir}/**/*.{css,sass,scss}`],
|
|
139
|
+
fix: ['--fix', '--allow-empty-input', '--config', configPath, `${projectDir}/**/*.{css,sass,scss}`],
|
|
140
|
+
})),
|
|
141
|
+
args: {
|
|
142
|
+
debug: ['--formatter', 'verbose'],
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
async function runTools(action: Action): Promise<void> {
|
|
148
|
+
for (const [toolName, { actions, args: additionalArgs }] of Object.entries(tools)) {
|
|
149
|
+
const actionArgs = actions?.[action];
|
|
150
|
+
if (actionArgs != null) {
|
|
151
|
+
let args = [...actionArgs];
|
|
152
|
+
if (options.debug) {
|
|
153
|
+
args = [...args, ...(additionalArgs.debug ?? [])];
|
|
154
|
+
}
|
|
155
|
+
// eslint-disable-next-line no-await-in-loop -- Must be run in series
|
|
156
|
+
await bunx(toolName, args);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
try {
|
|
162
|
+
switch (selectedAction) {
|
|
163
|
+
case 'check': {
|
|
164
|
+
await runTools('check');
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
case 'fix': {
|
|
169
|
+
await runTools('fix');
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
default: {
|
|
174
|
+
output.usage(1);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
} catch (error) {
|
|
178
|
+
output.error('Error:', [error]);
|
|
179
|
+
}
|
package/eslint.config.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import globals from 'globals';
|
|
2
|
+
|
|
1
3
|
import makeEslintConfig from './src/makeEslintConfig.ts';
|
|
2
4
|
|
|
3
5
|
export default [
|
|
@@ -5,4 +7,26 @@ export default [
|
|
|
5
7
|
ignores: ['dist/**/*.*'],
|
|
6
8
|
},
|
|
7
9
|
...makeEslintConfig({ tsconfigPath: './tsconfig.json' }),
|
|
10
|
+
{
|
|
11
|
+
languageOptions: {
|
|
12
|
+
globals: { Bun: true, ...globals.node },
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
// Rulesets
|
|
17
|
+
{
|
|
18
|
+
files: ['rulesets/**/*.ts'],
|
|
19
|
+
rules: {
|
|
20
|
+
'sort-keys': 'error', // Organise rules.
|
|
21
|
+
'unicorn/no-useless-spread': 'off', // Keep the unprefixed core rules together.
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
// CLI
|
|
26
|
+
{
|
|
27
|
+
files: ['bin-*.ts'],
|
|
28
|
+
rules: {
|
|
29
|
+
'no-process-exit': 'off',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
8
32
|
];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/* eslint require-unicode-regexp: 'off' -- Expressions are passed to Stylelint as strings so cannot use any flags in order to match their behaviour. */
|
|
2
|
+
export default {
|
|
3
|
+
bem: /^[a-z]+(?:(?:-|--|__)[a-z]+)*$/.source,
|
|
4
|
+
bemWithOptionalSingleUnderscorePrefix: /^_?[a-z]+(?:(?:-|--|__)[a-z]+)*$/.source,
|
|
5
|
+
bemWithOptionalUnderscoresPrefix: /^(?:__)?[a-z]+(?:(?:-|--|__)[a-z]+)*$/.source,
|
|
6
|
+
kebab: /^[a-z]+(?:-[a-z]+)*$/.source,
|
|
7
|
+
} satisfies Record<string, string>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@averay/codeformat",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"author": "Adam Averay (https://adamaveray.com.au/)",
|
|
5
5
|
"homepage": "https://github.com/adamaveray/codeformat",
|
|
6
6
|
"repository": {
|
|
@@ -15,46 +15,48 @@
|
|
|
15
15
|
},
|
|
16
16
|
"source": "./src/index.ts",
|
|
17
17
|
"bin": {
|
|
18
|
-
"codeformat": "bin-codeformat.
|
|
18
|
+
"codeformat": "bin-codeformat.ts"
|
|
19
19
|
},
|
|
20
20
|
"main": "./src/index.ts",
|
|
21
21
|
"scripts": {
|
|
22
22
|
"test": "bun test",
|
|
23
|
-
"format": "./bin-codeformat.
|
|
24
|
-
"lint": "./bin-codeformat.
|
|
25
|
-
"prepare": "bun --bun x husky"
|
|
23
|
+
"format": "./bin-codeformat.ts fix",
|
|
24
|
+
"lint": "./bin-codeformat.ts check",
|
|
25
|
+
"prepare": "bun --bun x husky",
|
|
26
|
+
"release": "bun run lint && bun --bun x bumpp && bun publish"
|
|
26
27
|
},
|
|
27
28
|
"dependencies": {
|
|
28
|
-
"@averay/css-properties-sort-order": "^1.0.
|
|
29
|
-
"@eslint/eslintrc": "3.
|
|
30
|
-
"@eslint/js": "9.
|
|
31
|
-
"@stylistic/eslint-plugin": "^
|
|
32
|
-
"@typescript-eslint/eslint-plugin": "8.
|
|
33
|
-
"@typescript-eslint/parser": "8.
|
|
34
|
-
"eslint-config-prettier": "10.
|
|
35
|
-
"eslint-import-resolver-typescript": "^
|
|
29
|
+
"@averay/css-properties-sort-order": "^1.0.3",
|
|
30
|
+
"@eslint/eslintrc": "^3.3.1",
|
|
31
|
+
"@eslint/js": "^9.29.0",
|
|
32
|
+
"@stylistic/eslint-plugin": "^4.4.1",
|
|
33
|
+
"@typescript-eslint/eslint-plugin": "^8.34.0",
|
|
34
|
+
"@typescript-eslint/parser": "^8.34.0",
|
|
35
|
+
"eslint-config-prettier": "^10.1.5",
|
|
36
|
+
"eslint-import-resolver-typescript": "^4.4.3",
|
|
36
37
|
"eslint-plugin-eslint-comments": "^3.2.0",
|
|
37
38
|
"eslint-plugin-import": "^2.31.0",
|
|
38
|
-
"eslint-plugin-jsdoc": "
|
|
39
|
-
"eslint-plugin-promise": "7.2.1",
|
|
40
|
-
"eslint-plugin-regexp": "2.
|
|
41
|
-
"eslint-plugin-sonarjs": "3.0.2",
|
|
42
|
-
"eslint-plugin-unicorn": "
|
|
43
|
-
"globals": "
|
|
39
|
+
"eslint-plugin-jsdoc": "^51.0.1",
|
|
40
|
+
"eslint-plugin-promise": "^7.2.1",
|
|
41
|
+
"eslint-plugin-regexp": "^2.9.0",
|
|
42
|
+
"eslint-plugin-sonarjs": "^3.0.2",
|
|
43
|
+
"eslint-plugin-unicorn": "^59.0.1",
|
|
44
|
+
"globals": "^16.2.0",
|
|
44
45
|
"postcss-scss": "^4.0.9",
|
|
45
|
-
"prettier": "3.5.
|
|
46
|
-
"stylelint": "16.
|
|
47
|
-
"stylelint-config-recommended": "
|
|
48
|
-
"stylelint-config-recommended-scss": "
|
|
49
|
-
"stylelint-config-standard": "
|
|
50
|
-
"stylelint-config-standard-scss": "
|
|
51
|
-
"stylelint-order": "^
|
|
52
|
-
"stylelint-scss": "6.
|
|
53
|
-
"typescript-eslint": "^8.
|
|
46
|
+
"prettier": "^3.5.3",
|
|
47
|
+
"stylelint": "^16.20.0",
|
|
48
|
+
"stylelint-config-recommended": "^16.0.0",
|
|
49
|
+
"stylelint-config-recommended-scss": "^15.0.1",
|
|
50
|
+
"stylelint-config-standard": "^38.0.0",
|
|
51
|
+
"stylelint-config-standard-scss": "^15.0.1",
|
|
52
|
+
"stylelint-order": "^7.0.0",
|
|
53
|
+
"stylelint-scss": "^6.12.1",
|
|
54
|
+
"typescript-eslint": "^8.34.0"
|
|
54
55
|
},
|
|
55
56
|
"devDependencies": {
|
|
56
57
|
"@types/bun": "latest",
|
|
57
|
-
"
|
|
58
|
-
"
|
|
58
|
+
"bumpp": "^10.1.1",
|
|
59
|
+
"husky": "^9.1.7",
|
|
60
|
+
"typescript": "^5.8.3"
|
|
59
61
|
}
|
|
60
62
|
}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
/* eslint sort-keys: 'error' -- Organise rules. */
|
|
2
|
-
/* eslint unicorn/no-useless-spread: "off" -- Keep the unprefixed core rules together. */
|
|
3
1
|
/* eslint import/no-named-as-default-member: "off" -- All plugins follow the same naming conventions. */
|
|
4
2
|
|
|
5
3
|
import stylisticPlugin from '@stylistic/eslint-plugin';
|
|
@@ -21,6 +19,7 @@ export default {
|
|
|
21
19
|
'consistent-return': 'error',
|
|
22
20
|
'consistent-this': ['error', '_this'],
|
|
23
21
|
'constructor-super': 'error',
|
|
22
|
+
curly: ['error', 'all'],
|
|
24
23
|
'default-case': 'error',
|
|
25
24
|
'default-case-last': 'error',
|
|
26
25
|
'default-param-last': 'error',
|
|
@@ -239,7 +238,7 @@ export default {
|
|
|
239
238
|
],
|
|
240
239
|
'import/no-commonjs': 'error',
|
|
241
240
|
'import/no-cycle': ['error', { ignoreExternal: true }],
|
|
242
|
-
'import/no-duplicates':
|
|
241
|
+
'import/no-duplicates': 'error',
|
|
243
242
|
'import/no-dynamic-require': 'error',
|
|
244
243
|
'import/no-empty-named-blocks': 'error',
|
|
245
244
|
'import/no-extraneous-dependencies': 'error',
|
|
@@ -259,7 +258,7 @@ export default {
|
|
|
259
258
|
'newlines-between': 'always',
|
|
260
259
|
},
|
|
261
260
|
],
|
|
262
|
-
'import/prefer-default-export': '
|
|
261
|
+
'import/prefer-default-export': 'off', // Causes friction when creating a utilities file with a single export in advance of adding additional exports.
|
|
263
262
|
|
|
264
263
|
...jsdocPlugin.configs.recommended.rules,
|
|
265
264
|
'jsdoc/check-indentation': 'error',
|
|
@@ -283,6 +282,7 @@ export default {
|
|
|
283
282
|
'jsdoc/tag-lines': ['error', 'any', { startLines: 1 }],
|
|
284
283
|
|
|
285
284
|
...promisePlugin.configs.recommended.rules,
|
|
285
|
+
'promise/always-return': ['error', { ignoreAssignmentVariable: ['globalThis', 'window'], ignoreLastCallback: true }],
|
|
286
286
|
'promise/no-multiple-resolved': 'error',
|
|
287
287
|
|
|
288
288
|
...regexpPlugin.configs.recommended.rules,
|
|
@@ -305,11 +305,14 @@ export default {
|
|
|
305
305
|
|
|
306
306
|
...sonarjsPlugin.configs.recommended.rules,
|
|
307
307
|
'sonarjs/cognitive-complexity': 'off',
|
|
308
|
+
'sonarjs/function-return-type': 'off', // Overly restrictive.
|
|
308
309
|
'sonarjs/max-switch-cases': 'off',
|
|
309
310
|
'sonarjs/no-inverted-boolean-check': 'error',
|
|
310
311
|
'sonarjs/no-nested-template-literals': 'off',
|
|
312
|
+
'sonarjs/no-selector-parameter': 'off', // Overly restrictive.
|
|
311
313
|
'sonarjs/no-small-switch': 'off',
|
|
312
314
|
'sonarjs/prefer-immediate-return': 'off',
|
|
315
|
+
'sonarjs/prefer-regexp-exec': 'off',
|
|
313
316
|
'sonarjs/prefer-single-boolean-return': 'off',
|
|
314
317
|
|
|
315
318
|
...stylisticPlugin.configs['recommended-flat'].rules,
|
|
@@ -336,9 +339,10 @@ export default {
|
|
|
336
339
|
'@stylistic/semi': 'off',
|
|
337
340
|
|
|
338
341
|
...unicornPlugin.configs.recommended.rules,
|
|
342
|
+
'unicorn/consistent-function-scoping': ['error', { checkArrowFunctions: false }],
|
|
339
343
|
'unicorn/filename-case': 'off',
|
|
340
344
|
'unicorn/no-null': 'off',
|
|
341
|
-
'unicorn/no-
|
|
345
|
+
'unicorn/no-useless-undefined': 'off', // Conflicts with `consistent-return`.
|
|
342
346
|
'unicorn/prefer-event-target': 'error',
|
|
343
347
|
'unicorn/prefer-query-selector': 'off',
|
|
344
348
|
'unicorn/prevent-abbreviations': 'off',
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
/* eslint unicorn/no-useless-spread: "off" -- Keep the unprefixed core rules together. */
|
|
2
|
-
/* eslint sort-keys: "error" -- Organise rules */
|
|
3
|
-
|
|
4
1
|
import js from '@eslint/js';
|
|
5
2
|
import typescriptPlugin from '@typescript-eslint/eslint-plugin';
|
|
6
3
|
import { type TSESLint } from '@typescript-eslint/utils';
|
|
@@ -32,6 +29,7 @@ export default {
|
|
|
32
29
|
'no-magic-numbers': 'off',
|
|
33
30
|
'no-redeclare': 'off',
|
|
34
31
|
'no-restricted-imports': 'off',
|
|
32
|
+
'no-restricted-syntax': ['error', 'WithStatement'],
|
|
35
33
|
'no-return-await': 'off',
|
|
36
34
|
'no-shadow': 'off',
|
|
37
35
|
'no-throw-literal': 'off',
|
|
@@ -67,57 +65,61 @@ export default {
|
|
|
67
65
|
/* eslint-disable sort-keys -- Logically ordered */
|
|
68
66
|
{
|
|
69
67
|
selector: 'default',
|
|
70
|
-
format: ['
|
|
68
|
+
format: ['strictCamelCase'],
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
selector: 'import',
|
|
72
|
+
format: ['strictCamelCase', 'StrictPascalCase', 'UPPER_CASE'],
|
|
71
73
|
},
|
|
72
74
|
{
|
|
73
75
|
selector: 'variable',
|
|
74
76
|
modifiers: ['const'],
|
|
75
|
-
format: ['
|
|
77
|
+
format: ['strictCamelCase', 'StrictPascalCase', 'UPPER_CASE'],
|
|
76
78
|
},
|
|
77
79
|
{
|
|
78
80
|
selector: 'variable',
|
|
79
81
|
modifiers: ['const'],
|
|
80
82
|
filter: { regex: /^_(static|\d+)?$/u.source, match: true },
|
|
81
|
-
format: ['
|
|
83
|
+
format: ['strictCamelCase'],
|
|
82
84
|
leadingUnderscore: 'allow',
|
|
83
85
|
},
|
|
84
86
|
{
|
|
85
87
|
selector: 'parameter',
|
|
86
|
-
format: ['
|
|
88
|
+
format: ['strictCamelCase'],
|
|
87
89
|
leadingUnderscore: 'allow',
|
|
88
90
|
},
|
|
89
91
|
{
|
|
90
92
|
selector: 'property',
|
|
91
|
-
format: ['
|
|
93
|
+
format: ['strictCamelCase', 'UPPER_CASE'],
|
|
92
94
|
},
|
|
93
95
|
{
|
|
94
96
|
selector: 'classProperty',
|
|
95
97
|
modifiers: ['static'],
|
|
96
|
-
format: ['
|
|
98
|
+
format: ['strictCamelCase', 'StrictPascalCase', 'UPPER_CASE'],
|
|
97
99
|
},
|
|
98
100
|
{
|
|
99
101
|
selector: 'enumMember',
|
|
100
|
-
format: ['
|
|
102
|
+
format: ['strictCamelCase', 'StrictPascalCase', 'UPPER_CASE'],
|
|
101
103
|
},
|
|
102
104
|
{
|
|
103
105
|
selector: 'function',
|
|
104
|
-
format: ['
|
|
106
|
+
format: ['strictCamelCase', 'StrictPascalCase'],
|
|
105
107
|
},
|
|
106
108
|
{
|
|
107
109
|
selector: 'typeLike',
|
|
108
|
-
format: ['
|
|
110
|
+
format: ['StrictPascalCase'],
|
|
109
111
|
},
|
|
110
112
|
{
|
|
111
113
|
selector: ['objectLiteralProperty'],
|
|
112
|
-
format:
|
|
114
|
+
format: null,
|
|
113
115
|
},
|
|
114
116
|
{
|
|
115
117
|
selector: ['classProperty', 'objectLiteralMethod'],
|
|
116
|
-
format: ['
|
|
118
|
+
format: ['strictCamelCase', 'UPPER_CASE'],
|
|
117
119
|
},
|
|
118
120
|
{
|
|
119
121
|
selector: 'typeParameter',
|
|
120
|
-
format: ['
|
|
122
|
+
format: ['StrictPascalCase'],
|
|
121
123
|
custom: { regex: /^([A-Z]|T[A-Z][a-zA-Z]+|key)$/u.source, match: true },
|
|
122
124
|
},
|
|
123
125
|
/* eslint-enable sort-keys -- Logically ordered */
|
|
@@ -146,7 +148,7 @@ export default {
|
|
|
146
148
|
{
|
|
147
149
|
detectObjects: true,
|
|
148
150
|
enforceConst: true,
|
|
149
|
-
ignore: [-1, 0, 1],
|
|
151
|
+
ignore: [-1, 0, 1, 2, 100, '0n'],
|
|
150
152
|
ignoreArrayIndexes: true,
|
|
151
153
|
ignoreClassFieldInitialValues: true,
|
|
152
154
|
ignoreDefaultValues: true,
|
|
@@ -211,14 +213,25 @@ export default {
|
|
|
211
213
|
'error',
|
|
212
214
|
{ allowNullableObject: false, allowNullableString: false, allowNumber: false, allowString: false },
|
|
213
215
|
],
|
|
214
|
-
'@typescript-eslint/switch-exhaustiveness-check':
|
|
216
|
+
'@typescript-eslint/switch-exhaustiveness-check': [
|
|
217
|
+
'error',
|
|
218
|
+
{
|
|
219
|
+
allowDefaultCaseForExhaustiveSwitch: false,
|
|
220
|
+
considerDefaultExhaustiveForUnions: true,
|
|
221
|
+
requireDefaultForNonUnion: true,
|
|
222
|
+
},
|
|
223
|
+
],
|
|
215
224
|
'@typescript-eslint/triple-slash-reference': 'error',
|
|
216
225
|
'@typescript-eslint/unbound-method': 'off', // Does not support @autobind nor recognise binding in constructors
|
|
217
226
|
'@typescript-eslint/unified-signatures': 'off',
|
|
218
227
|
|
|
228
|
+
'import/no-duplicates': 'off', // Breaks if importing both default and named exports as types (https://github.com/import-js/eslint-plugin-import/issues/2007).
|
|
229
|
+
|
|
219
230
|
'jsdoc/no-types': 'error',
|
|
220
231
|
'jsdoc/require-param-type': 'off',
|
|
221
232
|
'jsdoc/require-returns-type': 'off',
|
|
233
|
+
|
|
234
|
+
'sonarjs/super-invocation': 'off', // Causes issues and is enforced by TypeScript already.
|
|
222
235
|
} satisfies TSESLint.FlatConfig.Rules;
|
|
223
236
|
|
|
224
237
|
export const moduleDeclarations = {
|
|
@@ -1,22 +1,38 @@
|
|
|
1
|
-
/* eslint sort-keys: "error" -- Organise rules. */
|
|
2
|
-
/* eslint unicorn/no-useless-spread: "off" -- Keep the unprefixed core rules together. */
|
|
3
|
-
|
|
4
1
|
import propertiesOrder from '@averay/css-properties-sort-order';
|
|
5
2
|
import recommended from 'stylelint-config-recommended';
|
|
6
3
|
import standard from 'stylelint-config-standard';
|
|
7
4
|
|
|
5
|
+
import patterns from '../../lib/cssPatterns.ts';
|
|
6
|
+
|
|
8
7
|
export default {
|
|
9
8
|
...recommended.rules,
|
|
10
9
|
...standard.rules,
|
|
11
10
|
|
|
11
|
+
// Core rules
|
|
12
12
|
...{
|
|
13
|
-
'at-rule-empty-line-before': null,
|
|
14
13
|
'color-named': 'never',
|
|
15
|
-
'comment-empty-line-before': null,
|
|
16
14
|
'function-url-no-scheme-relative': true,
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
// Disable Prettier conflicts
|
|
18
|
+
...{
|
|
19
|
+
'at-rule-empty-line-before': null,
|
|
20
|
+
'comment-empty-line-before': null,
|
|
17
21
|
'rule-empty-line-before': null,
|
|
18
22
|
},
|
|
19
23
|
|
|
24
|
+
// Patterns
|
|
25
|
+
...{
|
|
26
|
+
'container-name-pattern': patterns.bem,
|
|
27
|
+
'custom-media-pattern': patterns.bem,
|
|
28
|
+
'custom-property-pattern': patterns.bem,
|
|
29
|
+
'keyframes-name-pattern': patterns.bem,
|
|
30
|
+
'layer-name-pattern': patterns.bem,
|
|
31
|
+
'selector-class-pattern': patterns.bemWithOptionalUnderscoresPrefix,
|
|
32
|
+
'selector-id-pattern': patterns.kebab,
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
// Extensions
|
|
20
36
|
'order/order': ['custom-properties', 'declarations'],
|
|
21
37
|
'order/properties-order': [propertiesOrder, { unspecified: 'bottomAlphabetical' }],
|
|
22
38
|
};
|
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
/* eslint sort-keys: "error" -- Organise rules. */
|
|
2
|
-
/* eslint unicorn/no-useless-spread: "off" -- Keep the unprefixed core rules together. */
|
|
3
|
-
|
|
4
1
|
import recommended from 'stylelint-config-recommended-scss';
|
|
5
2
|
import standard from 'stylelint-config-standard-scss';
|
|
6
3
|
|
|
7
|
-
|
|
4
|
+
import patterns from '../../lib/cssPatterns.ts';
|
|
8
5
|
|
|
9
6
|
export default {
|
|
10
7
|
...recommended.rules,
|
|
11
8
|
...standard.rules,
|
|
12
9
|
|
|
13
|
-
// Disable Prettier
|
|
10
|
+
// Disable Prettier conflicts
|
|
14
11
|
...{
|
|
15
12
|
'scss/at-else-closing-brace-newline-after': null,
|
|
16
13
|
'scss/at-else-closing-brace-space-after': null,
|
|
@@ -27,7 +24,9 @@ export default {
|
|
|
27
24
|
'scss/operator-no-newline-before': null,
|
|
28
25
|
'scss/operator-no-unspaced': null,
|
|
29
26
|
},
|
|
30
|
-
|
|
31
|
-
'scss/at-
|
|
32
|
-
'scss/
|
|
27
|
+
|
|
28
|
+
'scss/at-function-pattern': patterns.bemWithOptionalSingleUnderscorePrefix,
|
|
29
|
+
'scss/at-mixin-pattern': patterns.bemWithOptionalSingleUnderscorePrefix,
|
|
30
|
+
'scss/dollar-variable-pattern': patterns.bemWithOptionalSingleUnderscorePrefix,
|
|
31
|
+
'scss/percent-placeholder-pattern': patterns.bemWithOptionalSingleUnderscorePrefix,
|
|
33
32
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint sort-keys: "error" -- Organise rules */
|
|
2
2
|
|
|
3
3
|
import postcssScss from 'postcss-scss';
|
|
4
|
-
import { type Config } from 'stylelint';
|
|
4
|
+
import { type Config, type CustomSyntax } from 'stylelint';
|
|
5
5
|
import orderPlugin from 'stylelint-order';
|
|
6
6
|
import scssPlugin from 'stylelint-scss';
|
|
7
7
|
|
|
@@ -10,11 +10,13 @@ import rulesetStylelintScss from '../rulesets/stylelint/ruleset-scss.ts';
|
|
|
10
10
|
|
|
11
11
|
import extensions from './extensions.ts';
|
|
12
12
|
|
|
13
|
+
type ConfigRules = Config['rules'];
|
|
14
|
+
|
|
13
15
|
/**
|
|
14
16
|
* @returns The complete Stylelint config.
|
|
15
17
|
*/
|
|
16
18
|
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type,@typescript-eslint/explicit-module-boundary-types -- Preserve specific object shape.
|
|
17
|
-
export default function makeStylelintConfig() {
|
|
19
|
+
export default function makeStylelintConfig(cssRules: ConfigRules = {}, scssRules: ConfigRules = {}) {
|
|
18
20
|
return {
|
|
19
21
|
defaultSeverity: 'error',
|
|
20
22
|
ignoreFiles: ['**/*.min.*'],
|
|
@@ -22,15 +24,21 @@ export default function makeStylelintConfig() {
|
|
|
22
24
|
reportDescriptionlessDisables: true,
|
|
23
25
|
reportInvalidScopeDisables: true,
|
|
24
26
|
reportNeedlessDisables: true,
|
|
25
|
-
rules:
|
|
27
|
+
rules: {
|
|
28
|
+
...rulesetStylelintCss,
|
|
29
|
+
...cssRules,
|
|
30
|
+
},
|
|
26
31
|
|
|
27
32
|
// eslint-disable-next-line sort-keys -- Logically positioned.
|
|
28
33
|
overrides: [
|
|
29
34
|
{
|
|
30
|
-
customSyntax: postcssScss,
|
|
35
|
+
customSyntax: postcssScss as unknown as CustomSyntax,
|
|
31
36
|
files: extensions.scss.map((ext) => `**/*.${ext}`), // Does not support glob braces
|
|
32
37
|
plugins: [scssPlugin],
|
|
33
|
-
rules:
|
|
38
|
+
rules: {
|
|
39
|
+
...rulesetStylelintScss,
|
|
40
|
+
...scssRules,
|
|
41
|
+
},
|
|
34
42
|
},
|
|
35
43
|
],
|
|
36
44
|
} satisfies Config;
|
package/bin-codeformat.sh
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
#!/bin/sh
|
|
2
|
-
|
|
3
|
-
set -e
|
|
4
|
-
|
|
5
|
-
bunx() {
|
|
6
|
-
bun --bun x "$@"
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
# Parse arguments
|
|
10
|
-
ACTION="$1"
|
|
11
|
-
DIR="$2"
|
|
12
|
-
if [ "$DIR" = '' ]; then
|
|
13
|
-
DIR='.'
|
|
14
|
-
fi
|
|
15
|
-
|
|
16
|
-
CONFIG_PATH_TYPESCRIPT="$DIR/tsconfig.json"
|
|
17
|
-
|
|
18
|
-
if [ "$ACTION" = 'check' ]; then
|
|
19
|
-
bunx prettier --check "$DIR"
|
|
20
|
-
bunx eslint "$DIR"
|
|
21
|
-
if [ -f "$CONFIG_PATH_TYPESCRIPT" ]; then
|
|
22
|
-
bunx tsc --noEmit --project "$DIR/tsconfig.json"
|
|
23
|
-
fi
|
|
24
|
-
bunx stylelint --allow-empty-input "$DIR/**/*.{css,sass,scss}"
|
|
25
|
-
elif [ "$ACTION" = 'fix' ]; then
|
|
26
|
-
bunx prettier --write "$DIR"
|
|
27
|
-
bunx eslint --fix "$DIR"
|
|
28
|
-
bunx stylelint --fix --allow-empty-input "$DIR/**/*.{css,sass,scss}"
|
|
29
|
-
else
|
|
30
|
-
# Invalid/unset arguments
|
|
31
|
-
echo "Usage:
|
|
32
|
-
$0 check [root-path]
|
|
33
|
-
$0 fix [root-path]" >&2
|
|
34
|
-
exit 1
|
|
35
|
-
fi
|
/package/{LICENSE → LICENCE}
RENAMED
|
File without changes
|