@ethisyscore/eslint-plugin-coreconnect 1.71.4 → 1.71.6
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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ethisyscore/eslint-plugin-coreconnect",
|
|
3
|
-
"version": "1.71.
|
|
3
|
+
"version": "1.71.6",
|
|
4
4
|
"description": "ESLint rules enforcing EthisysCore plugin frontend conventions. Published so a new rule reaches every plugin on a version bump, rather than being copied into each scaffold and drifting.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -9,6 +9,18 @@
|
|
|
9
9
|
*/
|
|
10
10
|
const COLOR_REGEX = /^#(?:[0-9a-fA-F]{3}){1,2}(?:[0-9a-fA-F]{2})?$|^rgba?\(|^hsla?\(/;
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* A colour function whose channels come from CSS custom properties - `hsl(var(--border))`,
|
|
14
|
+
* `rgb(var(--cc-accent) / 0.5)`.
|
|
15
|
+
*
|
|
16
|
+
* This is not a hardcoded colour, it is the exact thing the rule's own message asks for, and
|
|
17
|
+
* flagging it was a false positive: `COLOR_REGEX` matches on the `hsl(` prefix alone and never
|
|
18
|
+
* looked inside. Measured on `finance`, whose `src/styles/tailwind.config.ts` is written entirely in
|
|
19
|
+
* this form - 48 findings, every one of them already themed, which is enough noise to teach a reader
|
|
20
|
+
* that the rule is wrong rather than that the file is.
|
|
21
|
+
*/
|
|
22
|
+
const TOKENISED_COLOR_REGEX = /^(?:rgba?|hsla?)\(\s*var\(\s*--/;
|
|
23
|
+
|
|
12
24
|
export default {
|
|
13
25
|
meta: {
|
|
14
26
|
type: "suggestion",
|
|
@@ -28,7 +40,15 @@ export default {
|
|
|
28
40
|
if (typeof node.value !== "string") {
|
|
29
41
|
return;
|
|
30
42
|
}
|
|
31
|
-
|
|
43
|
+
const value = node.value.trim();
|
|
44
|
+
|
|
45
|
+
// Order matters: a tokenised colour matches COLOR_REGEX too, so the exemption has to be
|
|
46
|
+
// checked first.
|
|
47
|
+
if (TOKENISED_COLOR_REGEX.test(value)) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (COLOR_REGEX.test(value)) {
|
|
32
52
|
context.report({ node, messageId: "noHardcodedColor", data: { value: node.value } });
|
|
33
53
|
}
|
|
34
54
|
},
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
* @type {import("eslint").Rule.RuleModule}
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
+
import { isTestFile } from "./testFiles.js";
|
|
17
|
+
|
|
16
18
|
const FUNCTION_LIKE = new Set([
|
|
17
19
|
"FunctionDeclaration",
|
|
18
20
|
"FunctionExpression",
|
|
@@ -96,6 +98,11 @@ export default {
|
|
|
96
98
|
schema: [],
|
|
97
99
|
},
|
|
98
100
|
create(context) {
|
|
101
|
+
// Test scaffolding is exempt: see isTestFile for why this rule's rationale does not reach it.
|
|
102
|
+
if (isTestFile(context.filename ?? context.getFilename?.())) {
|
|
103
|
+
return {};
|
|
104
|
+
}
|
|
105
|
+
|
|
99
106
|
return {
|
|
100
107
|
TSTypeLiteral(node) {
|
|
101
108
|
const position = positionOf(node);
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
* @type {import("eslint").Rule.RuleModule}
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
+
import { isTestFile } from "./testFiles.js";
|
|
16
|
+
|
|
15
17
|
const MINIMUM_MEMBERS = 3;
|
|
16
18
|
|
|
17
19
|
/** A `"literal"` type node, across the parser versions that spell it differently. */
|
|
@@ -37,6 +39,11 @@ export default {
|
|
|
37
39
|
schema: [],
|
|
38
40
|
},
|
|
39
41
|
create(context) {
|
|
42
|
+
// Test scaffolding is exempt: see isTestFile for why this rule's rationale does not reach it.
|
|
43
|
+
if (isTestFile(context.filename ?? context.getFilename?.())) {
|
|
44
|
+
return {};
|
|
45
|
+
}
|
|
46
|
+
|
|
40
47
|
return {
|
|
41
48
|
TSUnionType(node) {
|
|
42
49
|
const members = node.types ?? [];
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a file is test scaffolding rather than shipped code.
|
|
3
|
+
*
|
|
4
|
+
* Used by the two STRUCTURAL rules - `no-inline-object-type` and `no-inline-string-union` - and by
|
|
5
|
+
* nothing else. Both exist to stop an unnamed shape being re-written slightly differently by the
|
|
6
|
+
* next person who needs it, and that argument does not reach a test file: the shape belongs to one
|
|
7
|
+
* mock in one file, nobody imports it, and it is deleted when the test is.
|
|
8
|
+
*
|
|
9
|
+
* Measured before adding this: 80 of the estate's convention findings sit in test and mock files,
|
|
10
|
+
* 74 of them `no-inline-object-type`, and almost all are the prop type of a hand-rolled MUI stub -
|
|
11
|
+
* `Alert: ({ children, action }: { children?: ReactNode; action?: ReactNode }) => ...`. Naming those
|
|
12
|
+
* 74 would add 74 aliases that exist only to satisfy a rule, in files where the rule's own rationale
|
|
13
|
+
* does not apply. A rule that demands ceremony gets switched off, which costs the 679 findings in
|
|
14
|
+
* shipped code that it is genuinely right about.
|
|
15
|
+
*
|
|
16
|
+
* Deliberately NOT applied to `no-hardcoded-colors` or to any of the `no-local-*` rules. A hardcoded
|
|
17
|
+
* colour is trivially fixable anywhere and there is exactly one in a test file estate-wide; and a
|
|
18
|
+
* test file that re-declares the shared data grid is exactly the drift those rules exist to catch.
|
|
19
|
+
*
|
|
20
|
+
* The glob-shaped alternative - a `files` override in `configs.recommended` - would require that
|
|
21
|
+
* config to become an array, and every consumer spreads it as an object
|
|
22
|
+
* (`{ files: [...], ...coreconnect.configs.recommended }`). Changing that shape would break nine
|
|
23
|
+
* repos at once, so the check lives in the rules, which is also how this package delivers everything
|
|
24
|
+
* else: on a version bump, with no consumer edit.
|
|
25
|
+
*
|
|
26
|
+
* @param {string} filename Absolute or relative path, as ESLint reports it.
|
|
27
|
+
* @returns {boolean}
|
|
28
|
+
*/
|
|
29
|
+
export function isTestFile(filename) {
|
|
30
|
+
if (!filename) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Normalise Windows separators: ESLint reports native paths, and the estate is developed on both.
|
|
35
|
+
const path = filename.replace(/\\/g, "/");
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
/(^|\/)__tests__\//.test(path) ||
|
|
39
|
+
/(^|\/)__mocks__\//.test(path) ||
|
|
40
|
+
/\.(test|spec)\.[cm]?[jt]sx?$/.test(path) ||
|
|
41
|
+
// A hand-rolled stub kept beside the code it doubles rather than under __tests__. Anchored to the
|
|
42
|
+
// basename so a legitimate directory like `mockups/` cannot match.
|
|
43
|
+
/(^|\/)Mock[A-Z][^/]*\.[cm]?[jt]sx?$/.test(path)
|
|
44
|
+
);
|
|
45
|
+
}
|