@trigen/oxlint-config 9.2.2 → 9.3.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/package.json
CHANGED
package/src/plugin/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import extensionsRule from './extensions.js'
|
|
2
2
|
import importOrderRule from './import-order.js'
|
|
3
3
|
import memberOrderingRule from './member-ordering.js'
|
|
4
|
+
import namedExportOrderRule from './named-export-order.js'
|
|
4
5
|
import namedImportOrderRule from './named-import-order.js'
|
|
5
6
|
import namingConventionRule from './naming-convention.js'
|
|
6
7
|
import typeImportStyleRule from './type-import-style.js'
|
|
@@ -13,6 +14,7 @@ export default {
|
|
|
13
14
|
'extensions': extensionsRule,
|
|
14
15
|
'import-order': importOrderRule,
|
|
15
16
|
'member-ordering': memberOrderingRule,
|
|
17
|
+
'named-export-order': namedExportOrderRule,
|
|
16
18
|
'named-import-order': namedImportOrderRule,
|
|
17
19
|
'naming-convention': namingConventionRule,
|
|
18
20
|
'type-import-style': typeImportStyleRule
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
const defaultOptions = {
|
|
2
|
+
typeExports: 'none',
|
|
3
|
+
patterns: []
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
function getOptions(context) {
|
|
7
|
+
return {
|
|
8
|
+
...defaultOptions,
|
|
9
|
+
...context.options[0],
|
|
10
|
+
patterns: context.options[0]?.patterns ?? []
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function getName(specifier) {
|
|
15
|
+
const exported = specifier.exported ?? specifier.local
|
|
16
|
+
|
|
17
|
+
if (exported.type === 'Identifier') {
|
|
18
|
+
return exported.name
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return String(exported.value)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function isTypeSpecifier(node, specifier) {
|
|
25
|
+
return node.exportKind === 'type'
|
|
26
|
+
|| specifier.exportKind === 'type'
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function getTypeRank(node, specifier, options) {
|
|
30
|
+
if (options.typeExports === 'first') {
|
|
31
|
+
return isTypeSpecifier(node, specifier) ? 0 : 1
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (options.typeExports === 'last') {
|
|
35
|
+
return isTypeSpecifier(node, specifier) ? 1 : 0
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return 0
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function getPatternRank(name, patterns) {
|
|
42
|
+
const normalizedName = name.replace(/^\$+|\$+$/g, '')
|
|
43
|
+
const rank = patterns.findIndex(pattern => new RegExp(pattern).test(
|
|
44
|
+
normalizedName
|
|
45
|
+
))
|
|
46
|
+
|
|
47
|
+
return rank === -1 ? Number.POSITIVE_INFINITY : rank
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function getRank(node, specifier, options) {
|
|
51
|
+
const name = getName(specifier)
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
name,
|
|
55
|
+
typeRank: getTypeRank(node, specifier, options),
|
|
56
|
+
patternRank: getPatternRank(name, options.patterns)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function compareRanks(left, right) {
|
|
61
|
+
return left.typeRank - right.typeRank
|
|
62
|
+
|| left.patternRank - right.patternRank
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function getItems(node, options) {
|
|
66
|
+
return node.specifiers
|
|
67
|
+
.filter(specifier => specifier.type === 'ExportSpecifier')
|
|
68
|
+
.map((specifier, index) => ({
|
|
69
|
+
index,
|
|
70
|
+
specifier,
|
|
71
|
+
rank: getRank(node, specifier, options)
|
|
72
|
+
}))
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function compareItems(left, right) {
|
|
76
|
+
return compareRanks(left.rank, right.rank)
|
|
77
|
+
|| left.index - right.index
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function getFirstUnorderedPair(items) {
|
|
81
|
+
for (let index = 1; index < items.length; index++) {
|
|
82
|
+
const previousItem = items[index - 1]
|
|
83
|
+
const item = items[index]
|
|
84
|
+
|
|
85
|
+
if (compareItems(previousItem, item) > 0) {
|
|
86
|
+
return [
|
|
87
|
+
previousItem,
|
|
88
|
+
item
|
|
89
|
+
]
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return null
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function getLinebreak(text) {
|
|
97
|
+
return text.includes('\r\n') ? '\r\n' : '\n'
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function getLineIndent(text, index) {
|
|
101
|
+
const lineStart = text.lastIndexOf('\n', index - 1) + 1
|
|
102
|
+
const indentMatch = /^[ \t]*/.exec(text.slice(lineStart, index))
|
|
103
|
+
|
|
104
|
+
return indentMatch[0]
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function getBracesRange(node, items, sourceCode) {
|
|
108
|
+
const text = sourceCode.text
|
|
109
|
+
const firstSpecifier = items[0].specifier
|
|
110
|
+
const lastSpecifier = items.at(-1).specifier
|
|
111
|
+
const openingBrace = text.lastIndexOf('{', firstSpecifier.range[0])
|
|
112
|
+
const closingBrace = text.indexOf('}', lastSpecifier.range[1])
|
|
113
|
+
const searchEnd = node.source?.range?.[0] ?? node.range[1]
|
|
114
|
+
|
|
115
|
+
if (
|
|
116
|
+
openingBrace < node.range[0]
|
|
117
|
+
|| closingBrace === -1
|
|
118
|
+
|| closingBrace > searchEnd
|
|
119
|
+
) {
|
|
120
|
+
return null
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return [
|
|
124
|
+
openingBrace + 1,
|
|
125
|
+
closingBrace
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function hasInnerComments(sourceCode, range) {
|
|
130
|
+
return sourceCode.getAllComments().some(comment => comment.range[0] > range[0]
|
|
131
|
+
&& comment.range[1] < range[1])
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function shouldBeMultiline(sourceCode, range, items) {
|
|
135
|
+
return items.length > 1
|
|
136
|
+
&& !sourceCode.text.slice(range[0], range[1]).includes('\n')
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function getFixedText(node, items, options, sourceCode, range) {
|
|
140
|
+
const text = sourceCode.text
|
|
141
|
+
const content = text.slice(range[0], range[1])
|
|
142
|
+
const sortedSpecifiers = [...items]
|
|
143
|
+
.sort(compareItems)
|
|
144
|
+
.map(({ specifier }) => sourceCode.getText(specifier))
|
|
145
|
+
|
|
146
|
+
if (!content.includes('\n') && items.length < 2) {
|
|
147
|
+
return ` ${sortedSpecifiers.join(', ')} `
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const linebreak = getLinebreak(text)
|
|
151
|
+
const firstSpecifier = items[0].specifier
|
|
152
|
+
const closingIndent = getLineIndent(text, node.range[0])
|
|
153
|
+
const indent = content.includes('\n')
|
|
154
|
+
? getLineIndent(text, firstSpecifier.range[0])
|
|
155
|
+
: `${closingIndent} `
|
|
156
|
+
|
|
157
|
+
return `${linebreak}${indent}${sortedSpecifiers.join(`,${linebreak}${indent}`)}${linebreak}${closingIndent}`
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function getMessage(left, right) {
|
|
161
|
+
if (left.rank.typeRank !== right.rank.typeRank) {
|
|
162
|
+
return `Expected ${right.rank.name} to come before ${left.rank.name} because of export kind.`
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (left.rank.patternRank !== right.rank.patternRank) {
|
|
166
|
+
return `Expected ${right.rank.name} to come before ${left.rank.name} because of naming pattern.`
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return `Expected ${right.rank.name} to come before ${left.rank.name}.`
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export default {
|
|
173
|
+
meta: {
|
|
174
|
+
type: 'layout',
|
|
175
|
+
fixable: 'code',
|
|
176
|
+
docs: {
|
|
177
|
+
description: 'Enforce named export specifier order.'
|
|
178
|
+
},
|
|
179
|
+
schema: [
|
|
180
|
+
{
|
|
181
|
+
type: 'object',
|
|
182
|
+
properties: {
|
|
183
|
+
typeExports: {
|
|
184
|
+
enum: [
|
|
185
|
+
'first',
|
|
186
|
+
'last',
|
|
187
|
+
'none'
|
|
188
|
+
]
|
|
189
|
+
},
|
|
190
|
+
patterns: {
|
|
191
|
+
type: 'array',
|
|
192
|
+
items: {
|
|
193
|
+
type: 'string'
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
additionalProperties: true
|
|
198
|
+
}
|
|
199
|
+
]
|
|
200
|
+
},
|
|
201
|
+
create(context) {
|
|
202
|
+
const options = getOptions(context)
|
|
203
|
+
|
|
204
|
+
return {
|
|
205
|
+
ExportNamedDeclaration(node) {
|
|
206
|
+
const items = getItems(node, options)
|
|
207
|
+
|
|
208
|
+
if (items.length < 2) {
|
|
209
|
+
return
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const unorderedPair = getFirstUnorderedPair(items)
|
|
213
|
+
const sourceCode = context.sourceCode
|
|
214
|
+
const range = getBracesRange(node, items, sourceCode)
|
|
215
|
+
const invalidMultiline = range && shouldBeMultiline(
|
|
216
|
+
sourceCode,
|
|
217
|
+
range,
|
|
218
|
+
items
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
if (!unorderedPair && !invalidMultiline) {
|
|
222
|
+
return
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const fix = range && !hasInnerComments(sourceCode, range)
|
|
226
|
+
? fixer => fixer.replaceTextRange(
|
|
227
|
+
range,
|
|
228
|
+
getFixedText(node, items, options, sourceCode, range)
|
|
229
|
+
)
|
|
230
|
+
: null
|
|
231
|
+
const [
|
|
232
|
+
previousItem,
|
|
233
|
+
item
|
|
234
|
+
] = unorderedPair ?? [
|
|
235
|
+
items[0],
|
|
236
|
+
items[1]
|
|
237
|
+
]
|
|
238
|
+
|
|
239
|
+
context.report({
|
|
240
|
+
node: item.specifier,
|
|
241
|
+
message: unorderedPair
|
|
242
|
+
? getMessage(previousItem, item)
|
|
243
|
+
: 'Expected named exports to be multiline.',
|
|
244
|
+
fix
|
|
245
|
+
})
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
@@ -310,6 +310,12 @@ export default {
|
|
|
310
310
|
},
|
|
311
311
|
Property(node) {
|
|
312
312
|
checkProperty(node, 'objectLiteralProperty')
|
|
313
|
+
},
|
|
314
|
+
TSPropertySignature(node) {
|
|
315
|
+
checkProperty(node, 'objectLiteralProperty')
|
|
316
|
+
},
|
|
317
|
+
TSMethodSignature(node) {
|
|
318
|
+
checkProperty(node, 'objectLiteralMethod')
|
|
313
319
|
}
|
|
314
320
|
}
|
|
315
321
|
}
|
package/src/subconfigs/import.js
CHANGED
|
@@ -78,6 +78,17 @@ export default {
|
|
|
78
78
|
'^[a-z][a-zA-Z0-9]*$'
|
|
79
79
|
]
|
|
80
80
|
}
|
|
81
|
+
],
|
|
82
|
+
'trigen/named-export-order': [
|
|
83
|
+
'error',
|
|
84
|
+
{
|
|
85
|
+
typeExports: 'first',
|
|
86
|
+
patterns: [
|
|
87
|
+
'^[A-Z][A-Z0-9_]*$',
|
|
88
|
+
'^[A-Z][a-zA-Z0-9]*$',
|
|
89
|
+
'^[a-z][a-zA-Z0-9]*$'
|
|
90
|
+
]
|
|
91
|
+
}
|
|
81
92
|
]
|
|
82
93
|
}
|
|
83
94
|
}
|
package/src/test.js
CHANGED
|
@@ -23,6 +23,7 @@ export default {
|
|
|
23
23
|
'typescript/no-unsafe-call': 'off',
|
|
24
24
|
'typescript/no-unsafe-argument': 'off',
|
|
25
25
|
'typescript/no-explicit-any': 'off',
|
|
26
|
+
'typescript/await-thenable': 'off',
|
|
26
27
|
'typescript/no-floating-promises': 'off',
|
|
27
28
|
'trigen/import-order': 'off',
|
|
28
29
|
'eslint/prefer-destructuring': 'off',
|