aberlaas-lint 2.10.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/LICENSE +9 -0
- package/configs/eslint.js +194 -0
- package/configs/prettier.js +4 -0
- package/configs/stylelint.js +38 -0
- package/lib/circleci.js +81 -0
- package/lib/css.js +73 -0
- package/lib/js.js +75 -0
- package/lib/json.js +60 -0
- package/lib/main.js +62 -0
- package/lib/yml.js +62 -0
- package/package.json +60 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Tim Carry (tim@pixelastic.com)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import js from '@eslint/js';
|
|
2
|
+
import globals from 'globals';
|
|
3
|
+
import pluginN from 'eslint-plugin-n';
|
|
4
|
+
import pluginImport from 'eslint-plugin-import';
|
|
5
|
+
import pluginJsdoc from 'eslint-plugin-jsdoc';
|
|
6
|
+
import pluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
|
|
7
|
+
// Note:
|
|
8
|
+
// It is currently required to manually add typescript and
|
|
9
|
+
// @typescript-eslint/utils to aberlaas for the plugin to work
|
|
10
|
+
// See: https://github.com/vitest-dev/eslint-plugin-vitest/issues/543
|
|
11
|
+
import pluginVitest from '@vitest/eslint-plugin';
|
|
12
|
+
import { nodeVersion } from 'aberlaas-versions';
|
|
13
|
+
|
|
14
|
+
export default [
|
|
15
|
+
{
|
|
16
|
+
name: 'aberlaas/base',
|
|
17
|
+
files: ['**/*.js'],
|
|
18
|
+
ignores: ['node_modules/*', '.yarn/*'],
|
|
19
|
+
languageOptions: {
|
|
20
|
+
ecmaVersion: 'latest',
|
|
21
|
+
sourceType: 'module',
|
|
22
|
+
globals: {
|
|
23
|
+
...globals.nodeBuiltin,
|
|
24
|
+
...globals.browser,
|
|
25
|
+
...pluginN.configs['flat/recommended'].languageOptions.globals,
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
linterOptions: {
|
|
29
|
+
reportUnusedDisableDirectives: 'warn',
|
|
30
|
+
},
|
|
31
|
+
plugins: {
|
|
32
|
+
import: pluginImport.flatConfigs.recommended.plugins.import,
|
|
33
|
+
jsdoc: pluginJsdoc.configs['flat/recommended'].plugins.jsdoc,
|
|
34
|
+
n: pluginN.configs['flat/recommended'].plugins.n,
|
|
35
|
+
prettier: pluginPrettierRecommended.plugins.prettier,
|
|
36
|
+
},
|
|
37
|
+
rules: {
|
|
38
|
+
...js.configs.recommended.rules,
|
|
39
|
+
...pluginImport.flatConfigs.recommended.rules,
|
|
40
|
+
...pluginJsdoc.configs['flat/recommended'].plugins.rules,
|
|
41
|
+
...pluginN.configs['flat/recommended'].plugins.rules,
|
|
42
|
+
'dot-notation': ['error'],
|
|
43
|
+
'max-len': [
|
|
44
|
+
'error',
|
|
45
|
+
{
|
|
46
|
+
code: 80,
|
|
47
|
+
ignoreComments: true,
|
|
48
|
+
ignoreRegExpLiterals: true,
|
|
49
|
+
ignoreStrings: true,
|
|
50
|
+
ignoreTemplateLiterals: true,
|
|
51
|
+
ignoreTrailingComments: true,
|
|
52
|
+
ignoreUrls: true,
|
|
53
|
+
// Ignore long lines in test headers, allowing us to write descriptive
|
|
54
|
+
// tests
|
|
55
|
+
ignorePattern: '^\\s*it\\(',
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
'no-console': ['off'],
|
|
59
|
+
'no-irregular-whitespace': ['error', { skipRegExps: true }],
|
|
60
|
+
'no-restricted-properties': [
|
|
61
|
+
'error',
|
|
62
|
+
{
|
|
63
|
+
object: 'module',
|
|
64
|
+
property: 'export',
|
|
65
|
+
message: 'Typo: Use module.exports instead',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
object: '_',
|
|
69
|
+
property: 'contains',
|
|
70
|
+
message: 'Typo: Use _.includes instead',
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
'no-unused-vars': [
|
|
74
|
+
'error',
|
|
75
|
+
{
|
|
76
|
+
argsIgnorePattern: '^_.',
|
|
77
|
+
varsIgnorePattern: '^_.',
|
|
78
|
+
caughtErrorsIgnorePattern: '^_.',
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
'no-shadow': ['error'],
|
|
82
|
+
'object-shorthand': ['error', 'always'],
|
|
83
|
+
'quote-props': ['error', 'consistent-as-needed'],
|
|
84
|
+
quotes: ['error', 'single', { avoidEscape: true }],
|
|
85
|
+
'sort-imports': ['error', { ignoreDeclarationSort: true }],
|
|
86
|
+
// Node
|
|
87
|
+
'n/no-unsupported-features/es-syntax': [
|
|
88
|
+
'error',
|
|
89
|
+
{ version: `>=${nodeVersion}` },
|
|
90
|
+
],
|
|
91
|
+
// Import
|
|
92
|
+
'import/first': ['error'],
|
|
93
|
+
'import/no-cycle': ['error', { ignoreExternal: true, disableScc: true }],
|
|
94
|
+
'import/order': ['error'],
|
|
95
|
+
'import/newline-after-import': ['error'],
|
|
96
|
+
// Ignoring this rule for lint-staged, as it seem to have a missing .main
|
|
97
|
+
// field in its package.json
|
|
98
|
+
// See: https://github.com/lint-staged/lint-staged/issues/1474
|
|
99
|
+
'import/no-unresolved': ['error', { ignore: ['lint-staged'] }],
|
|
100
|
+
// JSDoc
|
|
101
|
+
'jsdoc/check-param-names': ['warn'],
|
|
102
|
+
'jsdoc/check-types': ['warn'],
|
|
103
|
+
'jsdoc/no-undefined-types': ['warn'],
|
|
104
|
+
'jsdoc/check-alignment': ['warn'],
|
|
105
|
+
'jsdoc/check-examples': ['off'],
|
|
106
|
+
'jsdoc/check-syntax': ['warn'],
|
|
107
|
+
'jsdoc/check-tag-names': ['warn'],
|
|
108
|
+
'jsdoc/require-jsdoc': ['warn'],
|
|
109
|
+
'jsdoc/require-param': ['warn'],
|
|
110
|
+
'jsdoc/require-param-description': ['warn'],
|
|
111
|
+
'jsdoc/require-param-name': ['warn'],
|
|
112
|
+
'jsdoc/require-param-type': ['warn'],
|
|
113
|
+
'jsdoc/require-returns': ['warn'],
|
|
114
|
+
'jsdoc/require-returns-check': ['warn'],
|
|
115
|
+
'jsdoc/require-returns-description': ['warn'],
|
|
116
|
+
'jsdoc/require-returns-type': ['warn'],
|
|
117
|
+
'jsdoc/valid-types': ['warn'],
|
|
118
|
+
// Prettier
|
|
119
|
+
...pluginPrettierRecommended.rules,
|
|
120
|
+
},
|
|
121
|
+
settings: {
|
|
122
|
+
// eslint-plugin-import doesn't currently support the "exports" syntax in
|
|
123
|
+
// package.json. This is supposed to allow mapping between custom
|
|
124
|
+
// entrypoints and files on disk.
|
|
125
|
+
// For example, it doesn't understand "import * from 'vitest/config';" as
|
|
126
|
+
// "vitest/config/" isn't really an existing filepath, but a mapping defined
|
|
127
|
+
// in vitest package.json
|
|
128
|
+
//
|
|
129
|
+
// Until this is fixed (see
|
|
130
|
+
// https://github.com/import-js/eslint-plugin-import/issues/2430)
|
|
131
|
+
// we manually define the most common extensions
|
|
132
|
+
'import/resolver': {
|
|
133
|
+
node: { extensions: ['.js', '.cjs', '.mjs', '.d.ts'] },
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
name: 'aberlaas/vitest',
|
|
139
|
+
files: ['**/__tests__/**/*.js'],
|
|
140
|
+
languageOptions: {
|
|
141
|
+
globals: {
|
|
142
|
+
afterAll: true,
|
|
143
|
+
afterEach: true,
|
|
144
|
+
beforeAll: true,
|
|
145
|
+
beforeEach: true,
|
|
146
|
+
describe: true,
|
|
147
|
+
expect: true,
|
|
148
|
+
it: true,
|
|
149
|
+
test: true,
|
|
150
|
+
vitest: true,
|
|
151
|
+
vi: true,
|
|
152
|
+
captureOutput: false,
|
|
153
|
+
dedent: false,
|
|
154
|
+
fdescribe: false,
|
|
155
|
+
fit: false,
|
|
156
|
+
testName: false,
|
|
157
|
+
xdescribe: false,
|
|
158
|
+
xit: false,
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
plugins: {
|
|
162
|
+
vitest: pluginVitest,
|
|
163
|
+
},
|
|
164
|
+
rules: {
|
|
165
|
+
...pluginVitest.configs.recommended.rules,
|
|
166
|
+
'no-restricted-globals': [
|
|
167
|
+
'error',
|
|
168
|
+
{ name: 'fit', message: 'No focused test' },
|
|
169
|
+
{ name: 'fdescribe', message: 'No focused tests' },
|
|
170
|
+
{ name: 'xit', message: 'No skipped test' },
|
|
171
|
+
{ name: 'xdescribe', message: 'No skipped tests' },
|
|
172
|
+
],
|
|
173
|
+
// In tests, we like to have the variable 'current' hold the object
|
|
174
|
+
// under test. The import/no-named-as-default-member would have warned
|
|
175
|
+
// us about using current.foo rather than foo directly, so we disable
|
|
176
|
+
// it.
|
|
177
|
+
'import/no-named-as-default-member': ['off'],
|
|
178
|
+
'vitest/consistent-test-it': ['warn', { fn: 'it' }],
|
|
179
|
+
// Disabling vitest/no-identical-title
|
|
180
|
+
// It can make eslint crash when used with fit/xit/fdescribe/xdescribe
|
|
181
|
+
// See: https://github.com/veritem/eslint-plugin-vitest/issues/310
|
|
182
|
+
'vitest/no-identical-title': ['off'],
|
|
183
|
+
'vitest/prefer-to-contain': ['error'],
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
name: 'aberlaas/scripts',
|
|
188
|
+
files: ['**/scripts/**/*.js'],
|
|
189
|
+
rules: { 'no-process-exit': ['off'] },
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
ignores: ['**/docs/**/*.js'],
|
|
193
|
+
},
|
|
194
|
+
];
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Initially exported from
|
|
2
|
+
// https://github.com/stylelint/stylelint-config-recommended/blob/master/index.js
|
|
3
|
+
export default {
|
|
4
|
+
rules: {
|
|
5
|
+
'at-rule-no-unknown': [
|
|
6
|
+
true,
|
|
7
|
+
{
|
|
8
|
+
ignoreAtRules: ['screen', 'tailwind'],
|
|
9
|
+
},
|
|
10
|
+
],
|
|
11
|
+
'block-no-empty': true,
|
|
12
|
+
'color-no-invalid-hex': true,
|
|
13
|
+
'comment-no-empty': true,
|
|
14
|
+
'declaration-property-value-no-unknown': true,
|
|
15
|
+
'declaration-block-no-duplicate-properties': [
|
|
16
|
+
true,
|
|
17
|
+
{
|
|
18
|
+
ignore: ['consecutive-duplicates-with-different-values'],
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
'declaration-block-no-redundant-longhand-properties': true,
|
|
22
|
+
'declaration-block-no-shorthand-property-overrides': true,
|
|
23
|
+
'font-family-no-duplicate-names': true,
|
|
24
|
+
'function-calc-no-unspaced-operator': true,
|
|
25
|
+
'function-linear-gradient-no-nonstandard-direction': true,
|
|
26
|
+
'keyframe-declaration-no-important': true,
|
|
27
|
+
'media-feature-name-no-unknown': true,
|
|
28
|
+
'no-empty-source': true,
|
|
29
|
+
'no-invalid-double-slash-comments': true,
|
|
30
|
+
'property-no-unknown': true,
|
|
31
|
+
'selector-pseudo-class-no-unknown': true,
|
|
32
|
+
'selector-pseudo-element-no-unknown': true,
|
|
33
|
+
'selector-type-no-unknown': true,
|
|
34
|
+
'shorthand-property-no-redundant-values': true,
|
|
35
|
+
'string-no-newline': true,
|
|
36
|
+
'unit-no-unknown': true,
|
|
37
|
+
},
|
|
38
|
+
};
|
package/lib/circleci.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import ciInfo from 'ci-info';
|
|
2
|
+
import { exists, firostError, run, which } from 'firost';
|
|
3
|
+
import helper from 'aberlaas-helper';
|
|
4
|
+
import lintYml from './yml.js';
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
configPath: '.circleci/config.yml',
|
|
8
|
+
/**
|
|
9
|
+
* Find all relevant files
|
|
10
|
+
* @returns {Array} Array of files
|
|
11
|
+
*/
|
|
12
|
+
async getInputFiles() {
|
|
13
|
+
return await helper.findHostFiles([this.configPath]);
|
|
14
|
+
},
|
|
15
|
+
/**
|
|
16
|
+
* Check if the code is currently running on CircleCI
|
|
17
|
+
* @returns {boolean} True if running on CircleCI, false otherwise
|
|
18
|
+
*/
|
|
19
|
+
isRunningOnCircleCi() {
|
|
20
|
+
return ciInfo.CIRCLE;
|
|
21
|
+
},
|
|
22
|
+
/**
|
|
23
|
+
* Check if the circleci binary is available in the $PATH
|
|
24
|
+
* @returns {boolean} True if available, false otherwise
|
|
25
|
+
*/
|
|
26
|
+
async hasCircleCiBin() {
|
|
27
|
+
const binary = await which('circleci');
|
|
28
|
+
return !!binary;
|
|
29
|
+
},
|
|
30
|
+
/**
|
|
31
|
+
* Validate the CircleCI config file.
|
|
32
|
+
* @returns {boolean} True if valid, throws an error if not
|
|
33
|
+
*/
|
|
34
|
+
async validateConfig() {
|
|
35
|
+
await run('circleci config validate', { stdout: false });
|
|
36
|
+
},
|
|
37
|
+
/**
|
|
38
|
+
* Lint the file, both for yml issues and if possible circleci specifics
|
|
39
|
+
* @returns {boolean} True on success
|
|
40
|
+
*/
|
|
41
|
+
async run() {
|
|
42
|
+
const absoluteConfigPath = helper.hostPath(this.configPath);
|
|
43
|
+
const hasConfigFile = await exists(absoluteConfigPath);
|
|
44
|
+
const isRunningOnCircleCi = this.isRunningOnCircleCi();
|
|
45
|
+
|
|
46
|
+
// Stop early if no config file, or if running on CircleCI
|
|
47
|
+
if (!hasConfigFile || isRunningOnCircleCi) {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Lint as yml first
|
|
52
|
+
await lintYml.run([absoluteConfigPath]);
|
|
53
|
+
|
|
54
|
+
// Stop early if no circleci bin available
|
|
55
|
+
if (!(await this.hasCircleCiBin())) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Validate the config
|
|
60
|
+
try {
|
|
61
|
+
await this.validateConfig();
|
|
62
|
+
} catch (error) {
|
|
63
|
+
const errorMessage = `CircleCI config error on ${this.configPath}\n${error.message}`;
|
|
64
|
+
throw firostError('CircleCiLintError', errorMessage);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return true;
|
|
68
|
+
},
|
|
69
|
+
/**
|
|
70
|
+
* Autofix yml issues in file
|
|
71
|
+
* @returns {boolean} True on success
|
|
72
|
+
*/
|
|
73
|
+
async fix() {
|
|
74
|
+
const absoluteConfigPath = helper.hostPath(this.configPath);
|
|
75
|
+
// Fix yml issues
|
|
76
|
+
await lintYml.fix([absoluteConfigPath]);
|
|
77
|
+
|
|
78
|
+
// Check for file errors so it still fails if file is invalid
|
|
79
|
+
await this.run();
|
|
80
|
+
},
|
|
81
|
+
};
|
package/lib/css.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import stylelint from 'stylelint';
|
|
2
|
+
import { _ } from 'golgoth';
|
|
3
|
+
import { firostError } from 'firost';
|
|
4
|
+
import helper from 'aberlaas-helper';
|
|
5
|
+
import stylelintConfig from '../configs/stylelint.js';
|
|
6
|
+
import { fix as prettierFix } from './helpers/prettier.js';
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
/**
|
|
10
|
+
* Find all relevant files
|
|
11
|
+
* @param {Array} userPatterns Patterns to narrow the search down
|
|
12
|
+
* @returns {Array} Array of files
|
|
13
|
+
*/
|
|
14
|
+
async getInputFiles(userPatterns) {
|
|
15
|
+
const filePatterns = _.isEmpty(userPatterns)
|
|
16
|
+
? ['./**/*.css']
|
|
17
|
+
: userPatterns;
|
|
18
|
+
return await helper.findHostFiles(filePatterns, ['.css']);
|
|
19
|
+
},
|
|
20
|
+
/**
|
|
21
|
+
* Lint all files and display results.
|
|
22
|
+
* @param {Array} userPatterns Patterns to narrow the search down
|
|
23
|
+
* @param {string} userConfigFile Custom config file to use
|
|
24
|
+
* @param {object} userOptions Options to pass to ESLint, including fix
|
|
25
|
+
* @returns {boolean} True on success
|
|
26
|
+
*/
|
|
27
|
+
async run(userPatterns, userConfigFile, userOptions = {}) {
|
|
28
|
+
// Options
|
|
29
|
+
const options = { fix: false, ...userOptions };
|
|
30
|
+
|
|
31
|
+
// Files
|
|
32
|
+
const files = await this.getInputFiles(userPatterns);
|
|
33
|
+
if (_.isEmpty(files)) {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Config
|
|
38
|
+
const config = await helper.getConfig(
|
|
39
|
+
userConfigFile,
|
|
40
|
+
'stylelint.config.js',
|
|
41
|
+
stylelintConfig,
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const result = await stylelint.lint({
|
|
45
|
+
config,
|
|
46
|
+
files,
|
|
47
|
+
formatter: 'string',
|
|
48
|
+
...options,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
if (result.errored) {
|
|
52
|
+
throw firostError('ERROR_CSS_LINT', result.report);
|
|
53
|
+
}
|
|
54
|
+
return true;
|
|
55
|
+
},
|
|
56
|
+
/**
|
|
57
|
+
* Autofix files in place
|
|
58
|
+
* @param {Array} userPatterns Patterns to narrow the search down
|
|
59
|
+
* @param {string} userConfigFile Custom config file to use
|
|
60
|
+
* @returns {boolean} True on success
|
|
61
|
+
*/
|
|
62
|
+
async fix(userPatterns, userConfigFile) {
|
|
63
|
+
const files = await this.getInputFiles(userPatterns);
|
|
64
|
+
if (_.isEmpty(files)) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
// Try to pretiffy as much as we can
|
|
68
|
+
await prettierFix(files);
|
|
69
|
+
// Still run a lint on it so it can fail if not everything is fixed
|
|
70
|
+
await this.run(userPatterns, userConfigFile, { fix: true });
|
|
71
|
+
return true;
|
|
72
|
+
},
|
|
73
|
+
};
|
package/lib/js.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { _ } from 'golgoth';
|
|
2
|
+
import { firostError } from 'firost';
|
|
3
|
+
import { ESLint } from 'eslint';
|
|
4
|
+
import helper from 'aberlaas-helper';
|
|
5
|
+
import eslintConfig from '../configs/eslint.js';
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
/**
|
|
9
|
+
* Find all relevant files
|
|
10
|
+
* @param {Array} userPatterns Patterns to narrow the search down
|
|
11
|
+
* @returns {Array} Array of files
|
|
12
|
+
*/
|
|
13
|
+
async getInputFiles(userPatterns) {
|
|
14
|
+
const filePatterns = _.isEmpty(userPatterns) ? ['./**/*.js'] : userPatterns;
|
|
15
|
+
|
|
16
|
+
return await helper.findHostFiles(filePatterns, ['.js']);
|
|
17
|
+
},
|
|
18
|
+
/**
|
|
19
|
+
* Lint all files and display results.
|
|
20
|
+
* @param {Array} userPatterns Patterns to narrow the search down
|
|
21
|
+
* @param {string} userConfigFile Custom config file to use
|
|
22
|
+
* @param {object} userOptions Options to pass to ESLint, including fix
|
|
23
|
+
* @returns {boolean} True on success
|
|
24
|
+
*/
|
|
25
|
+
async run(userPatterns, userConfigFile, userOptions = {}) {
|
|
26
|
+
// Options
|
|
27
|
+
const options = { fix: false, ...userOptions };
|
|
28
|
+
|
|
29
|
+
// Files to lint
|
|
30
|
+
const files = await this.getInputFiles(userPatterns);
|
|
31
|
+
if (_.isEmpty(files)) {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Config file
|
|
36
|
+
const config = await helper.getConfig(
|
|
37
|
+
userConfigFile,
|
|
38
|
+
'eslint.config.js',
|
|
39
|
+
eslintConfig,
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
// Run the actual lint
|
|
43
|
+
const eslint = new ESLint({
|
|
44
|
+
...options,
|
|
45
|
+
overrideConfigFile: true,
|
|
46
|
+
overrideConfig: config,
|
|
47
|
+
});
|
|
48
|
+
const results = await eslint.lintFiles(files);
|
|
49
|
+
|
|
50
|
+
// Fix
|
|
51
|
+
if (options.fix) {
|
|
52
|
+
await ESLint.outputFixes(results);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// All good, we can stop
|
|
56
|
+
const errorCount = _.chain(results).map('errorCount').sum().value();
|
|
57
|
+
if (errorCount == 0) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Format errors
|
|
62
|
+
const formatter = await eslint.loadFormatter('stylish');
|
|
63
|
+
const errorText = formatter.format(results);
|
|
64
|
+
throw firostError('JavaScriptLintError', errorText);
|
|
65
|
+
},
|
|
66
|
+
/**
|
|
67
|
+
* Autofix files in place
|
|
68
|
+
* @param {Array} userPatterns Patterns to narrow the search down
|
|
69
|
+
* @param {string} userConfigFile Custom config file to use
|
|
70
|
+
* @returns {boolean} True on success
|
|
71
|
+
*/
|
|
72
|
+
async fix(userPatterns, userConfigFile) {
|
|
73
|
+
return await this.run(userPatterns, userConfigFile, { fix: true });
|
|
74
|
+
},
|
|
75
|
+
};
|
package/lib/json.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { _, pMap } from 'golgoth';
|
|
3
|
+
import { firostError, read } from 'firost';
|
|
4
|
+
import helper from 'aberlaas-helper';
|
|
5
|
+
import { fix as prettierFix } from './helpers/prettier.js';
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
/**
|
|
9
|
+
* Find all relevant files
|
|
10
|
+
* @param {Array} userPatterns Patterns to narrow the search down
|
|
11
|
+
* @returns {Array} Array of files
|
|
12
|
+
*/
|
|
13
|
+
async getInputFiles(userPatterns) {
|
|
14
|
+
const filePatterns = _.isEmpty(userPatterns)
|
|
15
|
+
? ['./**/*.json']
|
|
16
|
+
: userPatterns;
|
|
17
|
+
return await helper.findHostFiles(filePatterns, ['.json']);
|
|
18
|
+
},
|
|
19
|
+
/**
|
|
20
|
+
* Lint all files and display results.
|
|
21
|
+
* @param {Array} userPatterns Patterns to narrow the search down
|
|
22
|
+
* @returns {boolean} True on success
|
|
23
|
+
*/
|
|
24
|
+
async run(userPatterns) {
|
|
25
|
+
const files = await this.getInputFiles(userPatterns);
|
|
26
|
+
if (_.isEmpty(files)) {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let hasErrors = false;
|
|
31
|
+
const errorMessages = [];
|
|
32
|
+
await pMap(files, async (filepath) => {
|
|
33
|
+
try {
|
|
34
|
+
JSON.parse(await read(filepath));
|
|
35
|
+
} catch (error) {
|
|
36
|
+
hasErrors = true;
|
|
37
|
+
const relativePath = path.relative(helper.hostRoot(), filepath);
|
|
38
|
+
errorMessages.push(`Invalid JSON: ${relativePath}`);
|
|
39
|
+
errorMessages.push(error.message);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
if (hasErrors) {
|
|
44
|
+
throw firostError('JsonLintError', errorMessages.join('\n'));
|
|
45
|
+
}
|
|
46
|
+
return true;
|
|
47
|
+
},
|
|
48
|
+
/**
|
|
49
|
+
* Autofix files in place
|
|
50
|
+
* @param {Array} userPatterns Patterns to narrow the search down
|
|
51
|
+
* @returns {boolean} True on success
|
|
52
|
+
*/
|
|
53
|
+
async fix(userPatterns) {
|
|
54
|
+
const files = await this.getInputFiles(userPatterns);
|
|
55
|
+
if (_.isEmpty(files)) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
await prettierFix(files);
|
|
59
|
+
},
|
|
60
|
+
};
|
package/lib/main.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { _, pMap } from 'golgoth';
|
|
2
|
+
import { consoleError, firostError, firostImport } from 'firost';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
/**
|
|
6
|
+
* List of all available linters, along with the --flag name
|
|
7
|
+
**/
|
|
8
|
+
linters: {
|
|
9
|
+
circleci: './circleci.js',
|
|
10
|
+
css: './css.js',
|
|
11
|
+
json: './json.js',
|
|
12
|
+
js: './js.js',
|
|
13
|
+
yml: './yml.js',
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Returns a linter, based on its name
|
|
18
|
+
* @param {string} linterType Name of the linter
|
|
19
|
+
* @returns {object} Linter
|
|
20
|
+
**/
|
|
21
|
+
async getLinter(linterType) {
|
|
22
|
+
const linterPath = this.linters[linterType];
|
|
23
|
+
if (!linterPath) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return await firostImport(linterPath);
|
|
28
|
+
},
|
|
29
|
+
/**
|
|
30
|
+
* Wrapper to lint all supported formats
|
|
31
|
+
* @param {object} cliArgs CLI Argument object, as created by minimist
|
|
32
|
+
* @returns {boolean} True on success
|
|
33
|
+
*/
|
|
34
|
+
async run(cliArgs = {}) {
|
|
35
|
+
const allTypesKeys = _.keys(this.linters);
|
|
36
|
+
const userTypes = _.intersection(_.keys(cliArgs), allTypesKeys);
|
|
37
|
+
const typesToLint = _.isEmpty(userTypes) ? allTypesKeys : userTypes;
|
|
38
|
+
|
|
39
|
+
let hasErrors = false;
|
|
40
|
+
await pMap(typesToLint, async (type) => {
|
|
41
|
+
const methodName = cliArgs.fix ? 'fix' : 'run';
|
|
42
|
+
try {
|
|
43
|
+
const linter = await this.getLinter(type);
|
|
44
|
+
|
|
45
|
+
const configFile = _.get(cliArgs, `config.${type}`);
|
|
46
|
+
const userPatterns = _.get(cliArgs, '_');
|
|
47
|
+
|
|
48
|
+
await linter[methodName](userPatterns, configFile);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
this.__consoleError(error.message);
|
|
51
|
+
hasErrors = true;
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
if (hasErrors) {
|
|
56
|
+
throw firostError('ERROR_LINT', 'Error while linting files');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return true;
|
|
60
|
+
},
|
|
61
|
+
__consoleError: consoleError,
|
|
62
|
+
};
|
package/lib/yml.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { firostError, read } from 'firost';
|
|
3
|
+
import { _, pMap } from 'golgoth';
|
|
4
|
+
import yamlLint from 'yaml-lint';
|
|
5
|
+
import helper from 'aberlaas-helper';
|
|
6
|
+
import { fix as prettierFix } from './helpers/prettier.js';
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
/**
|
|
10
|
+
* Find all relevant files
|
|
11
|
+
* @param {Array} userPatterns Patterns to narrow the search down
|
|
12
|
+
* @returns {Array} Array of files
|
|
13
|
+
*/
|
|
14
|
+
async getInputFiles(userPatterns) {
|
|
15
|
+
const filePatterns = _.isEmpty(userPatterns)
|
|
16
|
+
? ['./**/*.yml', './**/*.yaml']
|
|
17
|
+
: userPatterns;
|
|
18
|
+
return await helper.findHostFiles(filePatterns, ['.yml', '.yaml']);
|
|
19
|
+
},
|
|
20
|
+
/**
|
|
21
|
+
* Lint all files and display results.
|
|
22
|
+
* @param {Array} userPatterns Patterns to narrow the search down
|
|
23
|
+
* @returns {boolean} True on success
|
|
24
|
+
*/
|
|
25
|
+
async run(userPatterns) {
|
|
26
|
+
const files = await this.getInputFiles(userPatterns);
|
|
27
|
+
if (_.isEmpty(files)) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let hasErrors = false;
|
|
32
|
+
const errorMessages = [];
|
|
33
|
+
await pMap(files, async (filepath) => {
|
|
34
|
+
const input = await read(filepath);
|
|
35
|
+
try {
|
|
36
|
+
await yamlLint.lint(input);
|
|
37
|
+
} catch (error) {
|
|
38
|
+
hasErrors = true;
|
|
39
|
+
const relativePath = path.relative(helper.hostRoot(), filepath);
|
|
40
|
+
errorMessages.push(`Invalid YAML: ${relativePath}`);
|
|
41
|
+
errorMessages.push(error.message);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
if (hasErrors) {
|
|
46
|
+
throw firostError('YamlLintError', errorMessages.join('\n'));
|
|
47
|
+
}
|
|
48
|
+
return true;
|
|
49
|
+
},
|
|
50
|
+
/**
|
|
51
|
+
* Autofix files in place
|
|
52
|
+
* @param {Array} userPatterns Patterns to narrow the search down
|
|
53
|
+
* @returns {boolean} True on success
|
|
54
|
+
*/
|
|
55
|
+
async fix(userPatterns) {
|
|
56
|
+
const files = await this.getInputFiles(userPatterns);
|
|
57
|
+
if (_.isEmpty(files)) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
await prettierFix(files);
|
|
61
|
+
},
|
|
62
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "aberlaas-lint",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"description": "aberlaas lint command: Lint files",
|
|
5
|
+
"version": "2.10.0",
|
|
6
|
+
"repository": "pixelastic/aberlaas",
|
|
7
|
+
"homepage": "https://projects.pixelastic.com/aberlaas/",
|
|
8
|
+
"author": "Tim Carry (@pixelastic)",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"files": [
|
|
11
|
+
"lib/*.js",
|
|
12
|
+
"configs/*.js"
|
|
13
|
+
],
|
|
14
|
+
"exports": {
|
|
15
|
+
".": "./lib/main.js",
|
|
16
|
+
"./configs/eslint": "./configs/eslint.js",
|
|
17
|
+
"./configs/prettier": "./configs/prettier.js",
|
|
18
|
+
"./configs/stylelint": "./configs/stylelint.js"
|
|
19
|
+
},
|
|
20
|
+
"main": "./lib/main.js",
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=18.18.0"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "../../scripts/local/build",
|
|
26
|
+
"build:prod": "../../scripts/local/build-prod",
|
|
27
|
+
"cms": "../../scripts/local/cms",
|
|
28
|
+
"serve": "../../scripts/local/serve",
|
|
29
|
+
"ci": "../../scripts/local/ci",
|
|
30
|
+
"release": "../../scripts/local/release",
|
|
31
|
+
"update": "node ../../scripts/meta/update.js",
|
|
32
|
+
"test:meta": "../../scripts/local/test-meta",
|
|
33
|
+
"test": "../../scripts/local/test",
|
|
34
|
+
"test:watch": "../../scripts/local/test-watch",
|
|
35
|
+
"compress": "../../scripts/local/compress",
|
|
36
|
+
"lint": "../../scripts/local/lint",
|
|
37
|
+
"lint:fix": "../../scripts/local/lint-fix"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@eslint/js": "9.12.0",
|
|
41
|
+
"@typescript-eslint/utils": "8.8.1",
|
|
42
|
+
"@vitest/eslint-plugin": "1.1.7",
|
|
43
|
+
"aberlaas-helper": "^2.10.0",
|
|
44
|
+
"aberlaas-versions": "^2.10.0",
|
|
45
|
+
"ci-info": "4.0.0",
|
|
46
|
+
"eslint": "9.12.0",
|
|
47
|
+
"eslint-config-prettier": "9.1.0",
|
|
48
|
+
"eslint-plugin-import": "2.31.0",
|
|
49
|
+
"eslint-plugin-jsdoc": "50.3.1",
|
|
50
|
+
"eslint-plugin-n": "17.11.1",
|
|
51
|
+
"eslint-plugin-prettier": "5.2.1",
|
|
52
|
+
"firost": "4.3.0",
|
|
53
|
+
"golgoth": "2.4.0",
|
|
54
|
+
"prettier": "3.3.3",
|
|
55
|
+
"stylelint": "16.9.0",
|
|
56
|
+
"typescript": "5.6.3",
|
|
57
|
+
"yaml-lint": "1.7.0"
|
|
58
|
+
},
|
|
59
|
+
"gitHead": "bcdaf87c198a588e02b5539c222f611e356d3079"
|
|
60
|
+
}
|