eslint-plugin-kirklin 0.5.6 → 0.9.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 +1 -1
- package/README.md +27 -0
- package/dist/index.cjs +532 -52
- package/dist/index.d.cts +55 -7
- package/dist/index.d.mts +55 -7
- package/dist/index.d.ts +55 -7
- package/dist/index.mjs +532 -52
- package/package.json +82 -25
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
3
|
+
Copyright (c) 2021-PRESENT Anthony Fu <https://github.com/kirklin>
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# eslint-plugin-kirklin
|
|
2
|
+
|
|
3
|
+
[![npm version][npm-version-src]][npm-version-href]
|
|
4
|
+
[![npm downloads][npm-downloads-src]][npm-downloads-href]
|
|
5
|
+
|
|
6
|
+
Anthony extended ESLint rules. For [kirklin/eslint-config](https://github.com/kirklin/eslint-config).
|
|
7
|
+
|
|
8
|
+
[Rules List](./src/rules)
|
|
9
|
+
|
|
10
|
+
## Sponsors
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
<a href="https://cdn.jsdelivr.net/gh/kirklin/static/sponsors.svg">
|
|
14
|
+
<img src='https://cdn.jsdelivr.net/gh/kirklin/static/sponsors.svg'/>
|
|
15
|
+
</a>
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
## License
|
|
19
|
+
|
|
20
|
+
[MIT](./LICENSE) License © 2023-PRESENT [Anthony Fu](https://github.com/kirklin)
|
|
21
|
+
|
|
22
|
+
<!-- Badges -->
|
|
23
|
+
|
|
24
|
+
[npm-version-src]: https://img.shields.io/npm/v/eslint-plugin-kirklin?style=flat&colorA=080f12&colorB=1fa669
|
|
25
|
+
[npm-version-href]: https://npmjs.com/package/eslint-plugin-kirklin
|
|
26
|
+
[npm-downloads-src]: https://img.shields.io/npm/dm/eslint-plugin-kirklin?style=flat&colorA=080f12&colorB=1fa669
|
|
27
|
+
[npm-downloads-href]: https://npmjs.com/package/eslint-plugin-kirklin
|
package/dist/index.cjs
CHANGED
|
@@ -1,21 +1,66 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const version = "0.9.0";
|
|
4
4
|
|
|
5
|
-
const
|
|
6
|
-
|
|
5
|
+
const hasDocs = [
|
|
6
|
+
"consistent-list-newline",
|
|
7
|
+
"if-newline",
|
|
8
|
+
"import-dedupe",
|
|
9
|
+
"top-level-function"
|
|
10
|
+
];
|
|
11
|
+
const blobUrl = "https://github.com/kirklin/eslint-plugin-kirklin/blob/main/src/rules/";
|
|
12
|
+
function RuleCreator(urlCreator) {
|
|
13
|
+
return function createNamedRule({
|
|
14
|
+
name,
|
|
15
|
+
meta,
|
|
16
|
+
...rule
|
|
17
|
+
}) {
|
|
18
|
+
return createRule({
|
|
19
|
+
meta: {
|
|
20
|
+
...meta,
|
|
21
|
+
docs: {
|
|
22
|
+
...meta.docs,
|
|
23
|
+
url: urlCreator(name)
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
...rule
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function createRule({
|
|
31
|
+
create,
|
|
32
|
+
defaultOptions,
|
|
33
|
+
meta
|
|
34
|
+
}) {
|
|
35
|
+
return {
|
|
36
|
+
create: (context) => {
|
|
37
|
+
const optionsWithDefault = context.options.map((options, index) => {
|
|
38
|
+
return {
|
|
39
|
+
...defaultOptions[index] || {},
|
|
40
|
+
...options || {}
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
return create(context, optionsWithDefault);
|
|
44
|
+
},
|
|
45
|
+
defaultOptions,
|
|
46
|
+
meta
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
const createEslintRule = RuleCreator(
|
|
50
|
+
(ruleName) => hasDocs.includes(ruleName) ? `${blobUrl}${ruleName}.md` : `${blobUrl}${ruleName}.test.ts`
|
|
7
51
|
);
|
|
8
52
|
|
|
9
|
-
const RULE_NAME$
|
|
53
|
+
const RULE_NAME$a = "generic-spacing";
|
|
54
|
+
const PRESERVE_PREFIX_SPACE_BEFORE_GENERIC = /* @__PURE__ */ new Set(["TSCallSignatureDeclaration", "ArrowFunctionExpression", "TSFunctionType", "FunctionExpression"]);
|
|
10
55
|
const genericSpacing = createEslintRule({
|
|
11
|
-
name: RULE_NAME$
|
|
56
|
+
name: RULE_NAME$a,
|
|
12
57
|
meta: {
|
|
13
|
-
type: "
|
|
58
|
+
type: "layout",
|
|
14
59
|
docs: {
|
|
15
60
|
description: "Spaces around generic type parameters",
|
|
16
|
-
recommended: "
|
|
61
|
+
recommended: "stylistic"
|
|
17
62
|
},
|
|
18
|
-
fixable: "
|
|
63
|
+
fixable: "whitespace",
|
|
19
64
|
schema: [],
|
|
20
65
|
messages: {
|
|
21
66
|
genericSpacingMismatch: "Generic spaces mismatch"
|
|
@@ -26,7 +71,7 @@ const genericSpacing = createEslintRule({
|
|
|
26
71
|
const sourceCode = context.getSourceCode();
|
|
27
72
|
return {
|
|
28
73
|
TSTypeParameterDeclaration: (node) => {
|
|
29
|
-
if (!
|
|
74
|
+
if (!PRESERVE_PREFIX_SPACE_BEFORE_GENERIC.has(node.parent.type)) {
|
|
30
75
|
const pre = sourceCode.text.slice(0, node.range[0]);
|
|
31
76
|
const preSpace = pre.match(/(\s+)$/)?.[0];
|
|
32
77
|
if (preSpace && preSpace.length) {
|
|
@@ -46,7 +91,7 @@ const genericSpacing = createEslintRule({
|
|
|
46
91
|
const from = prev.range[1];
|
|
47
92
|
const to = current.range[0];
|
|
48
93
|
const span = sourceCode.text.slice(from, to);
|
|
49
|
-
if (span !== ", " && !span.match(/,\n/)) {
|
|
94
|
+
if (span !== ", " && !span.match(/,\s*\r?\n/)) {
|
|
50
95
|
context.report({
|
|
51
96
|
*fix(fixer) {
|
|
52
97
|
yield fixer.replaceTextRange([from, to], ", ");
|
|
@@ -87,16 +132,16 @@ const genericSpacing = createEslintRule({
|
|
|
87
132
|
}
|
|
88
133
|
});
|
|
89
134
|
|
|
90
|
-
const RULE_NAME$
|
|
135
|
+
const RULE_NAME$9 = "if-newline";
|
|
91
136
|
const ifNewline = createEslintRule({
|
|
92
|
-
name: RULE_NAME$
|
|
137
|
+
name: RULE_NAME$9,
|
|
93
138
|
meta: {
|
|
94
|
-
type: "
|
|
139
|
+
type: "layout",
|
|
95
140
|
docs: {
|
|
96
141
|
description: "Newline after if",
|
|
97
|
-
recommended: "
|
|
142
|
+
recommended: "stylistic"
|
|
98
143
|
},
|
|
99
|
-
fixable: "
|
|
144
|
+
fixable: "whitespace",
|
|
100
145
|
schema: [],
|
|
101
146
|
messages: {
|
|
102
147
|
missingIfNewline: "Expect newline after if"
|
|
@@ -130,14 +175,14 @@ const ifNewline = createEslintRule({
|
|
|
130
175
|
}
|
|
131
176
|
});
|
|
132
177
|
|
|
133
|
-
const RULE_NAME$
|
|
178
|
+
const RULE_NAME$8 = "import-dedupe";
|
|
134
179
|
const importDedupe = createEslintRule({
|
|
135
|
-
name: RULE_NAME$
|
|
180
|
+
name: RULE_NAME$8,
|
|
136
181
|
meta: {
|
|
137
182
|
type: "problem",
|
|
138
183
|
docs: {
|
|
139
184
|
description: "Fix duplication in imports",
|
|
140
|
-
recommended: "
|
|
185
|
+
recommended: "strict"
|
|
141
186
|
},
|
|
142
187
|
fixable: "code",
|
|
143
188
|
schema: [],
|
|
@@ -180,41 +225,13 @@ const importDedupe = createEslintRule({
|
|
|
180
225
|
}
|
|
181
226
|
});
|
|
182
227
|
|
|
183
|
-
const RULE_NAME$
|
|
184
|
-
const noConstEnum = createEslintRule({
|
|
185
|
-
name: RULE_NAME$1,
|
|
186
|
-
meta: {
|
|
187
|
-
type: "problem",
|
|
188
|
-
docs: {
|
|
189
|
-
description: "Disallow using `const enum` expression",
|
|
190
|
-
recommended: "error"
|
|
191
|
-
},
|
|
192
|
-
schema: [],
|
|
193
|
-
messages: {
|
|
194
|
-
noConstEnum: "Do not use `const enum` expression"
|
|
195
|
-
}
|
|
196
|
-
},
|
|
197
|
-
defaultOptions: [],
|
|
198
|
-
create: (context) => ({
|
|
199
|
-
TSEnumDeclaration(node) {
|
|
200
|
-
if (node.const) {
|
|
201
|
-
context.report({
|
|
202
|
-
node,
|
|
203
|
-
messageId: "noConstEnum"
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
})
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
const RULE_NAME = "prefer-inline-type-import";
|
|
228
|
+
const RULE_NAME$7 = "prefer-inline-type-import";
|
|
211
229
|
const preferInlineTypeImport = createEslintRule({
|
|
212
|
-
name: RULE_NAME,
|
|
230
|
+
name: RULE_NAME$7,
|
|
213
231
|
meta: {
|
|
214
232
|
type: "suggestion",
|
|
215
233
|
docs: {
|
|
216
|
-
description: "Inline type import"
|
|
217
|
-
recommended: "error"
|
|
234
|
+
description: "Inline type import"
|
|
218
235
|
},
|
|
219
236
|
fixable: "code",
|
|
220
237
|
schema: [],
|
|
@@ -249,7 +266,13 @@ const preferInlineTypeImport = createEslintRule({
|
|
|
249
266
|
});
|
|
250
267
|
function* removeTypeSpecifier(fixer, sourceCode, node) {
|
|
251
268
|
const importKeyword = sourceCode.getFirstToken(node);
|
|
269
|
+
if (!importKeyword) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
252
272
|
const typeIdentifier = sourceCode.getTokenAfter(importKeyword);
|
|
273
|
+
if (!typeIdentifier) {
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
253
276
|
yield fixer.remove(typeIdentifier);
|
|
254
277
|
if (importKeyword.loc.end.column + 1 === typeIdentifier.loc.start.column) {
|
|
255
278
|
yield fixer.removeRange([
|
|
@@ -259,14 +282,471 @@ function* removeTypeSpecifier(fixer, sourceCode, node) {
|
|
|
259
282
|
}
|
|
260
283
|
}
|
|
261
284
|
|
|
262
|
-
const
|
|
285
|
+
const RULE_NAME$6 = "top-level-function";
|
|
286
|
+
const topLevelFunction = createEslintRule({
|
|
287
|
+
name: RULE_NAME$6,
|
|
288
|
+
meta: {
|
|
289
|
+
type: "problem",
|
|
290
|
+
docs: {
|
|
291
|
+
description: "Enforce top-level functions to be declared with function keyword",
|
|
292
|
+
recommended: "stylistic"
|
|
293
|
+
},
|
|
294
|
+
fixable: "code",
|
|
295
|
+
schema: [],
|
|
296
|
+
messages: {
|
|
297
|
+
topLevelFunctionDeclaration: "Top-level functions should be declared with function keyword"
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
defaultOptions: [],
|
|
301
|
+
create: (context) => {
|
|
302
|
+
return {
|
|
303
|
+
VariableDeclaration(node) {
|
|
304
|
+
if (node.parent.type !== "Program" && node.parent.type !== "ExportNamedDeclaration") {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
if (node.declarations.length !== 1) {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
if (node.kind !== "const") {
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
if (node.declare) {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
const declaration = node.declarations[0];
|
|
317
|
+
if (declaration.init?.type !== "ArrowFunctionExpression") {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
if (declaration.id?.type !== "Identifier") {
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
if (declaration.id.typeAnnotation) {
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (declaration.init.body.type !== "BlockStatement" && declaration.id?.loc.start.line === declaration.init?.body.loc.end.line) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
const arrowFn = declaration.init;
|
|
330
|
+
const body = declaration.init.body;
|
|
331
|
+
const id = declaration.id;
|
|
332
|
+
context.report({
|
|
333
|
+
node,
|
|
334
|
+
loc: {
|
|
335
|
+
start: id.loc.start,
|
|
336
|
+
end: body.loc.start
|
|
337
|
+
},
|
|
338
|
+
messageId: "topLevelFunctionDeclaration",
|
|
339
|
+
fix(fixer) {
|
|
340
|
+
const code = context.getSourceCode().text;
|
|
341
|
+
const textName = code.slice(id.range[0], id.range[1]);
|
|
342
|
+
const textArgs = arrowFn.params.length ? code.slice(arrowFn.params[0].range[0], arrowFn.params[arrowFn.params.length - 1].range[1]) : "";
|
|
343
|
+
const textBody = body.type === "BlockStatement" ? code.slice(body.range[0], body.range[1]) : `{
|
|
344
|
+
return ${code.slice(body.range[0], body.range[1])}
|
|
345
|
+
}`;
|
|
346
|
+
const textGeneric = arrowFn.typeParameters ? code.slice(arrowFn.typeParameters.range[0], arrowFn.typeParameters.range[1]) : "";
|
|
347
|
+
const textTypeReturn = arrowFn.returnType ? code.slice(arrowFn.returnType.range[0], arrowFn.returnType.range[1]) : "";
|
|
348
|
+
const textAsync = arrowFn.async ? "async " : "";
|
|
349
|
+
const final = `${textAsync}function ${textName} ${textGeneric}(${textArgs})${textTypeReturn} ${textBody}`;
|
|
350
|
+
return fixer.replaceTextRange([node.range[0], node.range[1]], final);
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
const RULE_NAME$5 = "no-import-node-modules-by-path";
|
|
359
|
+
const noImportNodeModulesByPath = createEslintRule({
|
|
360
|
+
name: RULE_NAME$5,
|
|
361
|
+
meta: {
|
|
362
|
+
type: "problem",
|
|
363
|
+
docs: {
|
|
364
|
+
description: "Prevent importing modules in `node_modules` folder by relative or absolute path",
|
|
365
|
+
recommended: "recommended"
|
|
366
|
+
},
|
|
367
|
+
schema: [],
|
|
368
|
+
messages: {
|
|
369
|
+
noImportNodeModulesByPath: "Do not import modules in `node_modules` folder by path"
|
|
370
|
+
}
|
|
371
|
+
},
|
|
372
|
+
defaultOptions: [],
|
|
373
|
+
create: (context) => {
|
|
374
|
+
return {
|
|
375
|
+
"ImportDeclaration": (node) => {
|
|
376
|
+
if (node.source.value.includes("/node_modules/")) {
|
|
377
|
+
context.report({
|
|
378
|
+
node,
|
|
379
|
+
messageId: "noImportNodeModulesByPath"
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
},
|
|
383
|
+
'CallExpression[callee.name="require"]': (node) => {
|
|
384
|
+
const value = node.arguments[0]?.value;
|
|
385
|
+
if (typeof value === "string" && value.includes("/node_modules/")) {
|
|
386
|
+
context.report({
|
|
387
|
+
node,
|
|
388
|
+
messageId: "noImportNodeModulesByPath"
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
const RULE_NAME$4 = "no-ts-export-equal";
|
|
397
|
+
const noTsExportEqual = createEslintRule({
|
|
398
|
+
name: RULE_NAME$4,
|
|
399
|
+
meta: {
|
|
400
|
+
type: "problem",
|
|
401
|
+
docs: {
|
|
402
|
+
description: "Do not use `exports =`",
|
|
403
|
+
recommended: "recommended"
|
|
404
|
+
},
|
|
405
|
+
schema: [],
|
|
406
|
+
messages: {
|
|
407
|
+
noTsExportEqual: "Use ESM `export default` instead"
|
|
408
|
+
}
|
|
409
|
+
},
|
|
410
|
+
defaultOptions: [],
|
|
411
|
+
create: (context) => {
|
|
412
|
+
const extension = context.getFilename().split(".").pop();
|
|
413
|
+
if (!extension) {
|
|
414
|
+
return {};
|
|
415
|
+
}
|
|
416
|
+
if (!["ts", "tsx", "mts", "cts"].includes(extension)) {
|
|
417
|
+
return {};
|
|
418
|
+
}
|
|
419
|
+
return {
|
|
420
|
+
TSExportAssignment(node) {
|
|
421
|
+
context.report({
|
|
422
|
+
node,
|
|
423
|
+
messageId: "noTsExportEqual"
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
const RULE_NAME$3 = "no-cjs-exports";
|
|
431
|
+
const noCjsExports = createEslintRule({
|
|
432
|
+
name: RULE_NAME$3,
|
|
433
|
+
meta: {
|
|
434
|
+
type: "problem",
|
|
435
|
+
docs: {
|
|
436
|
+
description: "Do not use CJS exports"
|
|
437
|
+
},
|
|
438
|
+
schema: [],
|
|
439
|
+
messages: {
|
|
440
|
+
noCjsExports: "Use ESM export instead"
|
|
441
|
+
}
|
|
442
|
+
},
|
|
443
|
+
defaultOptions: [],
|
|
444
|
+
create: (context) => {
|
|
445
|
+
const extension = context.getFilename().split(".").pop();
|
|
446
|
+
if (!extension) {
|
|
447
|
+
return {};
|
|
448
|
+
}
|
|
449
|
+
if (!["ts", "tsx", "mts", "cts"].includes(extension)) {
|
|
450
|
+
return {};
|
|
451
|
+
}
|
|
452
|
+
return {
|
|
453
|
+
'MemberExpression[object.name="exports"]': function(node) {
|
|
454
|
+
context.report({
|
|
455
|
+
node,
|
|
456
|
+
messageId: "noCjsExports"
|
|
457
|
+
});
|
|
458
|
+
},
|
|
459
|
+
'MemberExpression[object.name="module"][property.name="exports"]': function(node) {
|
|
460
|
+
context.report({
|
|
461
|
+
node,
|
|
462
|
+
messageId: "noCjsExports"
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
const RULE_NAME$2 = "no-const-enum";
|
|
470
|
+
const noConstEnum = createEslintRule({
|
|
471
|
+
name: RULE_NAME$2,
|
|
472
|
+
meta: {
|
|
473
|
+
type: "problem",
|
|
474
|
+
docs: {
|
|
475
|
+
description: "Deprecated. Use `'no-restricted-syntax': ['error', 'TSEnumDeclaration[const=true]']` instead."
|
|
476
|
+
},
|
|
477
|
+
schema: [],
|
|
478
|
+
messages: {
|
|
479
|
+
noConstEnum: "Do not use `const enum` expression"
|
|
480
|
+
},
|
|
481
|
+
deprecated: true
|
|
482
|
+
},
|
|
483
|
+
defaultOptions: [],
|
|
484
|
+
create: (context) => {
|
|
485
|
+
return {
|
|
486
|
+
TSEnumDeclaration: (node) => {
|
|
487
|
+
if (node.const) {
|
|
488
|
+
context.report({
|
|
489
|
+
node,
|
|
490
|
+
messageId: "noConstEnum"
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
const RULE_NAME$1 = "named-tuple-spacing";
|
|
499
|
+
const RE = /^([\w_$]+)(\s*)(\?\s*)?:(\s*)(.*)$/;
|
|
500
|
+
const namedTupleSpacing = createEslintRule({
|
|
501
|
+
name: RULE_NAME$1,
|
|
502
|
+
meta: {
|
|
503
|
+
type: "layout",
|
|
504
|
+
docs: {
|
|
505
|
+
description: "Expect space before type declaration in named tuple",
|
|
506
|
+
recommended: "stylistic"
|
|
507
|
+
},
|
|
508
|
+
fixable: "whitespace",
|
|
509
|
+
schema: [],
|
|
510
|
+
messages: {
|
|
511
|
+
expectedSpaceAfter: "Expected a space after the ':'.",
|
|
512
|
+
unexpectedSpaceBetween: "Unexpected space between '?' and the ':'.",
|
|
513
|
+
unexpectedSpaceBefore: "Unexpected space before the ':'."
|
|
514
|
+
}
|
|
515
|
+
},
|
|
516
|
+
defaultOptions: [],
|
|
517
|
+
create: (context) => {
|
|
518
|
+
const sourceCode = context.getSourceCode();
|
|
519
|
+
return {
|
|
520
|
+
TSNamedTupleMember: (node) => {
|
|
521
|
+
const code = sourceCode.text.slice(node.range[0], node.range[1]);
|
|
522
|
+
const match = code.match(RE);
|
|
523
|
+
if (!match) {
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
const labelName = node.label.name;
|
|
527
|
+
const spaceBeforeColon = match[2];
|
|
528
|
+
const optionalMark = match[3];
|
|
529
|
+
const spacesAfterColon = match[4];
|
|
530
|
+
const elementType = match[5];
|
|
531
|
+
function getReplaceValue() {
|
|
532
|
+
let ret = labelName;
|
|
533
|
+
if (node.optional) {
|
|
534
|
+
ret += "?";
|
|
535
|
+
}
|
|
536
|
+
ret += ": ";
|
|
537
|
+
ret += elementType;
|
|
538
|
+
return ret;
|
|
539
|
+
}
|
|
540
|
+
if (optionalMark?.length > 1) {
|
|
541
|
+
context.report({
|
|
542
|
+
node,
|
|
543
|
+
messageId: "unexpectedSpaceBetween",
|
|
544
|
+
*fix(fixer) {
|
|
545
|
+
yield fixer.replaceTextRange(node.range, code.replace(RE, getReplaceValue()));
|
|
546
|
+
}
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
if (spaceBeforeColon?.length) {
|
|
550
|
+
context.report({
|
|
551
|
+
node,
|
|
552
|
+
messageId: "unexpectedSpaceBefore",
|
|
553
|
+
*fix(fixer) {
|
|
554
|
+
yield fixer.replaceTextRange(node.range, code.replace(RE, getReplaceValue()));
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
if (spacesAfterColon != null && spacesAfterColon.length !== 1) {
|
|
559
|
+
context.report({
|
|
560
|
+
node,
|
|
561
|
+
messageId: "expectedSpaceAfter",
|
|
562
|
+
*fix(fixer) {
|
|
563
|
+
yield fixer.replaceTextRange(node.range, code.replace(RE, getReplaceValue()));
|
|
564
|
+
}
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
const RULE_NAME = "consistent-list-newline";
|
|
573
|
+
const consistentListNewline = createEslintRule({
|
|
574
|
+
name: RULE_NAME,
|
|
575
|
+
meta: {
|
|
576
|
+
type: "layout",
|
|
577
|
+
docs: {
|
|
578
|
+
description: "Having line breaks styles to object, array and named imports",
|
|
579
|
+
recommended: "stylistic"
|
|
580
|
+
},
|
|
581
|
+
fixable: "whitespace",
|
|
582
|
+
schema: [],
|
|
583
|
+
messages: {
|
|
584
|
+
shouldWrap: "Should have line breaks between items",
|
|
585
|
+
shouldNotWrap: "Should not have line breaks between items"
|
|
586
|
+
}
|
|
587
|
+
},
|
|
588
|
+
defaultOptions: [{}],
|
|
589
|
+
create: (context, [options = {}] = [{}]) => {
|
|
590
|
+
function removeLines(fixer, start, end) {
|
|
591
|
+
const range = [start, end];
|
|
592
|
+
const code = context.getSourceCode().text.slice(...range);
|
|
593
|
+
return fixer.replaceTextRange(range, code.replace(/(\r\n|\n)/g, ""));
|
|
594
|
+
}
|
|
595
|
+
function check(node, children, prevNode, nextNode) {
|
|
596
|
+
const items = children.filter(Boolean);
|
|
597
|
+
if (items.length === 0) {
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
const startLine = prevNode ? prevNode.loc.end.line : node.loc.start.line;
|
|
601
|
+
let mode = null;
|
|
602
|
+
let lastLine = startLine;
|
|
603
|
+
items.forEach((item, idx) => {
|
|
604
|
+
if (mode == null) {
|
|
605
|
+
mode = item.loc.start.line === lastLine ? "inline" : "newline";
|
|
606
|
+
lastLine = item.loc.end.line;
|
|
607
|
+
return;
|
|
608
|
+
}
|
|
609
|
+
const currentStart = item.loc.start.line;
|
|
610
|
+
if (mode === "newline" && currentStart === lastLine) {
|
|
611
|
+
context.report({
|
|
612
|
+
node: item,
|
|
613
|
+
messageId: "shouldWrap",
|
|
614
|
+
*fix(fixer) {
|
|
615
|
+
yield fixer.insertTextBefore(item, "\n");
|
|
616
|
+
}
|
|
617
|
+
});
|
|
618
|
+
} else if (mode === "inline" && currentStart !== lastLine) {
|
|
619
|
+
const lastItem2 = items[idx - 1];
|
|
620
|
+
context.report({
|
|
621
|
+
node: item,
|
|
622
|
+
messageId: "shouldNotWrap",
|
|
623
|
+
*fix(fixer) {
|
|
624
|
+
yield removeLines(fixer, lastItem2.range[1], item.range[0]);
|
|
625
|
+
}
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
lastLine = item.loc.end.line;
|
|
629
|
+
});
|
|
630
|
+
const endLoc = nextNode?.loc.start ?? node.loc.end;
|
|
631
|
+
const endRange = nextNode?.range[0] ? nextNode?.range[0] - 1 : node.range[1];
|
|
632
|
+
const lastItem = items[items.length - 1];
|
|
633
|
+
if (mode === "newline" && endLoc.line === lastLine) {
|
|
634
|
+
context.report({
|
|
635
|
+
node: lastItem,
|
|
636
|
+
messageId: "shouldWrap",
|
|
637
|
+
*fix(fixer) {
|
|
638
|
+
yield fixer.insertTextAfter(lastItem, "\n");
|
|
639
|
+
}
|
|
640
|
+
});
|
|
641
|
+
} else if (mode === "inline" && endLoc.line !== lastLine) {
|
|
642
|
+
if (items.length === 1 && items[0].loc.start.line !== items[1]?.loc.start.line) {
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
context.report({
|
|
646
|
+
node: lastItem,
|
|
647
|
+
messageId: "shouldNotWrap",
|
|
648
|
+
*fix(fixer) {
|
|
649
|
+
yield removeLines(fixer, lastItem.range[1], endRange);
|
|
650
|
+
}
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
const listenser = {
|
|
655
|
+
ObjectExpression: (node) => {
|
|
656
|
+
check(node, node.properties);
|
|
657
|
+
},
|
|
658
|
+
ArrayExpression: (node) => {
|
|
659
|
+
check(node, node.elements);
|
|
660
|
+
},
|
|
661
|
+
ImportDeclaration: (node) => {
|
|
662
|
+
check(node, node.specifiers);
|
|
663
|
+
},
|
|
664
|
+
ExportNamedDeclaration: (node) => {
|
|
665
|
+
check(node, node.specifiers);
|
|
666
|
+
},
|
|
667
|
+
FunctionDeclaration: (node) => {
|
|
668
|
+
check(
|
|
669
|
+
node,
|
|
670
|
+
node.params,
|
|
671
|
+
node.typeParameters || void 0,
|
|
672
|
+
node.returnType || node.body
|
|
673
|
+
);
|
|
674
|
+
},
|
|
675
|
+
FunctionExpression: (node) => {
|
|
676
|
+
check(
|
|
677
|
+
node,
|
|
678
|
+
node.params,
|
|
679
|
+
node.typeParameters || void 0,
|
|
680
|
+
node.returnType || node.body
|
|
681
|
+
);
|
|
682
|
+
},
|
|
683
|
+
ArrowFunctionExpression: (node) => {
|
|
684
|
+
check(
|
|
685
|
+
node,
|
|
686
|
+
node.params,
|
|
687
|
+
node.typeParameters || void 0,
|
|
688
|
+
node.returnType || node.body
|
|
689
|
+
);
|
|
690
|
+
},
|
|
691
|
+
CallExpression: (node) => {
|
|
692
|
+
const startNode = node.typeArguments?.params.length ? node.typeArguments.params[node.typeArguments.params.length - 1] : node.callee.type === "MemberExpression" ? node.callee.property : node.callee;
|
|
693
|
+
check(node, node.arguments, startNode);
|
|
694
|
+
},
|
|
695
|
+
TSInterfaceDeclaration: (node) => {
|
|
696
|
+
check(node, node.body.body);
|
|
697
|
+
},
|
|
698
|
+
TSTypeLiteral: (node) => {
|
|
699
|
+
check(node, node.members);
|
|
700
|
+
},
|
|
701
|
+
TSTupleType: (node) => {
|
|
702
|
+
check(node, node.elementTypes);
|
|
703
|
+
},
|
|
704
|
+
NewExpression: (node) => {
|
|
705
|
+
check(node, node.arguments, node.callee);
|
|
706
|
+
},
|
|
707
|
+
TSTypeParameterDeclaration(node) {
|
|
708
|
+
check(node, node.params);
|
|
709
|
+
},
|
|
710
|
+
TSTypeParameterInstantiation(node) {
|
|
711
|
+
check(node, node.params);
|
|
712
|
+
},
|
|
713
|
+
ObjectPattern(node) {
|
|
714
|
+
check(node, node.properties, void 0, node.typeAnnotation);
|
|
715
|
+
},
|
|
716
|
+
ArrayPattern(node) {
|
|
717
|
+
check(node, node.elements);
|
|
718
|
+
}
|
|
719
|
+
};
|
|
720
|
+
Object.keys(options).forEach((key) => {
|
|
721
|
+
if (options[key] === false) {
|
|
722
|
+
delete listenser[key];
|
|
723
|
+
}
|
|
724
|
+
});
|
|
725
|
+
return listenser;
|
|
726
|
+
}
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
const plugin = {
|
|
730
|
+
meta: {
|
|
731
|
+
name: "kirklin",
|
|
732
|
+
version
|
|
733
|
+
},
|
|
263
734
|
rules: {
|
|
735
|
+
"consistent-list-newline": consistentListNewline,
|
|
736
|
+
"generic-spacing": genericSpacing,
|
|
264
737
|
"if-newline": ifNewline,
|
|
265
738
|
"import-dedupe": importDedupe,
|
|
739
|
+
"named-tuple-spacing": namedTupleSpacing,
|
|
740
|
+
"no-cjs-exports": noCjsExports,
|
|
741
|
+
"no-import-node-modules-by-path": noImportNodeModulesByPath,
|
|
742
|
+
"no-ts-export-equal": noTsExportEqual,
|
|
266
743
|
"prefer-inline-type-import": preferInlineTypeImport,
|
|
267
|
-
"
|
|
744
|
+
"top-level-function": topLevelFunction,
|
|
745
|
+
/**
|
|
746
|
+
* @deprecated Use `'no-restricted-syntax': ['error', 'TSEnumDeclaration[const=true]']` instead.
|
|
747
|
+
*/
|
|
268
748
|
"no-const-enum": noConstEnum
|
|
269
749
|
}
|
|
270
750
|
};
|
|
271
751
|
|
|
272
|
-
module.exports =
|
|
752
|
+
module.exports = plugin;
|