@borela-tech/eslint-config 1.3.1 → 1.3.3
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/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/rules/individualImports.ts +46 -0
- package/src/rules/sortedImports.ts +83 -0
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import eslint from '@eslint/js'\nimport react from 'eslint-plugin-react'\nimport reactHooks from 'eslint-plugin-react-hooks'\nimport stylistic from '@stylistic/eslint-plugin'\nimport typescript from 'typescript-eslint'\n\nexport const CONFIG = typescript.config(\n {\n ignores: [\n 'src/graphql/sdk.ts',\n '**/node_modules/**',\n '**/dist/**',\n ],\n settings: {\n react: {\n version: '19',\n },\n },\n },\n eslint.configs.recommended,\n react.configs.flat.recommended,\n stylistic.configs.recommended,\n typescript.configs.recommended,\n typescript.configs.stylistic,\n {\n plugins: {\n 'react-hooks': reactHooks,\n },\n rules: reactHooks.configs.recommended.rules,\n },\n {\n rules: {\n 'capitalized-comments': [\n 'error',\n 'always',\n {ignoreConsecutiveComments: true},\n ],\n 'react/react-in-jsx-scope': 'off',\n '@stylistic/arrow-parens': [\n 'error',\n 'as-needed',\n ],\n '@stylistic/array-bracket-newline': [\n 'error',\n 'consistent',\n ],\n '@stylistic/array-bracket-spacing': [\n 'error',\n 'never',\n ],\n '@stylistic/array-element-newline': [\n 'error',\n 'consistent',\n ],\n '@stylistic/brace-style': [\n 'error',\n '1tbs',\n {allowSingleLine: true},\n ],\n '@stylistic/indent': [\n 'error',\n 2,\n {ignoredNodes: ['TSMappedType > *']},\n ],\n '@stylistic/jsx-tag-spacing': [\n 'error',\n {\n afterOpening: 'never',\n beforeClosing: 'never',\n beforeSelfClosing: 'never',\n closingSlash: 'never',\n },\n ],\n '@stylistic/jsx-wrap-multilines': 'off',\n '@stylistic/lines-between-class-members': 'off',\n '@stylistic/object-curly-newline': [\n 'error',\n {consistent: true},\n ],\n '@stylistic/object-curly-spacing': [\n 'error',\n 'never',\n ],\n '@stylistic/operator-linebreak': [\n 'error',\n 'before',\n {overrides: {'=': 'after'}},\n ],\n '@stylistic/quotes': [\n 'error',\n 'single',\n {avoidEscape: true},\n ],\n '@stylistic/quote-props': [\n 'error',\n 'as-needed',\n ],\n '@stylistic/semi': [\n 'error',\n 'never',\n {beforeStatementContinuationChars: 'always'},\n ],\n '@typescript-eslint/no-empty-function': 'off',\n '@typescript-eslint/consistent-indexed-object-style': 'off',\n 'sort-imports': [\n 'error',\n {\n allowSeparatedGroups: true,\n ignoreCase: true,\n ignoreMemberSort: false,\n memberSyntaxSortOrder: [\n 'none',\n 'all',\n 'single',\n 'multiple',\n ],\n },\n ],\n },\n },\n)\n"],"mappings":";AAAA,OAAO,YAAY;AACnB,OAAO,WAAW;AAClB,OAAO,gBAAgB;AACvB,OAAO,eAAe;AACtB,OAAO,gBAAgB;AAEhB,IAAM,SAAS,WAAW;AAAA,EAC/B;AAAA,IACE,SAAS;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,UAAU;AAAA,MACR,OAAO;AAAA,QACL,SAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF;AAAA,EACA,OAAO,QAAQ;AAAA,EACf,MAAM,QAAQ,KAAK;AAAA,EACnB,UAAU,QAAQ;AAAA,EAClB,WAAW,QAAQ;AAAA,EACnB,WAAW,QAAQ;AAAA,EACnB;AAAA,IACE,SAAS;AAAA,MACP,eAAe;AAAA,IACjB;AAAA,IACA,OAAO,WAAW,QAAQ,YAAY;AAAA,EACxC;AAAA,EACA;AAAA,IACE,OAAO;AAAA,MACL,wBAAwB;AAAA,QACtB;AAAA,QACA;AAAA,QACA,EAAC,2BAA2B,KAAI;AAAA,MAClC;AAAA,MACA,4BAA4B;AAAA,MAC5B,2BAA2B;AAAA,QACzB;AAAA,QACA;AAAA,MACF;AAAA,MACA,oCAAoC;AAAA,QAClC;AAAA,QACA;AAAA,MACF;AAAA,MACA,oCAAoC;AAAA,QAClC;AAAA,QACA;AAAA,MACF;AAAA,MACA,oCAAoC;AAAA,QAClC;AAAA,QACA;AAAA,MACF;AAAA,MACA,0BAA0B;AAAA,QACxB;AAAA,QACA;AAAA,QACA,EAAC,iBAAiB,KAAI;AAAA,MACxB;AAAA,MACA,qBAAqB;AAAA,QACnB;AAAA,QACA;AAAA,QACA,EAAC,cAAc,CAAC,kBAAkB,EAAC;AAAA,MACrC;AAAA,MACA,8BAA8B;AAAA,QAC5B;AAAA,QACA;AAAA,UACE,cAAc;AAAA,UACd,eAAe;AAAA,UACf,mBAAmB;AAAA,UACnB,cAAc;AAAA,QAChB;AAAA,MACF;AAAA,MACA,kCAAkC;AAAA,MAClC,0CAA0C;AAAA,MAC1C,mCAAmC;AAAA,QACjC;AAAA,QACA,EAAC,YAAY,KAAI;AAAA,MACnB;AAAA,MACA,mCAAmC;AAAA,QACjC;AAAA,QACA;AAAA,MACF;AAAA,MACA,iCAAiC;AAAA,QAC/B;AAAA,QACA;AAAA,QACA,EAAC,WAAW,EAAC,KAAK,QAAO,EAAC;AAAA,MAC5B;AAAA,MACA,qBAAqB;AAAA,QACnB;AAAA,QACA;AAAA,QACA,EAAC,aAAa,KAAI;AAAA,MACpB;AAAA,MACA,0BAA0B;AAAA,QACxB;AAAA,QACA;AAAA,MACF;AAAA,MACA,mBAAmB;AAAA,QACjB;AAAA,QACA;AAAA,QACA,EAAC,kCAAkC,SAAQ;AAAA,MAC7C;AAAA,MACA,wCAAwC;AAAA,MACxC,sDAAsD;AAAA,MACtD,gBAAgB;AAAA,QACd;AAAA,QACA;AAAA,UACE,sBAAsB;AAAA,UACtB,YAAY;AAAA,UACZ,kBAAkB;AAAA,UAClB,uBAAuB;AAAA,YACrB;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import eslint from '@eslint/js'\nimport react from 'eslint-plugin-react'\nimport reactHooks from 'eslint-plugin-react-hooks'\nimport stylistic from '@stylistic/eslint-plugin'\nimport typescript from 'typescript-eslint'\n\nexport const CONFIG = typescript.config(\n {\n ignores: [\n 'src/graphql/sdk.ts',\n '**/node_modules/**',\n '**/dist/**',\n ],\n settings: {\n react: {\n version: '19',\n },\n },\n },\n eslint.configs.recommended,\n react.configs.flat.recommended,\n stylistic.configs.recommended,\n typescript.configs.recommended,\n typescript.configs.stylistic,\n {\n plugins: {\n 'react-hooks': reactHooks,\n },\n rules: reactHooks.configs.recommended.rules,\n },\n {\n rules: {\n 'capitalized-comments': [\n 'error',\n 'always',\n {ignoreConsecutiveComments: true},\n ],\n 'react/react-in-jsx-scope': 'off',\n '@stylistic/arrow-parens': [\n 'error',\n 'as-needed',\n ],\n '@stylistic/array-bracket-newline': [\n 'error',\n 'consistent',\n ],\n '@stylistic/array-bracket-spacing': [\n 'error',\n 'never',\n ],\n '@stylistic/array-element-newline': [\n 'error',\n 'consistent',\n ],\n '@stylistic/block-spacing': 'off',\n '@stylistic/brace-style': [\n 'error',\n '1tbs',\n {allowSingleLine: true},\n ],\n '@stylistic/indent': [\n 'error',\n 2,\n {ignoredNodes: ['TSMappedType > *']},\n ],\n '@stylistic/jsx-tag-spacing': [\n 'error',\n {\n afterOpening: 'never',\n beforeClosing: 'never',\n beforeSelfClosing: 'never',\n closingSlash: 'never',\n },\n ],\n '@stylistic/jsx-wrap-multilines': 'off',\n '@stylistic/lines-between-class-members': 'off',\n '@stylistic/object-curly-newline': [\n 'error',\n {consistent: true},\n ],\n '@stylistic/object-curly-spacing': [\n 'error',\n 'never',\n ],\n '@stylistic/operator-linebreak': [\n 'error',\n 'before',\n {overrides: {'=': 'after'}},\n ],\n '@stylistic/quotes': [\n 'error',\n 'single',\n {avoidEscape: true},\n ],\n '@stylistic/quote-props': [\n 'error',\n 'as-needed',\n ],\n '@stylistic/semi': [\n 'error',\n 'never',\n {beforeStatementContinuationChars: 'always'},\n ],\n '@typescript-eslint/no-empty-function': 'off',\n '@typescript-eslint/consistent-indexed-object-style': 'off',\n 'sort-imports': [\n 'error',\n {\n allowSeparatedGroups: true,\n ignoreCase: true,\n ignoreMemberSort: false,\n memberSyntaxSortOrder: [\n 'none',\n 'all',\n 'single',\n 'multiple',\n ],\n },\n ],\n },\n },\n)\n"],"mappings":";AAAA,OAAO,YAAY;AACnB,OAAO,WAAW;AAClB,OAAO,gBAAgB;AACvB,OAAO,eAAe;AACtB,OAAO,gBAAgB;AAEhB,IAAM,SAAS,WAAW;AAAA,EAC/B;AAAA,IACE,SAAS;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,UAAU;AAAA,MACR,OAAO;AAAA,QACL,SAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF;AAAA,EACA,OAAO,QAAQ;AAAA,EACf,MAAM,QAAQ,KAAK;AAAA,EACnB,UAAU,QAAQ;AAAA,EAClB,WAAW,QAAQ;AAAA,EACnB,WAAW,QAAQ;AAAA,EACnB;AAAA,IACE,SAAS;AAAA,MACP,eAAe;AAAA,IACjB;AAAA,IACA,OAAO,WAAW,QAAQ,YAAY;AAAA,EACxC;AAAA,EACA;AAAA,IACE,OAAO;AAAA,MACL,wBAAwB;AAAA,QACtB;AAAA,QACA;AAAA,QACA,EAAC,2BAA2B,KAAI;AAAA,MAClC;AAAA,MACA,4BAA4B;AAAA,MAC5B,2BAA2B;AAAA,QACzB;AAAA,QACA;AAAA,MACF;AAAA,MACA,oCAAoC;AAAA,QAClC;AAAA,QACA;AAAA,MACF;AAAA,MACA,oCAAoC;AAAA,QAClC;AAAA,QACA;AAAA,MACF;AAAA,MACA,oCAAoC;AAAA,QAClC;AAAA,QACA;AAAA,MACF;AAAA,MACA,4BAA4B;AAAA,MAC5B,0BAA0B;AAAA,QACxB;AAAA,QACA;AAAA,QACA,EAAC,iBAAiB,KAAI;AAAA,MACxB;AAAA,MACA,qBAAqB;AAAA,QACnB;AAAA,QACA;AAAA,QACA,EAAC,cAAc,CAAC,kBAAkB,EAAC;AAAA,MACrC;AAAA,MACA,8BAA8B;AAAA,QAC5B;AAAA,QACA;AAAA,UACE,cAAc;AAAA,UACd,eAAe;AAAA,UACf,mBAAmB;AAAA,UACnB,cAAc;AAAA,QAChB;AAAA,MACF;AAAA,MACA,kCAAkC;AAAA,MAClC,0CAA0C;AAAA,MAC1C,mCAAmC;AAAA,QACjC;AAAA,QACA,EAAC,YAAY,KAAI;AAAA,MACnB;AAAA,MACA,mCAAmC;AAAA,QACjC;AAAA,QACA;AAAA,MACF;AAAA,MACA,iCAAiC;AAAA,QAC/B;AAAA,QACA;AAAA,QACA,EAAC,WAAW,EAAC,KAAK,QAAO,EAAC;AAAA,MAC5B;AAAA,MACA,qBAAqB;AAAA,QACnB;AAAA,QACA;AAAA,QACA,EAAC,aAAa,KAAI;AAAA,MACpB;AAAA,MACA,0BAA0B;AAAA,QACxB;AAAA,QACA;AAAA,MACF;AAAA,MACA,mBAAmB;AAAA,QACjB;AAAA,QACA;AAAA,QACA,EAAC,kCAAkC,SAAQ;AAAA,MAC7C;AAAA,MACA,wCAAwC;AAAA,MACxC,sDAAsD;AAAA,MACtD,gBAAgB;AAAA,QACd;AAAA,QACA;AAAA,UACE,sBAAsB;AAAA,UACtB,YAAY;AAAA,UACZ,kBAAkB;AAAA,UAClB,uBAAuB;AAAA,YACrB;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type {Rule} from 'eslint'
|
|
2
|
+
|
|
3
|
+
export const individualImports: Rule.RuleModule = {
|
|
4
|
+
meta: {
|
|
5
|
+
docs: {
|
|
6
|
+
description: 'Enforce individual imports instead of grouped imports',
|
|
7
|
+
recommended: true,
|
|
8
|
+
},
|
|
9
|
+
fixable: 'code',
|
|
10
|
+
messages: {
|
|
11
|
+
individualImports: 'Use individual imports instead of grouped imports.',
|
|
12
|
+
},
|
|
13
|
+
schema: [],
|
|
14
|
+
type: 'suggestion',
|
|
15
|
+
},
|
|
16
|
+
create(context) {
|
|
17
|
+
return {
|
|
18
|
+
ImportDeclaration(node) {
|
|
19
|
+
if (node.specifiers.length <= 1)
|
|
20
|
+
return
|
|
21
|
+
context.report({
|
|
22
|
+
node,
|
|
23
|
+
messageId: 'individualImports',
|
|
24
|
+
fix(fixer) {
|
|
25
|
+
const source = node.source.raw
|
|
26
|
+
const specifiers = node.specifiers
|
|
27
|
+
.map(specifier => {
|
|
28
|
+
if (specifier.type === 'ImportSpecifier')
|
|
29
|
+
return `import {${specifier.local.name}} from ${source}`
|
|
30
|
+
return null
|
|
31
|
+
})
|
|
32
|
+
.filter(Boolean)
|
|
33
|
+
|
|
34
|
+
if (specifiers.length !== node.specifiers.length)
|
|
35
|
+
return null
|
|
36
|
+
|
|
37
|
+
return fixer.replaceText(
|
|
38
|
+
node,
|
|
39
|
+
specifiers.join('\n'),
|
|
40
|
+
)
|
|
41
|
+
},
|
|
42
|
+
})
|
|
43
|
+
},
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type {ImportDeclaration} from 'estree'
|
|
2
|
+
import type {Rule} from 'eslint'
|
|
3
|
+
|
|
4
|
+
export const sortedImports: Rule.RuleModule = {
|
|
5
|
+
meta: {
|
|
6
|
+
docs: {
|
|
7
|
+
description: 'Enforce sorted imports alphabetically',
|
|
8
|
+
recommended: true,
|
|
9
|
+
},
|
|
10
|
+
fixable: 'code',
|
|
11
|
+
messages: {
|
|
12
|
+
sortedImports: 'Imports should be sorted alphabetically',
|
|
13
|
+
},
|
|
14
|
+
schema: [],
|
|
15
|
+
type: 'suggestion',
|
|
16
|
+
},
|
|
17
|
+
create(context) {
|
|
18
|
+
return {
|
|
19
|
+
Program(node) {
|
|
20
|
+
const importDeclarations = node.body.filter(
|
|
21
|
+
(statement): statement is ImportDeclaration =>
|
|
22
|
+
statement.type === 'ImportDeclaration',
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
if (importDeclarations.length <= 1) return
|
|
26
|
+
|
|
27
|
+
const sortedImports = importDeclarations.sort((a, b) => {
|
|
28
|
+
const sourceA = (a.source.value as string).toLowerCase()
|
|
29
|
+
const sourceB = (b.source.value as string).toLowerCase()
|
|
30
|
+
return sourceA.localeCompare(sourceB)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
const isSorted = importDeclarations.every((decl, index) => decl === sortedImports[index])
|
|
34
|
+
|
|
35
|
+
if (!isSorted) {
|
|
36
|
+
context.report({
|
|
37
|
+
node: importDeclarations[0],
|
|
38
|
+
messageId: 'sortedImports',
|
|
39
|
+
fix(fixer) {
|
|
40
|
+
const sourceCode = context.getSourceCode()
|
|
41
|
+
|
|
42
|
+
// Find all consecutive import statements at the beginning
|
|
43
|
+
const programBody = node.body
|
|
44
|
+
let lastImportIndex = 0
|
|
45
|
+
for (let i = 0; i < programBody.length; i++) {
|
|
46
|
+
if (programBody[i].type === 'ImportDeclaration') {
|
|
47
|
+
lastImportIndex = i
|
|
48
|
+
} else {
|
|
49
|
+
break
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const firstImport = programBody[0] as import('estree').ImportDeclaration
|
|
54
|
+
const lastImport = programBody[lastImportIndex] as import('estree').ImportDeclaration
|
|
55
|
+
|
|
56
|
+
// Get the range from start of first import to end of last import
|
|
57
|
+
const startRange = firstImport.range![0]
|
|
58
|
+
let endRange = lastImport.range![1]
|
|
59
|
+
|
|
60
|
+
// Include any trailing whitespace/newlines after the last import
|
|
61
|
+
const fullText = sourceCode.getText()
|
|
62
|
+
for (let i = endRange; i < fullText.length; i++) {
|
|
63
|
+
const char = fullText[i]
|
|
64
|
+
if (char === '\n' || char === ' ' || char === '\t') {
|
|
65
|
+
endRange++
|
|
66
|
+
} else {
|
|
67
|
+
break
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Generate the sorted import code
|
|
72
|
+
const sortedCode = sortedImports.map(decl => {
|
|
73
|
+
return sourceCode.getText(decl)
|
|
74
|
+
}).join('\n')
|
|
75
|
+
|
|
76
|
+
return fixer.replaceTextRange([startRange, endRange], sortedCode)
|
|
77
|
+
},
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
}
|