- Introduce `fresh-npm-install.sh` to automate clean npm environment
setup.
- Revert workaround 924b326244, resolved
by updating Font Awesome.
- Remove `vue-template-compiler` and `@vue/test-utils` from
dependencies, they're obsolete in 2.7.
- Update anchor references to start with lower case in line with
MD051/link-fragments, introduced by updated `markdownlint`.
- Upgrade cypress to > 10, which includes:
- Change spec extensions from `*.spec.js` to `*.cy.js`.
- Change configuration file from `cypress.json` to
`cypress.config.ts`.
- Remove most configurations from `cypress/plugins/index.js`. These
configurations were initially generated by Vue CLI but obsoleted in
newer cypress versions.
- Lock Typescript version to 4.6.x due to lack of support in
unmaintained Vue CLI TypeScript plugin (see vuejs/vue-cli#7401).
- Use `setWindowOpenHandler` on Electron, replacing deprecated
`new-event` event.
- Document inability to upgrade `typescript-eslint` dependencies because
`@vue/eslint-config-typescript` does not support them. See
vuejs/eslint-config-typescript#60, vuejs/eslint-config-typescript#59,
vuejs/eslint-config-typescript#57.
- Fix `typescript` version to 4.6.X and `tslib` version to 2.4.x,
unit tests exit with a maximum call stack size exceeded error:
```
...
MOCHA Testing...
RUNTIME EXCEPTION Exception occurred while loading your tests
[=========================] 100% (completed)
RangeError: Maximum call stack size exceeded
at RegExp.exec (<anonymous>)
at retrieveSourceMapURL (/project/node_modules/source-map-support/source-map-support.js:174:21)
at Array.<anonymous> (/project/node_modules/source-map-support/source-map-support.js:186:26)
at /project/node_modules/source-map-support/source-map-support.js:85:24
at mapSourcePosition (/project/node_modules/source-map-support/source-map-support.js:216:21)
...
```
Issue has been reported but not fixed, suggested solutions did not
work, see evanw/node-source-map-support#252.
- Update `vue-cli-plugin-electron-builder` to latest alpha version. This
allows upgrading `ts-loader` to latest and using latest
`electron-builder`. Change `main` property value in `package.json` to
`index.js` for successful electron builds (see
nklayman/vue-cli-plugin-electron-builder#188).
299 lines
10 KiB
JavaScript
299 lines
10 KiB
JavaScript
const { rules: baseBestPracticesRules } = require('eslint-config-airbnb-base/rules/best-practices');
|
|
const { rules: baseErrorsRules } = require('eslint-config-airbnb-base/rules/errors');
|
|
const { rules: baseES6Rules } = require('eslint-config-airbnb-base/rules/es6');
|
|
const { rules: baseImportsRules } = require('eslint-config-airbnb-base/rules/imports');
|
|
const { rules: baseStyleRules } = require('eslint-config-airbnb-base/rules/style');
|
|
const { rules: baseVariablesRules } = require('eslint-config-airbnb-base/rules/variables');
|
|
const tsconfigJson = require('./tsconfig.json');
|
|
|
|
module.exports = {
|
|
root: true,
|
|
env: {
|
|
node: true,
|
|
},
|
|
extends: [
|
|
// Vue specific rules, eslint-plugin-vue
|
|
// Added by Vue CLI
|
|
'plugin:vue/essential',
|
|
|
|
// Extends eslint-config-airbnb
|
|
// Added by Vue CLI
|
|
// Here until https://github.com/vuejs/eslint-config-airbnb/issues/23 is done
|
|
'@vue/airbnb',
|
|
|
|
// Extends @typescript-eslint/recommended
|
|
// Uses the recommended rules from the @typescript-eslint/eslint-plugin
|
|
// Added by Vue CLI
|
|
'@vue/typescript/recommended',
|
|
],
|
|
parserOptions: {
|
|
ecmaVersion: 12, // ECMA 2021
|
|
/*
|
|
Having 'latest' leads to:
|
|
```
|
|
Parsing error: ecmaVersion must be a number. Received value of type string instead
|
|
```
|
|
For .js files in the project
|
|
*/
|
|
},
|
|
rules: {
|
|
...getOwnRules(),
|
|
...getTurnedOffBrokenRules(),
|
|
...getOpinionatedRuleOverrides(),
|
|
...getTodoRules(),
|
|
},
|
|
overrides: [
|
|
{
|
|
files: [
|
|
'**/__tests__/*.{j,t}s?(x)',
|
|
'**/tests/unit/**/*.spec.{j,t}s?(x)',
|
|
],
|
|
env: {
|
|
mocha: true,
|
|
},
|
|
},
|
|
{
|
|
files: ['**/*.ts?(x)', '**/*.d.ts'],
|
|
parserOptions: {
|
|
// Setting project is required for some rules such as @typescript-eslint/dot-notation,
|
|
// @typescript-eslint/return-await and @typescript-eslint/no-throw-literal.
|
|
// If this property is missing they fail due to missing parser.
|
|
project: ['./tsconfig.json'],
|
|
},
|
|
rules: {
|
|
...getTypeScriptOverrides(),
|
|
},
|
|
},
|
|
{
|
|
files: ['**/tests/**/*.{j,t}s?(x)'],
|
|
rules: {
|
|
'no-console': 'off',
|
|
},
|
|
},
|
|
],
|
|
};
|
|
|
|
function getOwnRules() {
|
|
return {
|
|
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
|
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
|
'linebreak-style': ['error', 'unix'], // This is also enforced in .editorconfig and .gitattributes files
|
|
'import/order': [ // Enforce strict import order taking account into aliases
|
|
'error',
|
|
{
|
|
groups: [ // Enforce more strict order than AirBnb
|
|
'builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'],
|
|
pathGroups: [ // Fix manually configured paths being incorrectly grouped as "external"
|
|
...getAliasesFromTsConfig(),
|
|
'js-yaml-loader!@/**',
|
|
].map((pattern) => ({ pattern, group: 'internal' })),
|
|
},
|
|
],
|
|
};
|
|
}
|
|
|
|
function getTodoRules() { // Should be worked on separate future commits
|
|
return {
|
|
'import/no-extraneous-dependencies': 'off',
|
|
// Accessibility improvements:
|
|
'vuejs-accessibility/form-control-has-label': 'off',
|
|
'vuejs-accessibility/click-events-have-key-events': 'off',
|
|
'vuejs-accessibility/anchor-has-content': 'off',
|
|
'vuejs-accessibility/accessible-emoji': 'off',
|
|
};
|
|
}
|
|
|
|
function getTurnedOffBrokenRules() {
|
|
return {
|
|
// Broken in TypeScript
|
|
'no-useless-constructor': 'off', // Cannot interpret TypeScript constructors
|
|
'no-shadow': 'off', // Fails with TypeScript enums
|
|
};
|
|
}
|
|
|
|
function getOpinionatedRuleOverrides() {
|
|
return {
|
|
// https://erkinekici.com/articles/linting-trap#no-use-before-define
|
|
'no-use-before-define': 'off',
|
|
// https://erkinekici.com/articles/linting-trap#arrow-body-style
|
|
'arrow-body-style': 'off',
|
|
// https://erkinekici.com/articles/linting-trap#no-plusplus
|
|
'no-plusplus': 'off',
|
|
// https://erkinekici.com/articles/linting-trap#no-param-reassign
|
|
'no-param-reassign': 'off',
|
|
// https://erkinekici.com/articles/linting-trap#class-methods-use-this
|
|
'class-methods-use-this': 'off',
|
|
// https://erkinekici.com/articles/linting-trap#importprefer-default-export
|
|
'import/prefer-default-export': 'off',
|
|
// https://erkinekici.com/articles/linting-trap#disallowing-for-of
|
|
// Original: https://github.com/airbnb/javascript/blob/d8cb404da74c302506f91e5928f30cc75109e74d/packages/eslint-config-airbnb-base/rules/style.js#L333-L351
|
|
'no-restricted-syntax': [
|
|
baseStyleRules['no-restricted-syntax'][0],
|
|
...baseStyleRules['no-restricted-syntax'].slice(1).filter((rule) => rule.selector !== 'ForOfStatement'),
|
|
],
|
|
};
|
|
}
|
|
|
|
function getTypeScriptOverrides() {
|
|
/*
|
|
Here until Vue supports AirBnb Typescript overrides (vuejs/eslint-config-airbnb#23).
|
|
Based on `eslint-config-airbnb-typescript`.
|
|
Source: https://github.com/iamturns/eslint-config-airbnb-typescript/blob/v16.1.0/lib/shared.js
|
|
It cannot be used directly due to compilation errors.
|
|
*/
|
|
return {
|
|
'brace-style': 'off',
|
|
'@typescript-eslint/brace-style': baseStyleRules['brace-style'],
|
|
|
|
camelcase: 'off',
|
|
'@typescript-eslint/naming-convention': [
|
|
'error',
|
|
{ selector: 'variable', format: ['camelCase', 'PascalCase', 'UPPER_CASE'] },
|
|
{ selector: 'function', format: ['camelCase', 'PascalCase'] },
|
|
{ selector: 'typeLike', format: ['PascalCase'] },
|
|
],
|
|
|
|
'comma-dangle': 'off',
|
|
'@typescript-eslint/comma-dangle': [
|
|
baseStyleRules['comma-dangle'][0],
|
|
{
|
|
...baseStyleRules['comma-dangle'][1],
|
|
enums: baseStyleRules['comma-dangle'][1].arrays,
|
|
generics: baseStyleRules['comma-dangle'][1].arrays,
|
|
tuples: baseStyleRules['comma-dangle'][1].arrays,
|
|
},
|
|
],
|
|
|
|
'comma-spacing': 'off',
|
|
'@typescript-eslint/comma-spacing': baseStyleRules['comma-spacing'],
|
|
|
|
'default-param-last': 'off',
|
|
'@typescript-eslint/default-param-last': baseBestPracticesRules['default-param-last'],
|
|
|
|
'dot-notation': 'off',
|
|
'@typescript-eslint/dot-notation': baseBestPracticesRules['dot-notation'],
|
|
|
|
'func-call-spacing': 'off',
|
|
'@typescript-eslint/func-call-spacing': baseStyleRules['func-call-spacing'],
|
|
|
|
// ❌ Broken for some cases, but still useful.
|
|
// Here until Prettifier is used.
|
|
indent: 'off',
|
|
'@typescript-eslint/indent': baseStyleRules.indent,
|
|
|
|
'keyword-spacing': 'off',
|
|
'@typescript-eslint/keyword-spacing': baseStyleRules['keyword-spacing'],
|
|
|
|
'lines-between-class-members': 'off',
|
|
'@typescript-eslint/lines-between-class-members': baseStyleRules['lines-between-class-members'],
|
|
|
|
'no-array-constructor': 'off',
|
|
'@typescript-eslint/no-array-constructor': baseStyleRules['no-array-constructor'],
|
|
|
|
'no-dupe-class-members': 'off',
|
|
'@typescript-eslint/no-dupe-class-members': baseES6Rules['no-dupe-class-members'],
|
|
|
|
'no-empty-function': 'off',
|
|
'@typescript-eslint/no-empty-function': baseBestPracticesRules['no-empty-function'],
|
|
|
|
'no-extra-parens': 'off',
|
|
'@typescript-eslint/no-extra-parens': baseErrorsRules['no-extra-parens'],
|
|
|
|
'no-extra-semi': 'off',
|
|
'@typescript-eslint/no-extra-semi': baseErrorsRules['no-extra-semi'],
|
|
|
|
// ❌ Fails due to missing parser
|
|
// 'no-implied-eval': 'off',
|
|
// 'no-new-func': 'off',
|
|
// '@typescript-eslint/no-implied-eval': baseBestPracticesRules['no-implied-eval'],
|
|
|
|
'no-loss-of-precision': 'off',
|
|
'@typescript-eslint/no-loss-of-precision': baseErrorsRules['no-loss-of-precision'],
|
|
|
|
'no-loop-func': 'off',
|
|
'@typescript-eslint/no-loop-func': baseBestPracticesRules['no-loop-func'],
|
|
|
|
'no-magic-numbers': 'off',
|
|
'@typescript-eslint/no-magic-numbers': baseBestPracticesRules['no-magic-numbers'],
|
|
|
|
'no-redeclare': 'off',
|
|
'@typescript-eslint/no-redeclare': baseBestPracticesRules['no-redeclare'],
|
|
|
|
// ESLint variant does not work with TypeScript enums.
|
|
'no-shadow': 'off',
|
|
'@typescript-eslint/no-shadow': baseVariablesRules['no-shadow'],
|
|
|
|
'no-throw-literal': 'off',
|
|
'@typescript-eslint/no-throw-literal': baseBestPracticesRules['no-throw-literal'],
|
|
|
|
'no-unused-expressions': 'off',
|
|
'@typescript-eslint/no-unused-expressions': baseBestPracticesRules['no-unused-expressions'],
|
|
|
|
'no-unused-vars': 'off',
|
|
'@typescript-eslint/no-unused-vars': baseVariablesRules['no-unused-vars'],
|
|
|
|
// https://erkinekici.com/articles/linting-trap#no-use-before-define
|
|
// 'no-use-before-define': 'off',
|
|
// '@typescript-eslint/no-use-before-define': baseVariablesRules['no-use-before-define'],
|
|
|
|
// ESLint variant does not understand TypeScript constructors.
|
|
// eslint/eslint/#14118, typescript-eslint/typescript-eslint#873
|
|
'no-useless-constructor': 'off',
|
|
'@typescript-eslint/no-useless-constructor': baseES6Rules['no-useless-constructor'],
|
|
|
|
quotes: 'off',
|
|
'@typescript-eslint/quotes': baseStyleRules.quotes,
|
|
|
|
semi: 'off',
|
|
'@typescript-eslint/semi': baseStyleRules.semi,
|
|
|
|
'space-before-function-paren': 'off',
|
|
'@typescript-eslint/space-before-function-paren': baseStyleRules['space-before-function-paren'],
|
|
|
|
'require-await': 'off',
|
|
'@typescript-eslint/require-await': baseBestPracticesRules['require-await'],
|
|
|
|
'no-return-await': 'off',
|
|
'@typescript-eslint/return-await': baseBestPracticesRules['no-return-await'],
|
|
|
|
'space-infix-ops': 'off',
|
|
'@typescript-eslint/space-infix-ops': baseStyleRules['space-infix-ops'],
|
|
|
|
'object-curly-spacing': 'off',
|
|
'@typescript-eslint/object-curly-spacing': baseStyleRules['object-curly-spacing'],
|
|
|
|
'import/extensions': [
|
|
baseImportsRules['import/extensions'][0],
|
|
baseImportsRules['import/extensions'][1],
|
|
{
|
|
...baseImportsRules['import/extensions'][2],
|
|
ts: 'never',
|
|
tsx: 'never',
|
|
},
|
|
],
|
|
|
|
// Changes required is not yet implemented:
|
|
// 'import/no-extraneous-dependencies': [
|
|
// baseImportsRules['import/no-extraneous-dependencies'][0],
|
|
// {
|
|
// ...baseImportsRules['import/no-extraneous-dependencies'][1],
|
|
// devDependencies: baseImportsRules[
|
|
// 'import/no-extraneous-dependencies'
|
|
// ][1].devDependencies.reduce((result, devDep) => {
|
|
// const toAppend = [devDep];
|
|
// const devDepWithTs = devDep.replace(/\bjs(x?)\b/g, 'ts$1');
|
|
// if (devDepWithTs !== devDep) {
|
|
// toAppend.push(devDepWithTs);
|
|
// }
|
|
// return [...result, ...toAppend];
|
|
// }, []),
|
|
// },
|
|
// ],
|
|
};
|
|
}
|
|
|
|
function getAliasesFromTsConfig() {
|
|
return Object.keys(tsconfigJson.compilerOptions.paths)
|
|
.map((path) => `${path}*`);
|
|
}
|