@almadar/eslint-plugin 2.7.0 → 2.8.1

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 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 noUnknownType = require("./rules/no-unknown-type");
11
12
  const noRecordStringUnknown = require("./rules/no-record-string-unknown");
12
13
  const noEntityStringType = require("./rules/no-entity-string-type");
13
14
  const noImportGenerated = require("./rules/no-import-generated");
@@ -66,6 +67,7 @@ const plugin = {
66
67
  "template-serializable-props": templateSerializableProps,
67
68
  "no-type-prop": noTypeProp,
68
69
  "no-as-any": noAsAny,
70
+ "no-unknown-type": noUnknownType,
69
71
  "no-record-string-unknown": noRecordStringUnknown,
70
72
  "no-entity-string-type": noEntityStringType,
71
73
  "no-import-generated": noImportGenerated,
@@ -128,6 +130,8 @@ plugin.configs.recommended = {
128
130
  "almadar/template-serializable-props": "error",
129
131
  "almadar/no-type-prop": "error",
130
132
  "almadar/no-as-any": "error",
133
+ "almadar/no-unknown-type": "error",
134
+ "almadar/no-record-string-unknown": "error",
131
135
  "almadar/no-entity-string-type": "error",
132
136
  "almadar/no-import-generated": "error",
133
137
  "almadar/no-use-navigate": "error",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/eslint-plugin",
3
- "version": "2.7.0",
3
+ "version": "2.8.1",
4
4
  "private": false,
5
5
  "description": "Custom ESLint rules for Almadar component architecture",
6
6
  "main": "index.js",
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Forbid `unknown` as a type annotation or cast target — fix the actual
5
+ * type issue instead. Mirrors `no-as-any` but for `unknown`.
6
+ *
7
+ * Rationale: `unknown` is technically safe (you can't use it until you
8
+ * narrow it), but in this codebase it gets used as a lazy escape hatch
9
+ * on trace events, service results, API boundaries — exactly where
10
+ * typed interfaces from `@almadar/core` or service return types SHOULD
11
+ * appear. Ban it across the board.
12
+ *
13
+ * Allowed contexts (where `unknown` is the idiomatic correct answer):
14
+ * - `catch (err: unknown)` — catch-clause parameter. TS 4.4+ idiom;
15
+ * the alternative is `any`, which is worse.
16
+ * - `<T extends unknown>` — generic parameter extends clause. `unknown`
17
+ * there is just "no constraint" and is sometimes required for
18
+ * conditional-type edge cases.
19
+ *
20
+ * Everything else — type annotations, return types, property types,
21
+ * `as unknown` casts, type aliases — is flagged.
22
+ */
23
+ module.exports = {
24
+ meta: {
25
+ type: "problem",
26
+ docs: {
27
+ description:
28
+ "Disallow `unknown` as a type annotation or cast target — use a real typed interface from @almadar/core or the relevant package instead",
29
+ category: "Almadar Architecture",
30
+ },
31
+ messages: {
32
+ noUnknownType:
33
+ "Never use `unknown` as a type annotation or cast target. Fix the real type issue: import the right interface from @almadar/core (OrbitalSchema, Entity, Trait, Field, PatternConfig, Effect, Transition, PayloadField, ServiceParams, EntityRow, FieldValue) or the relevant package, or export a typed union from the producing module. Allowed only in `catch (err: unknown)` and generic `<T extends unknown>` clauses.",
34
+ },
35
+ schema: [],
36
+ },
37
+
38
+ create(context) {
39
+ /** Walk up the parent chain looking for an allowed-context ancestor. */
40
+ function isInAllowedContext(node) {
41
+ let cur = node.parent;
42
+ while (cur) {
43
+ // catch (err: unknown)
44
+ if (cur.type === "CatchClause") return true;
45
+ // catch binding's type annotation wraps the unknown:
46
+ // CatchClause → Identifier → TSTypeAnnotation → TSUnknownKeyword
47
+ if (
48
+ cur.type === "TSTypeAnnotation" &&
49
+ cur.parent &&
50
+ cur.parent.type === "Identifier" &&
51
+ cur.parent.parent &&
52
+ cur.parent.parent.type === "CatchClause"
53
+ ) {
54
+ return true;
55
+ }
56
+ // <T extends unknown> — generic parameter's extends clause
57
+ if (cur.type === "TSTypeParameter") return true;
58
+ cur = cur.parent;
59
+ }
60
+ return false;
61
+ }
62
+
63
+ return {
64
+ TSUnknownKeyword(node) {
65
+ if (isInAllowedContext(node)) return;
66
+ context.report({ node, messageId: "noUnknownType" });
67
+ },
68
+ };
69
+ },
70
+ };
@@ -23,7 +23,6 @@ module.exports = {
23
23
  "usePaginatedEntityList",
24
24
  "useEntityListSuspense",
25
25
  "useEntitySuspense",
26
- "useSelectedEntity",
27
26
  ]);
28
27
 
29
28
  return {