@almadar/eslint-plugin 2.17.0 → 2.19.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/index.js +3 -0
- package/package.json +4 -2
- package/rules/no-as-unknown-as.js +46 -0
- package/rules/no-record-string-unknown.js +1 -15
package/index.js
CHANGED
|
@@ -8,6 +8,7 @@ const templateNoIteration = require("./rules/template-no-iteration");
|
|
|
8
8
|
const templateSerializableProps = require("./rules/template-serializable-props");
|
|
9
9
|
const noTypeProp = require("./rules/no-type-prop");
|
|
10
10
|
const noAsAny = require("./rules/no-as-any");
|
|
11
|
+
const noAsUnknownAs = require("./rules/no-as-unknown-as");
|
|
11
12
|
const noUnknownType = require("./rules/no-unknown-type");
|
|
12
13
|
const noRecordStringUnknown = require("./rules/no-record-string-unknown");
|
|
13
14
|
const noEntityStringType = require("./rules/no-entity-string-type");
|
|
@@ -70,6 +71,7 @@ const plugin = {
|
|
|
70
71
|
"template-serializable-props": templateSerializableProps,
|
|
71
72
|
"no-type-prop": noTypeProp,
|
|
72
73
|
"no-as-any": noAsAny,
|
|
74
|
+
"no-as-unknown-as": noAsUnknownAs,
|
|
73
75
|
"no-unknown-type": noUnknownType,
|
|
74
76
|
"no-record-string-unknown": noRecordStringUnknown,
|
|
75
77
|
"no-entity-string-type": noEntityStringType,
|
|
@@ -136,6 +138,7 @@ plugin.configs.recommended = {
|
|
|
136
138
|
"almadar/template-serializable-props": "error",
|
|
137
139
|
"almadar/no-type-prop": "error",
|
|
138
140
|
"almadar/no-as-any": "error",
|
|
141
|
+
"almadar/no-as-unknown-as": "error",
|
|
139
142
|
"almadar/no-unknown-type": "error",
|
|
140
143
|
"almadar/no-record-string-unknown": "error",
|
|
141
144
|
"almadar/no-entity-string-type": "error",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@almadar/eslint-plugin",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.19.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Custom ESLint rules for Almadar component architecture",
|
|
6
6
|
"main": "index.js",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
16
|
"eslint": "10.0.0",
|
|
17
|
+
"@typescript-eslint/parser": "^8.65.0",
|
|
17
18
|
"turbo": "^2.8.17"
|
|
18
19
|
},
|
|
19
20
|
"repository": {
|
|
@@ -28,6 +29,7 @@
|
|
|
28
29
|
"jsonc-eslint-parser": "3.1.0"
|
|
29
30
|
},
|
|
30
31
|
"scripts": {
|
|
31
|
-
"lint": "eslint index.js rules/ utils/"
|
|
32
|
+
"lint": "eslint index.js rules/ utils/",
|
|
33
|
+
"test": "node --test"
|
|
32
34
|
}
|
|
33
35
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Forbid the `x as unknown as T` double-cast chain (CLAUDE.md "Type safety —
|
|
5
|
+
* Zero `as any` / `unknown` / `as unknown as X`"). The pattern routes an
|
|
6
|
+
* arbitrarily-typed value through `unknown` purely to defeat structural
|
|
7
|
+
* checking before landing it on a target type — the value is never actually
|
|
8
|
+
* narrowed, so the compiler stops verifying the cast at all.
|
|
9
|
+
*
|
|
10
|
+
* Flags a `TSAsExpression` whose own expression is itself a `TSAsExpression`
|
|
11
|
+
* to `unknown` — i.e. an `as unknown` that exists only as a step toward
|
|
12
|
+
* another cast, not a value genuinely left as `unknown`. A terminal
|
|
13
|
+
* `x as unknown` (nothing casts it further) is not itself reported by this
|
|
14
|
+
* rule — `almadar/no-unknown-type` already owns flagging bare `unknown`.
|
|
15
|
+
*/
|
|
16
|
+
module.exports = {
|
|
17
|
+
meta: {
|
|
18
|
+
type: "problem",
|
|
19
|
+
docs: {
|
|
20
|
+
description:
|
|
21
|
+
"Disallow the `x as unknown as T` double-cast chain — type the value or parse it instead",
|
|
22
|
+
category: "Almadar Architecture",
|
|
23
|
+
},
|
|
24
|
+
messages: {
|
|
25
|
+
noAsUnknownAs:
|
|
26
|
+
"Double cast via `as unknown as` is forbidden (CLAUDE.md type-safety rule) — type the value or parse it",
|
|
27
|
+
},
|
|
28
|
+
schema: [],
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
create(context) {
|
|
32
|
+
return {
|
|
33
|
+
TSAsExpression(node) {
|
|
34
|
+
const inner = node.expression;
|
|
35
|
+
if (
|
|
36
|
+
inner &&
|
|
37
|
+
inner.type === "TSAsExpression" &&
|
|
38
|
+
inner.typeAnnotation &&
|
|
39
|
+
inner.typeAnnotation.type === "TSUnknownKeyword"
|
|
40
|
+
) {
|
|
41
|
+
context.report({ node, messageId: "noAsUnknownAs" });
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
};
|
|
@@ -5,7 +5,7 @@ module.exports = {
|
|
|
5
5
|
type: "problem",
|
|
6
6
|
docs: {
|
|
7
7
|
description:
|
|
8
|
-
"Disallow Record<string, unknown
|
|
8
|
+
"Disallow Record<string, unknown> and Record<string, any>. Use @almadar/core types instead. (The 'as unknown as' double-cast check moved to almadar/no-as-unknown-as.)",
|
|
9
9
|
category: "Almadar Architecture",
|
|
10
10
|
},
|
|
11
11
|
messages: {
|
|
@@ -13,8 +13,6 @@ module.exports = {
|
|
|
13
13
|
"Use a typed interface from @almadar/core instead of Record<string, unknown>. Common replacements: OrbitalSchema, Entity, Trait, Field, PatternConfig, Effect, Transition, PayloadField.",
|
|
14
14
|
noRecordStringAny:
|
|
15
15
|
"Record<string, any> is never acceptable. Use Record<string, unknown> at minimum, or a proper @almadar/core type.",
|
|
16
|
-
noDoubleUnknownCast:
|
|
17
|
-
"Avoid 'as unknown as' double casts. Use a type guard, define a proper interface, or extend @almadar/core types.",
|
|
18
16
|
},
|
|
19
17
|
schema: [],
|
|
20
18
|
},
|
|
@@ -48,18 +46,6 @@ module.exports = {
|
|
|
48
46
|
}
|
|
49
47
|
}
|
|
50
48
|
},
|
|
51
|
-
|
|
52
|
-
// Catch: as unknown as X (double cast)
|
|
53
|
-
TSAsExpression(node) {
|
|
54
|
-
if (
|
|
55
|
-
node.typeAnnotation &&
|
|
56
|
-
node.typeAnnotation.type === "TSUnknownKeyword" &&
|
|
57
|
-
node.parent &&
|
|
58
|
-
node.parent.type === "TSAsExpression"
|
|
59
|
-
) {
|
|
60
|
-
context.report({ node: node.parent, messageId: "noDoubleUnknownCast" });
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
49
|
};
|
|
64
50
|
},
|
|
65
51
|
};
|