@planfredapp/eslint-config 1.0.9

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/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # planfred-eslint-config
2
+
3
+ Shared ESLint configurations for the Planfred monorepo.
4
+
5
+ ## Available Configurations
6
+
7
+ ### Base Configuration
8
+
9
+ The base configuration includes common rules and plugins used across all projects:
10
+
11
+ - Standard JavaScript rules
12
+ - Import/export rules
13
+ - Node.js specific rules
14
+ - Promise handling rules
15
+ - Stylistic rules
16
+
17
+ ### Vue Configuration
18
+
19
+ Extends the base configuration with Vue.js specific rules:
20
+
21
+ - Vue component rules
22
+ - Template-specific styling rules
23
+ - Component naming conventions
24
+ - Vue-specific import path rules
25
+
26
+ ### Cypress Configuration
27
+
28
+ Extends the base configuration with Cypress testing rules:
29
+
30
+ - TypeScript support
31
+ - Cypress-specific globals and rules
32
+ - Test-specific linting rules
33
+
34
+ ### Test Configuration
35
+
36
+ Extends the base configuration with testing framework rules:
37
+
38
+ - Vitest support
39
+ - Test-specific globals
40
+ - Testing best practices
41
+
42
+ ## Usage
43
+
44
+ ### In ESLint Config Files
45
+
46
+ ```javascript
47
+ // For base configuration
48
+ import baseConfig from '@planfred/eslint-config/base'
49
+
50
+ export default [
51
+ ...baseConfig,
52
+ // your specific overrides
53
+ ]
54
+
55
+ // For Vue projects
56
+ import vueConfig from '@planfred/eslint-config/vue'
57
+
58
+ export default [
59
+ ...vueConfig,
60
+ // your specific overrides
61
+ ]
62
+
63
+ // For Cypress tests
64
+ import cypressConfig from '@planfred/eslint-config/cypress'
65
+
66
+ export default [
67
+ ...cypressConfig,
68
+ // your specific overrides
69
+ ]
70
+
71
+ // For test files
72
+ import testConfig from '@planfred/eslint-config/test'
73
+
74
+ export default [
75
+ ...testConfig,
76
+ // your specific overrides
77
+ ]
78
+ ```
79
+
80
+ ### Package.json Dependencies
81
+
82
+ Add the shared config as a dependency in your package.json using the GitHub repository URL:
83
+
84
+ ```json
85
+ {
86
+ "dependencies": {
87
+ "@planfred/eslint-config": "git+https://github.com/planfred/eslint-config.git"
88
+ }
89
+ }
90
+ ```
91
+
92
+ Alternatively, you can use a specific version or branch:
93
+
94
+ ```json
95
+ {
96
+ "dependencies": {
97
+ "@planfred/eslint-config": "git+https://github.com/planfred/eslint-config.git#v1.0.0"
98
+ }
99
+ }
100
+ ```
101
+
102
+ ## Configuration Structure
103
+
104
+ The shared configurations are organized as follows:
105
+
106
+ - `base.js` - Core configuration with common rules
107
+ - `vue.js` - Vue.js specific configuration extending base
108
+ - `cypress.js` - Cypress testing configuration extending base
109
+ - `test.js` - General testing configuration extending base
110
+
111
+ Each configuration can be extended and overridden as needed in individual projects.
package/base.js ADDED
@@ -0,0 +1,457 @@
1
+ /** @type {import('eslint').Linter.Config[]} */
2
+ import js from '@eslint/js'
3
+ import stylisticPlugin from '@stylistic/eslint-plugin'
4
+ import importPlugin from 'eslint-plugin-import'
5
+ import nodePlugin from 'eslint-plugin-n'
6
+ import promisePlugin from 'eslint-plugin-promise'
7
+ import globals from 'globals'
8
+
9
+ export default [
10
+ js.configs.recommended,
11
+ {
12
+ plugins: {
13
+ import: importPlugin,
14
+ promise: promisePlugin,
15
+ n: nodePlugin,
16
+ stylistic: stylisticPlugin,
17
+ },
18
+ languageOptions: {
19
+ sourceType: 'module',
20
+ globals: {
21
+ ...globals.node,
22
+ ...globals.browser,
23
+ },
24
+ },
25
+ rules: {
26
+ 'comma-dangle': 'off', // turn off because of stylistic/comma-dangle
27
+ 'no-console': 'off',
28
+
29
+ // standard rules
30
+ 'no-var': 'warn',
31
+ 'object-shorthand': ['warn', 'properties'],
32
+ 'accessor-pairs': [
33
+ 'error',
34
+ {
35
+ setWithoutGet: true,
36
+ enforceForClassMembers: true,
37
+ },
38
+ ],
39
+ 'array-callback-return': [
40
+ 'error',
41
+ {
42
+ allowImplicit: false,
43
+ checkForEach: false,
44
+ },
45
+ ],
46
+ camelcase: [
47
+ 'error',
48
+ {
49
+ allow: ['^UNSAFE_'],
50
+ properties: 'never',
51
+ ignoreGlobals: true,
52
+ },
53
+ ],
54
+ 'comma-style': ['error', 'last'],
55
+ 'constructor-super': 'error',
56
+ curly: ['error', 'multi-line'],
57
+ 'default-case-last': 'error',
58
+ 'dot-notation': ['error', { allowKeywords: true }],
59
+ eqeqeq: ['error', 'always', { null: 'ignore' }],
60
+ 'new-cap': [
61
+ 'error',
62
+ {
63
+ newIsCap: true,
64
+ capIsNew: false,
65
+ properties: true,
66
+ },
67
+ ],
68
+ 'no-array-constructor': 'error',
69
+ 'no-async-promise-executor': 'error',
70
+ 'no-caller': 'error',
71
+ 'no-case-declarations': 'error',
72
+ 'no-class-assign': 'error',
73
+ 'no-compare-neg-zero': 'error',
74
+ 'no-cond-assign': 'error',
75
+ 'no-const-assign': 'error',
76
+ 'no-constant-condition': ['error', { checkLoops: false }],
77
+ 'no-control-regex': 'error',
78
+ 'no-debugger': 'error',
79
+ 'no-delete-var': 'error',
80
+ 'no-dupe-args': 'error',
81
+ 'no-dupe-class-members': 'error',
82
+ 'no-dupe-keys': 'error',
83
+ 'no-duplicate-case': 'error',
84
+ 'no-useless-backreference': 'error',
85
+ 'no-empty': ['error', { allowEmptyCatch: true }],
86
+ 'no-empty-character-class': 'error',
87
+ 'no-empty-pattern': 'error',
88
+ 'no-eval': 'error',
89
+ 'no-ex-assign': 'error',
90
+ 'no-extend-native': 'error',
91
+ 'no-extra-bind': 'error',
92
+ 'no-extra-boolean-cast': 'error',
93
+ 'no-fallthrough': 'error',
94
+ 'no-func-assign': 'error',
95
+ 'no-global-assign': 'error',
96
+ 'no-implied-eval': 'error',
97
+ 'no-import-assign': 'error',
98
+ 'no-invalid-regexp': 'error',
99
+ 'no-irregular-whitespace': 'error',
100
+ 'no-iterator': 'error',
101
+ 'no-labels': [
102
+ 'error',
103
+ {
104
+ allowLoop: false,
105
+ allowSwitch: false,
106
+ },
107
+ ],
108
+ 'no-lone-blocks': 'error',
109
+ 'no-loss-of-precision': 'error',
110
+ 'no-misleading-character-class': 'error',
111
+ 'no-multi-str': 'error',
112
+ 'no-prototype-builtins': 'error',
113
+ 'no-useless-catch': 'error',
114
+ 'no-new': 'error',
115
+ 'no-new-func': 'error',
116
+ 'no-new-object': 'error',
117
+ 'no-new-symbol': 'error',
118
+ 'no-new-wrappers': 'error',
119
+ 'no-obj-calls': 'error',
120
+ 'no-octal': 'error',
121
+ 'no-octal-escape': 'error',
122
+ 'no-proto': 'error',
123
+ 'no-redeclare': ['error', { builtinGlobals: false }],
124
+ 'no-regex-spaces': 'error',
125
+ 'no-return-assign': ['error', 'except-parens'],
126
+ 'no-self-assign': ['error', { props: true }],
127
+ 'no-self-compare': 'error',
128
+ 'no-sequences': 'error',
129
+ 'no-shadow-restricted-names': 'error',
130
+ 'no-sparse-arrays': 'error',
131
+ 'no-template-curly-in-string': 'error',
132
+ 'no-this-before-super': 'error',
133
+ 'no-throw-literal': 'error',
134
+ 'no-undef': 'error',
135
+ 'no-undef-init': 'error',
136
+ 'no-unexpected-multiline': 'error',
137
+ 'no-unmodified-loop-condition': 'error',
138
+ 'no-unneeded-ternary': ['error', { defaultAssignment: false }],
139
+ 'no-unreachable': 'error',
140
+ 'no-unreachable-loop': 'error',
141
+ 'no-unsafe-finally': 'error',
142
+ 'no-unsafe-negation': 'error',
143
+ 'no-unused-expressions': [
144
+ 'error',
145
+ {
146
+ allowShortCircuit: true,
147
+ allowTernary: true,
148
+ allowTaggedTemplates: true,
149
+ },
150
+ ],
151
+ 'no-unused-vars': [
152
+ 'error',
153
+ {
154
+ args: 'none',
155
+ caughtErrors: 'none',
156
+ ignoreRestSiblings: true,
157
+ vars: 'all',
158
+ argsIgnorePattern: '^_',
159
+ destructuredArrayIgnorePattern: '^_',
160
+ },
161
+ ],
162
+ 'no-use-before-define': [
163
+ 'error',
164
+ {
165
+ functions: false,
166
+ classes: false,
167
+ variables: false,
168
+ },
169
+ ],
170
+ 'no-useless-call': 'error',
171
+ 'no-useless-computed-key': 'error',
172
+ 'no-useless-constructor': 'error',
173
+ 'no-useless-escape': 'error',
174
+ 'no-useless-rename': 'error',
175
+ 'no-useless-return': 'error',
176
+ 'no-void': 'error',
177
+ 'no-with': 'error',
178
+ 'one-var': ['error', { initialized: 'never' }],
179
+ 'prefer-const': ['error', { destructuring: 'all' }],
180
+ 'prefer-promise-reject-errors': 'error',
181
+ 'prefer-regex-literals': ['error', { disallowRedundantWrapping: true }],
182
+ 'symbol-description': 'error',
183
+ 'unicode-bom': ['error', 'never'],
184
+ 'use-isnan': [
185
+ 'error',
186
+ {
187
+ enforceForSwitchCase: true,
188
+ enforceForIndexOf: true,
189
+ },
190
+ ],
191
+ 'valid-typeof': ['error', { requireStringLiterals: true }],
192
+ yoda: ['error', 'never'],
193
+
194
+ // import rules
195
+ 'import/export': 'error',
196
+ 'import/first': 'error',
197
+ 'import/order': [
198
+ 'error',
199
+ {
200
+ 'newlines-between': 'always',
201
+ groups: [
202
+ ['builtin', 'external'],
203
+ 'internal',
204
+ ['parent', 'sibling', 'index'],
205
+ ],
206
+ alphabetize: {
207
+ order: 'asc',
208
+ caseInsensitive: true,
209
+ },
210
+ },
211
+ ],
212
+ 'import/no-absolute-path': [
213
+ 'error',
214
+ {
215
+ esmodule: true,
216
+ commonjs: true,
217
+ amd: false,
218
+ },
219
+ ],
220
+ 'import/no-duplicates': 'error',
221
+ 'import/no-named-default': 'error',
222
+ 'import/no-webpack-loader-syntax': 'error',
223
+
224
+ // n rules
225
+ 'n/handle-callback-err': ['error', '^(err|error)$'],
226
+ 'n/no-callback-literal': 'error',
227
+ 'n/no-deprecated-api': 'error',
228
+ 'n/no-exports-assign': 'error',
229
+ 'n/no-new-require': 'error',
230
+ 'n/no-path-concat': 'error',
231
+ 'n/process-exit-as-throw': 'error',
232
+
233
+ // promise rules
234
+ 'promise/param-names': 'error',
235
+
236
+ // custom style rules
237
+ 'stylistic/array-bracket-newline': ['warn', 'consistent'],
238
+ 'stylistic/array-element-newline': [
239
+ 'warn',
240
+ { ArrayExpression: 'consistent' },
241
+ ],
242
+ 'stylistic/arrow-parens': 'off',
243
+ 'stylistic/template-curly-spacing': ['off'],
244
+
245
+ // standard style rules
246
+ 'stylistic/array-bracket-spacing': ['error', 'never'],
247
+ 'stylistic/arrow-spacing': [
248
+ 'error',
249
+ {
250
+ before: true,
251
+ after: true,
252
+ },
253
+ ],
254
+ 'stylistic/block-spacing': ['error', 'always'],
255
+ 'stylistic/brace-style': ['error', '1tbs', { allowSingleLine: true }],
256
+ 'stylistic/comma-dangle': [
257
+ 'error',
258
+ {
259
+ arrays: 'always-multiline',
260
+ objects: 'always-multiline',
261
+ imports: 'always-multiline',
262
+ exports: 'always-multiline',
263
+ functions: 'always-multiline',
264
+ },
265
+ ],
266
+ 'stylistic/comma-spacing': [
267
+ 'error',
268
+ {
269
+ before: false,
270
+ after: true,
271
+ },
272
+ ],
273
+ 'stylistic/computed-property-spacing': [
274
+ 'error',
275
+ 'never',
276
+ { enforceForClassMembers: true },
277
+ ],
278
+ 'stylistic/dot-location': ['error', 'property'],
279
+ 'stylistic/eol-last': 'error',
280
+ 'stylistic/function-call-spacing': ['error', 'never'],
281
+ 'stylistic/generator-star-spacing': [
282
+ 'error',
283
+ {
284
+ before: true,
285
+ after: true,
286
+ },
287
+ ],
288
+ 'stylistic/indent': [
289
+ 'error',
290
+ 2,
291
+ {
292
+ SwitchCase: 1,
293
+ VariableDeclarator: 1,
294
+ outerIIFEBody: 1,
295
+ MemberExpression: 1,
296
+ FunctionDeclaration: {
297
+ parameters: 1,
298
+ body: 1,
299
+ },
300
+ FunctionExpression: {
301
+ parameters: 1,
302
+ body: 1,
303
+ },
304
+ CallExpression: { arguments: 1 },
305
+ ArrayExpression: 1,
306
+ ObjectExpression: 1,
307
+ ImportDeclaration: 1,
308
+ flatTernaryExpressions: false,
309
+ ignoreComments: false,
310
+ ignoredNodes: [
311
+ 'TemplateLiteral *',
312
+ 'JSXElement',
313
+ 'JSXElement > *',
314
+ 'JSXAttribute',
315
+ 'JSXIdentifier',
316
+ 'JSXNamespacedName',
317
+ 'JSXMemberExpression',
318
+ 'JSXSpreadAttribute',
319
+ 'JSXExpressionContainer',
320
+ 'JSXOpeningElement',
321
+ 'JSXClosingElement',
322
+ 'JSXFragment',
323
+ 'JSXOpeningFragment',
324
+ 'JSXClosingFragment',
325
+ 'JSXText',
326
+ 'JSXEmptyExpression',
327
+ 'JSXSpreadChild',
328
+ ],
329
+ offsetTernaryExpressions: true,
330
+ },
331
+ ],
332
+ 'stylistic/key-spacing': [
333
+ 'error',
334
+ {
335
+ beforeColon: false,
336
+ afterColon: true,
337
+ },
338
+ ],
339
+ 'stylistic/keyword-spacing': [
340
+ 'error',
341
+ {
342
+ before: true,
343
+ after: true,
344
+ },
345
+ ],
346
+ 'stylistic/lines-between-class-members': [
347
+ 'error',
348
+ 'always',
349
+ { exceptAfterSingleLine: true },
350
+ ],
351
+ 'stylistic/multiline-ternary': ['error', 'always-multiline'],
352
+ 'stylistic/new-parens': 'error',
353
+ 'stylistic/no-extra-parens': ['error', 'functions'],
354
+ 'stylistic/no-floating-decimal': 'error',
355
+ 'stylistic/no-mixed-operators': [
356
+ 'error',
357
+ {
358
+ groups: [
359
+ ['==', '!=', '===', '!==', '>', '>=', '<', '<='],
360
+ ['&&', '||'],
361
+ ['in', 'instanceof'],
362
+ ],
363
+ allowSamePrecedence: true,
364
+ },
365
+ ],
366
+ 'stylistic/no-mixed-spaces-and-tabs': 'error',
367
+ 'stylistic/no-multi-spaces': 'error',
368
+ 'stylistic/no-multiple-empty-lines': [
369
+ 'error',
370
+ {
371
+ max: 1,
372
+ maxBOF: 0,
373
+ maxEOF: 0,
374
+ },
375
+ ],
376
+ 'stylistic/no-tabs': 'error',
377
+ 'stylistic/no-trailing-spaces': 'error',
378
+ 'stylistic/no-whitespace-before-property': 'error',
379
+ 'stylistic/object-curly-newline': [
380
+ 'error',
381
+ {
382
+ multiline: true,
383
+ consistent: true,
384
+ },
385
+ ],
386
+ 'stylistic/object-curly-spacing': ['error', 'always'],
387
+ 'stylistic/object-property-newline': 'error',
388
+ 'stylistic/operator-linebreak': [
389
+ 'error',
390
+ 'after',
391
+ {
392
+ overrides: {
393
+ '?': 'before',
394
+ ':': 'before',
395
+ '|>': 'before',
396
+ },
397
+ },
398
+ ],
399
+ 'stylistic/padded-blocks': [
400
+ 'error',
401
+ {
402
+ blocks: 'never',
403
+ switches: 'never',
404
+ classes: 'never',
405
+ },
406
+ ],
407
+ 'stylistic/quote-props': ['error', 'as-needed'],
408
+ 'stylistic/quotes': [
409
+ 'error',
410
+ 'single',
411
+ {
412
+ avoidEscape: true,
413
+ allowTemplateLiterals: 'never',
414
+ },
415
+ ],
416
+ 'stylistic/rest-spread-spacing': ['error', 'never'],
417
+ 'stylistic/semi': ['error', 'never'],
418
+ 'stylistic/semi-spacing': [
419
+ 'error',
420
+ {
421
+ before: false,
422
+ after: true,
423
+ },
424
+ ],
425
+ 'stylistic/space-before-blocks': ['error', 'always'],
426
+ 'stylistic/space-before-function-paren': ['error', 'always'],
427
+ 'stylistic/space-in-parens': ['error', 'never'],
428
+ 'stylistic/space-infix-ops': 'error',
429
+ 'stylistic/space-unary-ops': [
430
+ 'error',
431
+ {
432
+ words: true,
433
+ nonwords: false,
434
+ },
435
+ ],
436
+ 'stylistic/spaced-comment': [
437
+ 'error',
438
+ 'always',
439
+ {
440
+ line: { markers: ['*package', '!', '/', ',', '='] },
441
+ block: {
442
+ balanced: true,
443
+ markers: ['*package', '!', ',', ':', '::', 'flow-include'],
444
+ exceptions: ['*'],
445
+ },
446
+ },
447
+ ],
448
+ 'stylistic/template-tag-spacing': ['error', 'never'],
449
+ 'stylistic/wrap-iife': [
450
+ 'error',
451
+ 'any',
452
+ { functionPrototypeMethods: true },
453
+ ],
454
+ 'stylistic/yield-star-spacing': ['error', 'both'],
455
+ },
456
+ },
457
+ ]
package/cypress.js ADDED
@@ -0,0 +1,30 @@
1
+ /** @type {import('eslint').Linter.Config[]} */
2
+ import cypressPlugin from 'eslint-plugin-cypress/flat'
3
+ import noOnlyTestsPlugin from 'eslint-plugin-no-only-tests'
4
+ import globals from 'globals'
5
+ import tsEslint from 'typescript-eslint'
6
+
7
+ import baseConfig from './base.js'
8
+
9
+ export default [
10
+ ...baseConfig,
11
+ ...tsEslint.configs.recommended,
12
+ cypressPlugin.configs.recommended,
13
+ {
14
+ plugins: {
15
+ '@typescript-eslint': tsEslint.plugin,
16
+ noOnlyTestsPlugin,
17
+ },
18
+ languageOptions: {
19
+ parser: tsEslint.parser,
20
+ globals: {
21
+ ...globals.node,
22
+ ...globals.browser,
23
+ },
24
+ },
25
+ rules: {
26
+ '@typescript-eslint/no-require-imports': 'off',
27
+ 'noOnlyTestsPlugin/no-only-tests': 'error',
28
+ },
29
+ },
30
+ ]
@@ -0,0 +1,9 @@
1
+ import baseConfig from './base.js'
2
+
3
+ export default [
4
+ ...baseConfig,
5
+ {
6
+ files: ['**/*.js'],
7
+ ignores: ['node_modules/**', 'dist/**'],
8
+ },
9
+ ]
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@planfredapp/eslint-config",
3
+ "version": "1.0.9",
4
+ "description": "Shared ESLint configurations for Planfred monorepo",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "exports": {
8
+ ".": "./base.js",
9
+ "./base": "./base.js",
10
+ "./vue": "./vue.js",
11
+ "./cypress": "./cypress.js",
12
+ "./test": "./test.js"
13
+ },
14
+ "files": [
15
+ "*.js"
16
+ ],
17
+ "scripts": {
18
+ "lint": "eslint .",
19
+ "lint:fix": "eslint . --fix",
20
+ "test": "vitest",
21
+ "test:run": "vitest run",
22
+ "ncu": "NCU_COOLDOWN_DAYS=${NCU_COOLDOWN_DAYS:-3}; npx npm-check-updates@latest -u --cooldown $NCU_COOLDOWN_DAYS",
23
+ "upgrade": "git stash; NCU_OUTPUT=${node --run ncu}; npm install; echo \"$NCU_OUTPUT\"; git commit -am \"Upgrade npm packages: \n\n$NCU_OUTPUT\"; git push --force-with-lease;",
24
+ "tag": "git tag v$(node -p \"require('./package.json').version\") || true",
25
+ "tag:push": "git push origin v$(node -p \"require('./package.json').version\")",
26
+ "release": "npm run tag && npm run tag:push",
27
+ "version:patch": "npm version patch && npm run release",
28
+ "version:minor": "npm version minor && npm run release",
29
+ "version:major": "npm version major && npm run release",
30
+ "publish": "npm publish --access public"
31
+ },
32
+ "dependencies": {
33
+ "@eslint/js": "9.36.0",
34
+ "@stylistic/eslint-plugin": "5.4.0",
35
+ "eslint-plugin-import": "2.32.0",
36
+ "eslint-plugin-n": "17.23.1",
37
+ "eslint-plugin-promise": "7.2.1",
38
+ "eslint-plugin-vue": "10.5.0",
39
+ "eslint-plugin-cypress": "5.1.1",
40
+ "eslint-plugin-no-only-tests": "3.3.0",
41
+ "eslint-plugin-no-relative-import-paths": "1.6.1",
42
+ "@vitest/eslint-plugin": "1.3.13",
43
+ "typescript-eslint": "8.44.0",
44
+ "globals": "16.4.0"
45
+ },
46
+ "devDependencies": {
47
+ "vitest": "3.2.4",
48
+ "eslint": "9.36.0",
49
+ "typescript": "5.9.2",
50
+ "vue-eslint-parser": "10.2.0"
51
+ },
52
+ "peerDependencies": {
53
+ "eslint": "9.0.0"
54
+ }
55
+ }
package/test.js ADDED
@@ -0,0 +1,45 @@
1
+ /** @type {import('eslint').Linter.Config[]} */
2
+ import vitestPlugin from '@vitest/eslint-plugin'
3
+ import noOnlyTestsPlugin from 'eslint-plugin-no-only-tests'
4
+ import globals from 'globals'
5
+
6
+ import baseConfig from './base.js'
7
+
8
+ export default [
9
+ ...baseConfig,
10
+ {
11
+ plugins: {
12
+ noOnlyTestsPlugin,
13
+ vitest: vitestPlugin,
14
+ },
15
+ languageOptions: {
16
+ globals: {
17
+ ...globals.node,
18
+ // Test globals
19
+ describe: 'readonly',
20
+ it: 'readonly',
21
+ test: 'readonly',
22
+ expect: 'readonly',
23
+ beforeEach: 'readonly',
24
+ beforeAll: 'readonly',
25
+ afterEach: 'readonly',
26
+ afterAll: 'readonly',
27
+ vi: 'readonly',
28
+ // Additional test globals
29
+ assert: 'readonly',
30
+ suite: 'readonly',
31
+ spec: 'readonly',
32
+ context: 'readonly',
33
+ // Chai globals
34
+ should: 'readonly',
35
+ },
36
+ },
37
+ rules: {
38
+ ...vitestPlugin.configs.recommended.rules,
39
+ 'vitest/valid-expect': 'off', // Produces too much false positives right now. Try again at some point.
40
+ 'vitest/expect-expect': 'off', // Sometimes expect statements are hidden in helper functions.
41
+ 'vitest/no-commented-out-tests': 'off',
42
+ 'noOnlyTestsPlugin/no-only-tests': 'error',
43
+ },
44
+ },
45
+ ]
@@ -0,0 +1,8 @@
1
+ import { defineConfig } from 'vitest/config'
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ globals: true,
6
+ environment: 'node',
7
+ },
8
+ })
package/vue.js ADDED
@@ -0,0 +1,191 @@
1
+ /** @type {import('eslint').Linter.Config[]} */
2
+ import noRelativeImportPathsPlugin from 'eslint-plugin-no-relative-import-paths'
3
+ import vuePlugin from 'eslint-plugin-vue'
4
+
5
+ import baseConfig from './base.js'
6
+
7
+ export default [
8
+ ...baseConfig,
9
+ ...vuePlugin.configs['flat/recommended'],
10
+ {
11
+ plugins: {
12
+ vue: vuePlugin,
13
+ },
14
+ rules: {
15
+ // vue rules
16
+ 'vue/padding-lines-in-component-definition': ['error'],
17
+ 'vue/padding-line-between-blocks': 'error',
18
+ 'vue/padding-line-between-tags': [
19
+ 'error',
20
+ [
21
+ {
22
+ blankLine: 'always',
23
+ prev: '*',
24
+ next: '*',
25
+ },
26
+ ],
27
+ ],
28
+ 'vue/block-order': [
29
+ 'error',
30
+ {
31
+ order: ['template', 'script', 'style'],
32
+ },
33
+ ],
34
+ 'vue/no-undef-components': [
35
+ 'error',
36
+ {
37
+ ignorePatterns: [
38
+ 'PfIcon',
39
+ 'RouterLink',
40
+ 'i18n-t',
41
+ 'trix-editor',
42
+ 'trix-toolbar',
43
+ ],
44
+ },
45
+ ],
46
+ 'vue/html-comment-content-newline': [
47
+ 'error',
48
+ {
49
+ singleline: 'ignore',
50
+ multiline: 'always',
51
+ },
52
+ ],
53
+ 'vue/no-unused-refs': 'error',
54
+ 'vue/no-unused-emit-declarations': 'error',
55
+ 'vue/no-undef-properties': 'error',
56
+ 'vue/no-this-in-before-route-enter': 'error',
57
+ 'vue/html-comment-indent': 'error',
58
+ 'vue/html-comment-content-spacing': 'error',
59
+ 'vue/component-name-in-template-casing': 'warn',
60
+ 'vue/multi-word-component-names': 'off',
61
+ 'vue/new-line-between-multi-line-property': 2,
62
+ 'vue/no-deprecated-slot-attribute': 'off',
63
+ 'vue/no-multiple-template-root': 'error',
64
+ 'vue/no-unused-properties': [
65
+ 'warn',
66
+ {
67
+ groups: ['props', 'data', 'computed', 'methods', 'setup'],
68
+ deepData: false,
69
+ ignorePublicMembers: false,
70
+ unreferencedOptions: [],
71
+ },
72
+ ],
73
+ 'vue/no-v-html': 'error',
74
+ 'vue/eqeqeq': 'error',
75
+
76
+ 'vue/array-bracket-newline': ['warn', 'consistent'],
77
+ 'vue/array-element-newline': [
78
+ 'warn',
79
+ { ArrayExpression: 'consistent' },
80
+ ],
81
+ 'vue/arrow-parens': 'off',
82
+ 'vue/template-curly-spacing': ['off'],
83
+
84
+ // extensions of stylistic rules applied to the template tag
85
+ 'vue/array-bracket-spacing': ['error', 'never'],
86
+ 'vue/arrow-spacing': [
87
+ 'error',
88
+ {
89
+ before: true,
90
+ after: true,
91
+ },
92
+ ],
93
+ 'vue/block-spacing': ['error', 'always'],
94
+ 'vue/brace-style': ['error', '1tbs', { allowSingleLine: true }],
95
+ 'vue/comma-dangle': [
96
+ 'error',
97
+ {
98
+ arrays: 'always-multiline',
99
+ objects: 'always-multiline',
100
+ imports: 'always-multiline',
101
+ exports: 'always-multiline',
102
+ functions: 'always-multiline',
103
+ },
104
+ ],
105
+ 'vue/comma-spacing': [
106
+ 'error',
107
+ {
108
+ before: false,
109
+ after: true,
110
+ },
111
+ ],
112
+ 'vue/dot-location': ['error', 'property'],
113
+ 'vue/func-call-spacing': ['error', 'never'],
114
+ 'vue/key-spacing': [
115
+ 'error',
116
+ {
117
+ beforeColon: false,
118
+ afterColon: true,
119
+ },
120
+ ],
121
+ 'vue/keyword-spacing': [
122
+ 'error',
123
+ {
124
+ before: true,
125
+ after: true,
126
+ },
127
+ ],
128
+ 'vue/multiline-ternary': ['error', 'always-multiline'],
129
+ 'vue/no-extra-parens': ['error', 'functions'],
130
+ 'vue/object-curly-newline': [
131
+ 'error',
132
+ {
133
+ multiline: true,
134
+ consistent: true,
135
+ },
136
+ ],
137
+ 'vue/object-curly-spacing': ['error', 'always'],
138
+ 'vue/object-property-newline': 'error',
139
+ 'vue/operator-linebreak': [
140
+ 'error',
141
+ 'after',
142
+ {
143
+ overrides: {
144
+ '?': 'before',
145
+ ':': 'before',
146
+ '|>': 'before',
147
+ },
148
+ },
149
+ ],
150
+ 'vue/space-in-parens': ['error', 'never'],
151
+ 'vue/space-infix-ops': 'error',
152
+ 'vue/space-unary-ops': [
153
+ 'error',
154
+ {
155
+ words: true,
156
+ nonwords: false,
157
+ },
158
+ ],
159
+ },
160
+ },
161
+ {
162
+ // IMPORTANT: These rules should be only applied to components, not pages. That's why we filter the files here
163
+ files: ['src/components/**/*'],
164
+ rules: {
165
+ 'vue/match-component-file-name': [
166
+ 'error',
167
+ {
168
+ extensions: ['vue'],
169
+ shouldMatchCase: true,
170
+ },
171
+ ],
172
+ 'vue/require-name-property': 'error',
173
+ },
174
+ },
175
+ {
176
+ files: ['src/**/*'], // exclude files from root folder
177
+ plugins: {
178
+ noRelativeImportPathsPlugin,
179
+ },
180
+ rules: {
181
+ 'noRelativeImportPathsPlugin/no-relative-import-paths': [
182
+ 'error',
183
+ {
184
+ allowSameFolder: false,
185
+ rootDir: 'src',
186
+ prefix: '@',
187
+ },
188
+ ],
189
+ },
190
+ },
191
+ ]