@almadar/eslint-plugin 2.4.1 → 2.4.3

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
@@ -28,6 +28,9 @@ const organismRequireEntityRow = require("./rules/organism-require-entity-row");
28
28
  // Atom/molecule rules
29
29
  const atomMoleculeNoEntityProp = require("./rules/atom-molecule-no-entity-prop");
30
30
 
31
+ // Behavior rules
32
+ const behaviorNoOrganisms = require("./rules/behavior-no-organisms");
33
+
31
34
  // Service rules - Phase 1-3 (Implemented)
32
35
  const serviceLazySingleton = require("./rules/service-lazy-singleton");
33
36
  const serviceSingletonResettable = require("./rules/service-singleton-resettable");
@@ -82,6 +85,9 @@ const plugin = {
82
85
  // Atom/molecule rules
83
86
  "atom-molecule-no-entity-prop": atomMoleculeNoEntityProp,
84
87
 
88
+ // Behavior rules
89
+ "behavior-no-organisms": behaviorNoOrganisms,
90
+
85
91
  // Service rules - Phase 1-3
86
92
  "service-lazy-singleton": serviceLazySingleton,
87
93
  "service-singleton-resettable": serviceSingletonResettable,
@@ -134,6 +140,9 @@ plugin.configs.recommended = {
134
140
  "almadar/template-extends-base": "warn",
135
141
  "almadar/require-translate": "warn",
136
142
 
143
+ // Behavior rules — restrict to atoms/molecules only
144
+ "almadar/behavior-no-organisms": "error",
145
+
137
146
  // Organism rules — enforce dumb organism pattern
138
147
  "almadar/organism-no-data-state": "error",
139
148
  "almadar/organism-no-auto-fetch": "error",
@@ -230,4 +239,17 @@ plugin.configs["services-strict"] = {
230
239
  },
231
240
  };
232
241
 
242
+ // Behaviors config — lint .orb behavior schemas for pattern tier compliance
243
+ // Requires: jsonc-eslint-parser (pnpm add -D jsonc-eslint-parser)
244
+ // Usage in eslint.config.js: { files: ["**/*.orb"], ...almadar.configs.behaviors }
245
+ plugin.configs.behaviors = {
246
+ plugins: { almadar: plugin },
247
+ languageOptions: {
248
+ parser: require("jsonc-eslint-parser"),
249
+ },
250
+ rules: {
251
+ "almadar/behavior-no-organisms": "error",
252
+ },
253
+ };
254
+
233
255
  module.exports = plugin;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/eslint-plugin",
3
- "version": "2.4.1",
3
+ "version": "2.4.3",
4
4
  "private": false,
5
5
  "description": "Custom ESLint rules for Almadar component architecture",
6
6
  "main": "index.js",
@@ -22,6 +22,9 @@
22
22
  "publishConfig": {
23
23
  "access": "public"
24
24
  },
25
+ "dependencies": {
26
+ "jsonc-eslint-parser": "3.1.0"
27
+ },
25
28
  "scripts": {
26
29
  "lint": "eslint index.js rules/ utils/"
27
30
  }
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * behavior-no-organisms
5
+ *
6
+ * Behaviors (.orb files in behaviors/) must only use atom and molecule patterns.
7
+ * Organisms and templates are forbidden, with exceptions for:
8
+ * - form / form-section (explicitly allowed by convention)
9
+ *
10
+ * All game components (canvas renderers, HUDs, menus, logs, panels) have been
11
+ * moved to molecule level. No game exception is needed.
12
+ *
13
+ * Requires: jsonc-eslint-parser configured for *.orb files.
14
+ *
15
+ * To regenerate BLOCKED_PATTERNS from component-mapping.json:
16
+ * node -e "
17
+ * const m = require('../almadar-patterns/src/component-mapping.json').mappings;
18
+ * const blocked = Object.entries(m)
19
+ * .filter(([k, v]) =>
20
+ * (v.importPath.includes('/organisms/') || v.importPath.includes('/templates/'))
21
+ * && !['form', 'form-section'].includes(k))
22
+ * .map(([k]) => k);
23
+ * console.log(JSON.stringify(blocked, null, 2));
24
+ * "
25
+ */
26
+
27
+ // Organism patterns: importPath contains /organisms/ or /templates/
28
+ // Excludes: form, form-section (allowed by convention)
29
+ const BLOCKED_PATTERNS = new Set([
30
+ // ── Organisms (non-game, non-form) ────────────────────────────────
31
+ "page-header",
32
+ "entity-list",
33
+ "entity-table",
34
+ "entity-cards",
35
+ "stats",
36
+ "detail-panel",
37
+ "wizard-container",
38
+ "confirm-dialog",
39
+ "master-detail",
40
+ "dashboard-grid",
41
+ "runtime-debugger",
42
+ "button-pattern",
43
+ "custom-pattern",
44
+ "drawer-slot",
45
+ "header",
46
+ "layout-pattern",
47
+ "modal-slot",
48
+ "navigation",
49
+ "orbital-visualization",
50
+ "section",
51
+ "sidebar",
52
+ "split",
53
+ "table",
54
+ "toast-slot",
55
+ "u-i-slot-renderer",
56
+ "split-pane",
57
+ "tabbed-container",
58
+ "collapsible-section",
59
+ "camera3-d",
60
+ "lighting3-d",
61
+ "scene3-d",
62
+ "canvas3-d-error-boundary",
63
+ "canvas3-d-loading-state",
64
+ "model-loader",
65
+ "physics-object3-d",
66
+ "feature-renderer",
67
+ "feature-renderer3-d",
68
+ "unit-renderer",
69
+ "trait-slot",
70
+ "trait-state-viewer",
71
+ "content-renderer",
72
+ "jazari-state-machine",
73
+ "state-machine-view",
74
+ "book-chapter-view",
75
+ "book-cover-page",
76
+ "book-nav-bar",
77
+ "book-table-of-contents",
78
+ "book-viewer",
79
+ "simulation-controls",
80
+ "simulation-graph",
81
+ "chart",
82
+ "timeline",
83
+ "media-gallery",
84
+ "signature-pad",
85
+ "document-viewer",
86
+ "graph-canvas",
87
+ "code-viewer",
88
+ "event-log",
89
+ "object-rule-panel",
90
+ "rule-editor",
91
+ "action-palette",
92
+ "sequence-bar",
93
+ "code-view",
94
+ "state-architect-board",
95
+ "state-node",
96
+ "transition-arrow",
97
+ "variable-panel",
98
+
99
+ // ── Templates (non-game) ──────────────────────────────────────────
100
+ "auth-layout",
101
+ "counter-template",
102
+ "dashboard-layout",
103
+ "generic-app-template",
104
+ ]);
105
+
106
+ // Alternative names that map to the same organism
107
+ const ALIASES = {
108
+ form: null, // explicitly allowed
109
+ "form-section": null, // explicitly allowed
110
+ };
111
+
112
+ module.exports = {
113
+ meta: {
114
+ type: "problem",
115
+ docs: {
116
+ description:
117
+ "Behavior schemas must only use atom and molecule patterns. " +
118
+ "Organisms and templates (except canvas game organisms and form-section) are forbidden.",
119
+ category: "Almadar Architecture",
120
+ },
121
+ messages: {
122
+ blockedPattern:
123
+ 'Pattern "{{pattern}}" is an organism/template. ' +
124
+ "Behaviors must only use atoms and molecules. " +
125
+ "Replace with a molecule-level equivalent or restructure the schema.",
126
+ },
127
+ schema: [],
128
+ },
129
+
130
+ create(context) {
131
+ const filename = context.filename || context.getFilename();
132
+
133
+ // Only apply to .orb files inside behaviors/ directories
134
+ if (!filename.endsWith(".orb") || !filename.includes("behaviors")) {
135
+ return {};
136
+ }
137
+
138
+ return {
139
+ // jsonc-eslint-parser provides JSONProperty AST nodes
140
+ JSONProperty(node) {
141
+ // Look for "type": "<pattern-name>" properties
142
+ if (
143
+ node.key &&
144
+ node.key.type === "JSONLiteral" &&
145
+ node.key.value === "type" &&
146
+ node.value &&
147
+ node.value.type === "JSONLiteral" &&
148
+ typeof node.value.value === "string"
149
+ ) {
150
+ const pattern = node.value.value;
151
+
152
+ // Skip explicitly allowed aliases
153
+ if (pattern in ALIASES) return;
154
+
155
+ if (BLOCKED_PATTERNS.has(pattern)) {
156
+ context.report({
157
+ node: node.value,
158
+ messageId: "blockedPattern",
159
+ data: { pattern },
160
+ });
161
+ }
162
+ }
163
+ },
164
+ };
165
+ },
166
+ };