eslint-plugin-flawless 0.1.11 → 1.0.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/README.md +18 -13
- package/dist/index.d.mts +82 -4
- package/dist/index.mjs +1 -1
- package/dist/oxlint.mjs +1 -1
- package/dist/{plugin-BvQt8gSt.mjs → plugin-DFLOyhkl.mjs} +1497 -32
- package/dist/rules/arrow-return-style/worker.d.mts +25 -0
- package/dist/rules/arrow-return-style/worker.mjs +90 -0
- package/package.json +8 -1
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//#region src/rules/arrow-return-style/worker.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* One entry of the batched request sent by the rule: format `code` with oxfmt
|
|
4
|
+
* and locate the `arrowIndex`-th arrow function (in source order) in the
|
|
5
|
+
* formatted output. Requests are batched per linted file so a file pays the
|
|
6
|
+
* worker round-trip cost once, not once per arrow.
|
|
7
|
+
*/
|
|
8
|
+
interface FormatRequest {
|
|
9
|
+
arrowIndex: number;
|
|
10
|
+
code: string;
|
|
11
|
+
printWidth: number;
|
|
12
|
+
tabWidth: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Response: whether the arrow (params through body) occupies a single line in
|
|
16
|
+
* the formatted output, and that line's text for width measurement. `lineText`
|
|
17
|
+
* is `null` when formatting failed or the arrow could not be located, which
|
|
18
|
+
* callers must treat as "no verdict".
|
|
19
|
+
*/
|
|
20
|
+
interface FormatResponse {
|
|
21
|
+
lineText: null | string;
|
|
22
|
+
singleLine: boolean;
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { FormatRequest, FormatResponse };
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { runAsWorker } from "synckit";
|
|
2
|
+
//#region src/rules/arrow-return-style/worker.ts
|
|
3
|
+
function isNodeLike(value) {
|
|
4
|
+
return typeof value === "object" && value !== null && typeof value.type === "string" && typeof value.start === "number" && typeof value.end === "number";
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Collects all arrow function nodes in the tree, ordered by source position.
|
|
8
|
+
*
|
|
9
|
+
* @param root - The parsed AST to search.
|
|
10
|
+
* @returns All arrow function nodes, sorted by start offset.
|
|
11
|
+
*/
|
|
12
|
+
function collectArrows(root) {
|
|
13
|
+
const arrows = [];
|
|
14
|
+
const stack = [root];
|
|
15
|
+
while (stack.length > 0) {
|
|
16
|
+
const current = stack.pop();
|
|
17
|
+
if (typeof current !== "object" || current === null) continue;
|
|
18
|
+
if (isNodeLike(current) && current.type === "ArrowFunctionExpression") arrows.push(current);
|
|
19
|
+
for (const value of Object.values(current)) if (Array.isArray(value)) stack.push(...value);
|
|
20
|
+
else if (typeof value === "object" && value !== null) stack.push(value);
|
|
21
|
+
}
|
|
22
|
+
return arrows.sort((a, b) => a.start - b.start);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Start offsets of every line in `code`, for offset-to-line lookups.
|
|
26
|
+
*
|
|
27
|
+
* @param code - The source text.
|
|
28
|
+
* @returns Ascending offsets at which each line begins.
|
|
29
|
+
*/
|
|
30
|
+
function lineStartsOf(code) {
|
|
31
|
+
const starts = [0];
|
|
32
|
+
for (let index = 0; index < code.length; index += 1) if (code.charAt(index) === "\n") starts.push(index + 1);
|
|
33
|
+
return starts;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Index (0-based) of the line containing `offset`.
|
|
37
|
+
*
|
|
38
|
+
* @param starts - Line start offsets from {@link lineStartsOf}.
|
|
39
|
+
* @param offset - The source offset to locate.
|
|
40
|
+
* @returns The containing line's index.
|
|
41
|
+
*/
|
|
42
|
+
function lineIndexOf(starts, offset) {
|
|
43
|
+
let low = 0;
|
|
44
|
+
let high = starts.length - 1;
|
|
45
|
+
while (low < high) {
|
|
46
|
+
const mid = Math.ceil((low + high) / 2);
|
|
47
|
+
if ((starts[mid] ?? 0) <= offset) low = mid;
|
|
48
|
+
else high = mid - 1;
|
|
49
|
+
}
|
|
50
|
+
return low;
|
|
51
|
+
}
|
|
52
|
+
async function formatOne(request) {
|
|
53
|
+
const { format } = await import("oxfmt");
|
|
54
|
+
const { parseSync } = await import("oxc-parser");
|
|
55
|
+
const result = await format("snippet.tsx", request.code, {
|
|
56
|
+
endOfLine: "lf",
|
|
57
|
+
printWidth: request.printWidth,
|
|
58
|
+
semi: true,
|
|
59
|
+
tabWidth: request.tabWidth,
|
|
60
|
+
useTabs: true
|
|
61
|
+
});
|
|
62
|
+
if (result.errors.length > 0) return {
|
|
63
|
+
lineText: null,
|
|
64
|
+
singleLine: false
|
|
65
|
+
};
|
|
66
|
+
const parsed = parseSync("snippet.tsx", result.code);
|
|
67
|
+
if (parsed.errors.length > 0) return {
|
|
68
|
+
lineText: null,
|
|
69
|
+
singleLine: false
|
|
70
|
+
};
|
|
71
|
+
const arrow = collectArrows(parsed.program)[request.arrowIndex];
|
|
72
|
+
if (arrow === void 0) return {
|
|
73
|
+
lineText: null,
|
|
74
|
+
singleLine: false
|
|
75
|
+
};
|
|
76
|
+
const starts = lineStartsOf(result.code);
|
|
77
|
+
const startLine = lineIndexOf(starts, arrow.start);
|
|
78
|
+
const lineEnd = starts[startLine + 1] ?? result.code.length + 1;
|
|
79
|
+
return {
|
|
80
|
+
lineText: result.code.slice(starts[startLine], lineEnd - 1),
|
|
81
|
+
singleLine: startLine === lineIndexOf(starts, arrow.end)
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
runAsWorker(async (requests) => {
|
|
85
|
+
const responses = [];
|
|
86
|
+
for (const request of requests) responses.push(await formatOne(request));
|
|
87
|
+
return responses;
|
|
88
|
+
});
|
|
89
|
+
//#endregion
|
|
90
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-flawless",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Your ESLint plugin description",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"eslint",
|
|
@@ -40,6 +40,10 @@
|
|
|
40
40
|
"@typescript-eslint/scope-manager": "8.62.1",
|
|
41
41
|
"@typescript-eslint/type-utils": "8.62.1",
|
|
42
42
|
"@typescript-eslint/utils": "8.62.1",
|
|
43
|
+
"jsonc-eslint-parser": "3.1.0",
|
|
44
|
+
"oxc-parser": "0.112.0",
|
|
45
|
+
"oxfmt": "0.59.0",
|
|
46
|
+
"synckit": "0.11.13",
|
|
43
47
|
"toml-eslint-parser": "1.0.3"
|
|
44
48
|
},
|
|
45
49
|
"devDependencies": {
|
|
@@ -58,6 +62,7 @@
|
|
|
58
62
|
"eslint-plugin-pnpm": "1.6.1",
|
|
59
63
|
"eslint-plugin-toml": "1.4.0",
|
|
60
64
|
"eslint-plugin-yml": "3.5.0",
|
|
65
|
+
"eslint-rule-benchmark": "0.8.0",
|
|
61
66
|
"eslint-vitest-rule-tester": "3.1.0",
|
|
62
67
|
"jiti": "2.7.0",
|
|
63
68
|
"lint-staged": "17.0.8",
|
|
@@ -82,6 +87,8 @@
|
|
|
82
87
|
"provenance": true
|
|
83
88
|
},
|
|
84
89
|
"scripts": {
|
|
90
|
+
"prebench": "nr build",
|
|
91
|
+
"bench": "eslint-rule-benchmark run --eslint-config benchmark/eslint.config.mjs",
|
|
85
92
|
"build": "tsdown --clean --dts",
|
|
86
93
|
"create-rule": "tsx scripts/create-rule.ts",
|
|
87
94
|
"dev": "tsdown --stub",
|