@tsrx/eslint-plugin 0.3.68 → 0.3.69

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 CHANGED
@@ -36,8 +36,7 @@ The plugin automatically:
36
36
  - Detects and uses `@typescript-eslint/parser` if installed for `.ts`/`.tsx` files
37
37
  - Excludes `.d.ts` files, `node_modules`, `dist`, and `build` directories from
38
38
  linting
39
- - Works with both `.ts`/`.tsx` and Ripple component files (`.tsrx` by default,
40
- plus `.tsrx`)
39
+ - Works with `.ts`, `.tsx`, and `.tsrx` files
41
40
 
42
41
  ### Legacy Config (.eslintrc)
43
42
 
@@ -85,8 +84,8 @@ export default [
85
84
 
86
85
  ### `ripple/no-module-scope-track` (error)
87
86
 
88
- Prevents calling `track()` at module scope. Tracked values must be created within
89
- a component context.
87
+ Prevents calling `track()` at module scope. Tracked values must be created inside
88
+ a function body.
90
89
 
91
90
  ❌ **Incorrect:**
92
91
 
@@ -96,8 +95,8 @@ import { track } from 'ripple';
96
95
  // This will cause runtime errors
97
96
  let globalCount = track(0);
98
97
 
99
- export component App() {
100
- <div>{@globalCount}</div>
98
+ export function App() {
99
+ return <div>{globalCount}</div>;
101
100
  }
102
101
  ```
103
102
 
@@ -106,33 +105,10 @@ export component App() {
106
105
  ```js
107
106
  import { track } from 'ripple';
108
107
 
109
- export component App() {
110
- // track() called within component
108
+ export function App() {
111
109
  let count = track(0);
112
110
 
113
- <div>{@count}</div>
114
- }
115
- ```
116
-
117
- ### `ripple/require-component-export` (warning)
118
-
119
- Warns when capitalized components are not exported. This helps ensure components
120
- are reusable across modules.
121
-
122
- ❌ **Incorrect:**
123
-
124
- ```js
125
- component MyButton() {
126
- <button>Click me</button>
127
- }
128
- // MyButton is defined but not exported
129
- ```
130
-
131
- ✅ **Correct:**
132
-
133
- ```js
134
- export component MyButton() {
135
- <button>Click me</button>
111
+ return <div>{count}</div>;
136
112
  }
137
113
  ```
138
114
 
@@ -155,26 +131,11 @@ Ripple doesn't have synthetic events, so `onInput` is the correct event handler.
155
131
 
156
132
  This rule is auto-fixable with `--fix`.
157
133
 
158
- ### `ripple/no-return-in-component` (error)
134
+ ### `ripple/control-flow-jsx` (error)
159
135
 
160
- Prevents returning JSX from Ripple components. In Ripple, JSX should be used as
161
- statements, not expressions.
162
-
163
- ❌ **Incorrect:**
164
-
165
- ```js
166
- export component App() {
167
- return <div>Hello World</div>;
168
- }
169
- ```
170
-
171
- ✅ **Correct:**
172
-
173
- ```js
174
- export component App() {
175
- <div>Hello World</div>
176
- }
177
- ```
136
+ Checks render control flow inside functions that return native TSRX. `for...of`
137
+ loops in returned TSRX should render elements, while loops inside `effect()`
138
+ callbacks should not render JSX.
178
139
 
179
140
  ### `ripple/no-lazy-destructuring-in-modules` (error)
180
141
 
@@ -217,9 +178,13 @@ export function useCount() {
217
178
  }
218
179
  ```
219
180
 
220
- **Note:** Lazy destructuring (`&[]` / `&{}`) is only valid in Ripple component
221
- files (`.tsrx` by default). In TypeScript modules, use `.value` to read and write
222
- tracked values.
181
+ **Note:** Lazy destructuring (`&[]` / `&{}`) is only valid in TSRX files. In
182
+ TypeScript modules, use `.value` to read and write tracked values.
183
+
184
+ ### `ripple/no-return-in-component` (deprecated)
185
+
186
+ This compatibility rule is now a no-op. TSRX components are ordinary functions, so
187
+ returning native TSRX is the expected authoring style.
223
188
 
224
189
  ## Custom Configuration
225
190
 
@@ -231,17 +196,16 @@ export default [
231
196
  plugins: { ripple },
232
197
  rules: {
233
198
  'ripple/no-module-scope-track': 'error',
234
- 'ripple/require-component-export': 'off', // Disable this rule
235
199
  'ripple/prefer-oninput': 'error', // Make this an error instead of warning
236
- 'ripple/no-return-in-component': 'error',
200
+ 'ripple/control-flow-jsx': 'error',
237
201
  'ripple/no-lazy-destructuring-in-modules': 'error',
202
+ 'ripple/valid-for-of-key': 'error',
238
203
  },
239
204
  },
240
205
  ];
241
206
  ```
242
207
 
243
- The plugin will automatically detect and use the Ripple parser for your Ripple
244
- component files, including `.tsrx`.
208
+ The plugin will automatically detect and use the Ripple parser for `.tsrx` files.
245
209
 
246
210
  ## License
247
211
 
package/dist/index.js CHANGED
@@ -7,19 +7,14 @@ const rule$5 = {
7
7
  description: "Disallow calling track() at module scope",
8
8
  recommended: true
9
9
  },
10
- messages: { moduleScope: "track() cannot be called at module scope. It must be called within a component context." },
10
+ messages: { moduleScope: "track() cannot be called at module scope. Move it into a function body." },
11
11
  schema: []
12
12
  },
13
13
  create(context) {
14
- let componentDepth = 0;
15
14
  let functionDepth = 0;
16
- const incrementComponentDepth = () => componentDepth++;
17
- const decrementComponentDepth = () => componentDepth--;
18
15
  const incrementFunctionDepth = () => functionDepth++;
19
16
  const decrementFunctionDepth = () => functionDepth--;
20
17
  return {
21
- Component: incrementComponentDepth,
22
- "Component:exit": decrementComponentDepth,
23
18
  FunctionDeclaration: incrementFunctionDepth,
24
19
  "FunctionDeclaration:exit": decrementFunctionDepth,
25
20
  FunctionExpression: incrementFunctionDepth,
@@ -27,7 +22,7 @@ const rule$5 = {
27
22
  ArrowFunctionExpression: incrementFunctionDepth,
28
23
  "ArrowFunctionExpression:exit": decrementFunctionDepth,
29
24
  CallExpression(node) {
30
- if (node.callee.type === "Identifier" && node.callee.name === "track" && componentDepth === 0 && functionDepth === 0) context.report({
25
+ if (node.callee.type === "Identifier" && node.callee.name === "track" && functionDepth === 0) context.report({
31
26
  node,
32
27
  messageId: "moduleScope"
33
28
  });
@@ -89,39 +84,53 @@ const rule$3 = {
89
84
  meta: {
90
85
  type: "problem",
91
86
  docs: {
92
- description: "Disallow return statements with JSX in Ripple components",
93
- recommended: true
87
+ description: "Deprecated: TSRX components are functions that return native TSRX expressions.",
88
+ recommended: false
94
89
  },
95
- messages: { noReturn: "Do not return JSX from Ripple components. Use JSX as statements instead." },
90
+ deprecated: true,
91
+ messages: { noReturn: "TSRX components should return native TSRX expressions." },
96
92
  schema: []
97
93
  },
98
94
  create(context) {
99
- let insideComponent = 0;
100
- return {
101
- "ExpressionStatement > CallExpression[callee.name='component']"() {
102
- insideComponent++;
103
- },
104
- "ExpressionStatement > CallExpression[callee.name='component']:exit"() {
105
- insideComponent--;
106
- },
107
- "VariableDeclarator[init.callee.name=\"component\"]"() {
108
- insideComponent++;
109
- },
110
- "VariableDeclarator[init.callee.name=\"component\"]:exit"() {
111
- insideComponent--;
112
- },
113
- ReturnStatement(node) {
114
- if (insideComponent > 0 && node.argument) {
115
- if (node.argument.type === "JSXElement" || node.argument.type === "JSXFragment") context.report({
116
- node,
117
- messageId: "noReturn"
118
- });
119
- }
120
- }
121
- };
95
+ return {};
122
96
  }
123
97
  };
124
98
  //#endregion
99
+ //#region src/utils/tsrx.ts
100
+ const NESTED_BOUNDARY_TYPES = new Set([
101
+ "FunctionDeclaration",
102
+ "FunctionExpression",
103
+ "ArrowFunctionExpression",
104
+ "ClassDeclaration",
105
+ "ClassExpression",
106
+ "MethodDefinition",
107
+ "PropertyDefinition",
108
+ "StaticBlock"
109
+ ]);
110
+ function isNativeTsrxNode(node) {
111
+ return node?.type === "Element" || node?.type === "Tsrx";
112
+ }
113
+ function functionReturnsNativeTsrx(node) {
114
+ const body = node.body;
115
+ if (!body) return false;
116
+ if (isNativeTsrxNode(body)) return true;
117
+ if (body.type !== "BlockStatement") return false;
118
+ return containsNativeTsrxReturn(body);
119
+ }
120
+ function containsNativeTsrxReturn(node) {
121
+ if (!node || typeof node !== "object") return false;
122
+ if (node.type === "ReturnStatement" && isNativeTsrxNode(node.argument)) return true;
123
+ if (node.type !== "BlockStatement" && NESTED_BOUNDARY_TYPES.has(node.type)) return false;
124
+ for (const key of Object.keys(node)) {
125
+ if (key === "parent" || key === "loc" || key === "range") continue;
126
+ const value = node[key];
127
+ if (Array.isArray(value)) {
128
+ for (const child of value) if (child?.type && containsNativeTsrxReturn(child)) return true;
129
+ } else if (value?.type && containsNativeTsrxReturn(value)) return true;
130
+ }
131
+ return false;
132
+ }
133
+ //#endregion
125
134
  //#region src/rules/control-flow-jsx.ts
126
135
  const rule$2 = {
127
136
  meta: {
@@ -131,7 +140,7 @@ const rule$2 = {
131
140
  recommended: true
132
141
  },
133
142
  messages: {
134
- requireJsxInLoop: "For...of loops in component bodies should contain JSX elements. Use JSX to render items.",
143
+ requireJsxInLoop: "For...of loops in returned TSRX should contain JSX elements. Use JSX to render items.",
135
144
  noJsxInEffectLoop: "For...of loops inside effect() should not contain JSX. Effects are for side effects, not rendering."
136
145
  },
137
146
  schema: []
@@ -139,11 +148,13 @@ const rule$2 = {
139
148
  create(context) {
140
149
  let insideComponent = 0;
141
150
  let insideEffect = 0;
151
+ let nonComponentFunctionDepth = 0;
152
+ const functionStack = [];
142
153
  function containsJSX(node, visited = /* @__PURE__ */ new Set()) {
143
154
  if (!node) return false;
144
155
  if (visited.has(node)) return false;
145
156
  visited.add(node);
146
- if (node.type === "JSXElement" || node.type === "JSXFragment" || node.type === "Element") return true;
157
+ if (node.type === "JSXElement" || node.type === "JSXFragment" || isNativeTsrxNode(node)) return true;
147
158
  const keys = Object.keys(node);
148
159
  for (const key of keys) {
149
160
  if (key === "parent" || key === "loc" || key === "range") continue;
@@ -157,12 +168,12 @@ const rule$2 = {
157
168
  return false;
158
169
  }
159
170
  return {
160
- Component() {
161
- insideComponent++;
162
- },
163
- "Component:exit"() {
164
- insideComponent--;
165
- },
171
+ FunctionDeclaration: enterFunction,
172
+ "FunctionDeclaration:exit": exitFunction,
173
+ FunctionExpression: enterFunction,
174
+ "FunctionExpression:exit": exitFunction,
175
+ ArrowFunctionExpression: enterFunction,
176
+ "ArrowFunctionExpression:exit": exitFunction,
166
177
  "CallExpression[callee.name='effect']"() {
167
178
  insideEffect++;
168
179
  },
@@ -177,12 +188,23 @@ const rule$2 = {
177
188
  node,
178
189
  messageId: "noJsxInEffectLoop"
179
190
  });
180
- } else if (!hasJSX) context.report({
191
+ } else if (nonComponentFunctionDepth > 0) return;
192
+ else if (!hasJSX) context.report({
181
193
  node,
182
194
  messageId: "requireJsxInLoop"
183
195
  });
184
196
  }
185
197
  };
198
+ function enterFunction(node) {
199
+ const isComponent = functionReturnsNativeTsrx(node);
200
+ functionStack.push(isComponent);
201
+ if (isComponent) insideComponent++;
202
+ else if (insideComponent > 0) nonComponentFunctionDepth++;
203
+ }
204
+ function exitFunction() {
205
+ if (functionStack.pop()) insideComponent--;
206
+ else if (insideComponent > 0) nonComponentFunctionDepth--;
207
+ }
186
208
  }
187
209
  };
188
210
  //#endregion
@@ -332,7 +354,6 @@ function createConfig(name, files, parser) {
332
354
  rules: {
333
355
  "ripple/no-module-scope-track": "error",
334
356
  "ripple/prefer-oninput": "warn",
335
- "ripple/no-return-in-component": "error",
336
357
  "ripple/control-flow-jsx": "error",
337
358
  "ripple/no-lazy-destructuring-in-modules": "error",
338
359
  "ripple/valid-for-of-key": "error"
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["rule","rule","rule","rule","rule","noModuleScopeTrack","preferOnInput","noReturnInComponent","controlFlowJsx","noLazyDestructuringInModules","validForOfKey"],"sources":["../src/rules/no-module-scope-track.ts","../src/rules/prefer-oninput.ts","../src/rules/no-return-in-component.ts","../src/rules/control-flow-jsx.ts","../src/rules/no-lazy-destructuring-in-modules.ts","../src/rules/valid-for-of-key.ts","../src/index.ts"],"sourcesContent":["import type { Rule } from 'eslint';\nimport type * as AST from '@tsrx/core/types/estree';\n\nconst rule: Rule.RuleModule = {\n\tmeta: {\n\t\ttype: 'problem',\n\t\tdocs: {\n\t\t\tdescription: 'Disallow calling track() at module scope',\n\t\t\trecommended: true,\n\t\t},\n\t\tmessages: {\n\t\t\tmoduleScope:\n\t\t\t\t'track() cannot be called at module scope. It must be called within a component context.',\n\t\t},\n\t\tschema: [],\n\t},\n\tcreate(context) {\n\t\tlet componentDepth = 0;\n\t\tlet functionDepth = 0;\n\n\t\tconst incrementComponentDepth = () => componentDepth++;\n\t\tconst decrementComponentDepth = () => componentDepth--;\n\t\tconst incrementFunctionDepth = () => functionDepth++;\n\t\tconst decrementFunctionDepth = () => functionDepth--;\n\n\t\treturn {\n\t\t\t// Only track when we enter a Ripple component\n\t\t\t// Ripple's parser returns \"Component\" nodes for component declarations\n\t\t\tComponent: incrementComponentDepth,\n\t\t\t'Component:exit': decrementComponentDepth,\n\n\t\t\t// Track regular functions and arrow functions\n\t\t\tFunctionDeclaration: incrementFunctionDepth,\n\t\t\t'FunctionDeclaration:exit': decrementFunctionDepth,\n\t\t\tFunctionExpression: incrementFunctionDepth,\n\t\t\t'FunctionExpression:exit': decrementFunctionDepth,\n\t\t\tArrowFunctionExpression: incrementFunctionDepth,\n\t\t\t'ArrowFunctionExpression:exit': decrementFunctionDepth,\n\n\t\t\t// Check track() calls\n\t\t\tCallExpression(node: AST.CallExpression) {\n\t\t\t\tif (\n\t\t\t\t\tnode.callee.type === 'Identifier' &&\n\t\t\t\t\tnode.callee.name === 'track' &&\n\t\t\t\t\tcomponentDepth === 0 &&\n\t\t\t\t\tfunctionDepth === 0\n\t\t\t\t) {\n\t\t\t\t\tcontext.report({\n\t\t\t\t\t\tnode,\n\t\t\t\t\t\tmessageId: 'moduleScope',\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t},\n};\n\nexport default rule;\n","import type { Rule } from 'eslint';\nimport type * as AST from '@tsrx/core/types/estree';\nimport type * as ESTreeJSX from '@tsrx/core/types/estree-jsx';\n\nconst rule: Rule.RuleModule = {\n\tmeta: {\n\t\ttype: 'suggestion',\n\t\tdocs: {\n\t\t\tdescription: 'Prefer onInput over onChange for form inputs in Ripple',\n\t\t\trecommended: true,\n\t\t},\n\t\tmessages: {\n\t\t\tpreferOnInput:\n\t\t\t\t'Use \"onInput\" instead of \"onChange\". Ripple does not have synthetic events like React.',\n\t\t},\n\t\tfixable: 'code',\n\t\tschema: [],\n\t},\n\tcreate(context) {\n\t\tconst reported_ranges = new Set<string>();\n\n\t\tfunction report_onchange(node: AST.Attribute | ESTreeJSX.JSXAttribute) {\n\t\t\tconst range = node.range;\n\t\t\tif (!range) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst key = `${range[0]}:${range[1]}`;\n\t\t\tif (reported_ranges.has(key)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\treported_ranges.add(key);\n\n\t\t\tcontext.report({\n\t\t\t\tnode,\n\t\t\t\tmessageId: 'preferOnInput',\n\t\t\t\tfix(fixer) {\n\t\t\t\t\treturn fixer.replaceText(node.name, 'onInput');\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\treturn {\n\t\t\t// Check JSX attributes (standard JSX)\n\t\t\t'JSXAttribute[name.name=\"onChange\"]'(node: ESTreeJSX.JSXAttribute) {\n\t\t\t\treport_onchange(node);\n\t\t\t},\n\t\t\t// Check Attribute nodes (Ripple parser)\n\t\t\t'Attribute[name.name=\"onChange\"]'(node: AST.Attribute) {\n\t\t\t\treport_onchange(node);\n\t\t\t},\n\t\t\t// Check object properties (for spread props)\n\t\t\t'Property[key.name=\"onChange\"]'(node: AST.Property) {\n\t\t\t\t// Only report if this looks like it's in a props object\n\t\t\t\tconst ancestors = context.sourceCode.getAncestors(node);\n\t\t\t\tconst inObjectExpression = ancestors.some(\n\t\t\t\t\t(ancestor) => ancestor.type === 'ObjectExpression',\n\t\t\t\t);\n\n\t\t\t\tif (inObjectExpression) {\n\t\t\t\t\tcontext.report({\n\t\t\t\t\t\tnode,\n\t\t\t\t\t\tmessageId: 'preferOnInput',\n\t\t\t\t\t\tfix(fixer) {\n\t\t\t\t\t\t\treturn fixer.replaceText(node.key, 'onInput');\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t},\n};\n\nexport default rule;\n","import type { Rule } from 'eslint';\nimport type * as AST from '@tsrx/core/types/estree';\n\nconst rule: Rule.RuleModule = {\n\tmeta: {\n\t\ttype: 'problem',\n\t\tdocs: {\n\t\t\tdescription: 'Disallow return statements with JSX in Ripple components',\n\t\t\trecommended: true,\n\t\t},\n\t\tmessages: {\n\t\t\tnoReturn: 'Do not return JSX from Ripple components. Use JSX as statements instead.',\n\t\t},\n\t\tschema: [],\n\t},\n\tcreate(context) {\n\t\tlet insideComponent = 0;\n\n\t\treturn {\n\t\t\t// Track component boundaries\n\t\t\t\"ExpressionStatement > CallExpression[callee.name='component']\"() {\n\t\t\t\tinsideComponent++;\n\t\t\t},\n\t\t\t\"ExpressionStatement > CallExpression[callee.name='component']:exit\"() {\n\t\t\t\tinsideComponent--;\n\t\t\t},\n\t\t\t// Also track arrow functions and regular functions that might be components\n\t\t\t'VariableDeclarator[init.callee.name=\"component\"]'() {\n\t\t\t\tinsideComponent++;\n\t\t\t},\n\t\t\t'VariableDeclarator[init.callee.name=\"component\"]:exit'() {\n\t\t\t\tinsideComponent--;\n\t\t\t},\n\t\t\t// Check return statements\n\t\t\tReturnStatement(node: AST.ReturnStatement) {\n\t\t\t\tif (insideComponent > 0 && node.argument) {\n\t\t\t\t\t// Check if returning JSX (JSXElement, JSXFragment)\n\t\t\t\t\tif (node.argument.type === 'JSXElement' || node.argument.type === 'JSXFragment') {\n\t\t\t\t\t\tcontext.report({\n\t\t\t\t\t\t\tnode,\n\t\t\t\t\t\t\tmessageId: 'noReturn',\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t},\n};\n\nexport default rule;\n","import type { Rule } from 'eslint';\nimport type * as AST from '@tsrx/core/types/estree';\n\nconst rule: Rule.RuleModule = {\n\tmeta: {\n\t\ttype: 'problem',\n\t\tdocs: {\n\t\t\tdescription:\n\t\t\t\t'Require JSX in for...of loops within components, but disallow JSX in for...of loops within effects',\n\t\t\trecommended: true,\n\t\t},\n\t\tmessages: {\n\t\t\trequireJsxInLoop:\n\t\t\t\t'For...of loops in component bodies should contain JSX elements. Use JSX to render items.',\n\t\t\tnoJsxInEffectLoop:\n\t\t\t\t'For...of loops inside effect() should not contain JSX. Effects are for side effects, not rendering.',\n\t\t},\n\t\tschema: [],\n\t},\n\tcreate(context) {\n\t\tlet insideComponent = 0;\n\t\tlet insideEffect = 0;\n\n\t\tfunction containsJSX(node: AST.Node, visited: Set<AST.Node> = new Set()): boolean {\n\t\t\tif (!node) return false;\n\n\t\t\t// Avoid infinite loops from circular references\n\t\t\tif (visited.has(node)) return false;\n\t\t\tvisited.add(node);\n\n\t\t\t// Check if current node is JSX/Element (Ripple uses 'Element' type instead of 'JSXElement')\n\t\t\tif (\n\t\t\t\tnode.type === ('JSXElement' as string) ||\n\t\t\t\tnode.type === ('JSXFragment' as string) ||\n\t\t\t\tnode.type === ('Element' as string)\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tconst keys = Object.keys(node);\n\t\t\tfor (const key of keys) {\n\t\t\t\tif (key === 'parent' || key === 'loc' || key === 'range') {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst value = (node as any)[key];\n\t\t\t\tif (value && typeof value === 'object') {\n\t\t\t\t\tif (Array.isArray(value)) {\n\t\t\t\t\t\tfor (const item of value) {\n\t\t\t\t\t\t\tif (item && typeof item === 'object' && containsJSX(item, visited)) {\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (value.type && containsJSX(value, visited)) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\treturn {\n\t\t\tComponent() {\n\t\t\t\tinsideComponent++;\n\t\t\t},\n\t\t\t'Component:exit'() {\n\t\t\t\tinsideComponent--;\n\t\t\t},\n\n\t\t\t\"CallExpression[callee.name='effect']\"() {\n\t\t\t\tinsideEffect++;\n\t\t\t},\n\t\t\t\"CallExpression[callee.name='effect']:exit\"() {\n\t\t\t\tinsideEffect--;\n\t\t\t},\n\n\t\t\tForOfStatement(node: AST.ForOfStatement) {\n\t\t\t\tif (insideComponent === 0) return;\n\n\t\t\t\tconst hasJSX = containsJSX(node.body);\n\n\t\t\t\tif (insideEffect > 0) {\n\t\t\t\t\tif (hasJSX) {\n\t\t\t\t\t\tcontext.report({\n\t\t\t\t\t\t\tnode,\n\t\t\t\t\t\t\tmessageId: 'noJsxInEffectLoop',\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (!hasJSX) {\n\t\t\t\t\t\tcontext.report({\n\t\t\t\t\t\t\tnode,\n\t\t\t\t\t\t\tmessageId: 'requireJsxInLoop',\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t},\n};\n\nexport default rule;\n","import type { Rule } from 'eslint';\n\nconst rule: Rule.RuleModule = {\n\tmeta: {\n\t\ttype: 'problem',\n\t\tdocs: {\n\t\t\tdescription: 'Disallow lazy destructuring (&[] / &{}) in TypeScript/JavaScript modules',\n\t\t\trecommended: true,\n\t\t},\n\t\tmessages: {\n\t\t\tnoLazyDestructuring:\n\t\t\t\t'Lazy destructuring (&[] / &{}) cannot be used in TypeScript/JavaScript modules. Use .value to read and write tracked values instead.',\n\t\t},\n\t\tschema: [],\n\t},\n\tcreate(context) {\n\t\tconst filename = context.filename;\n\n\t\t// Skip component files where lazy destructuring is valid\n\t\tif (filename && filename.endsWith('.tsrx')) {\n\t\t\treturn {};\n\t\t}\n\n\t\treturn {\n\t\t\tArrayPattern(node: any) {\n\t\t\t\tif (node.lazy === true) {\n\t\t\t\t\tcontext.report({\n\t\t\t\t\t\tnode,\n\t\t\t\t\t\tmessageId: 'noLazyDestructuring',\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\t\t\tObjectPattern(node: any) {\n\t\t\t\tif (node.lazy === true) {\n\t\t\t\t\tcontext.report({\n\t\t\t\t\t\tnode,\n\t\t\t\t\t\tmessageId: 'noLazyDestructuring',\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t},\n};\n\nexport default rule;\n","import type { Rule } from 'eslint';\nimport type * as AST from '@tsrx/core/types/estree';\nimport type { Scope } from 'eslint';\n\nconst rule: Rule.RuleModule = {\n\tmeta: {\n\t\ttype: 'problem',\n\t\tdocs: {\n\t\t\tdescription: 'Ensure variables used in for..of key expression are defined',\n\t\t\trecommended: true,\n\t\t},\n\t\tmessages: {\n\t\t\tundefinedVariable: \"Variable '{{name}}' is not defined.\",\n\t\t},\n\t\tschema: [],\n\t},\n\tcreate(context) {\n\t\treturn {\n\t\t\tForOfStatement(node: AST.ForOfStatement) {\n\t\t\t\tif (!node.key) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst checkIdentifier = (identifier: AST.Identifier) => {\n\t\t\t\t\tconst scope = context.sourceCode.getScope(node);\n\t\t\t\t\tconst variable = findVariable(scope, identifier.name);\n\n\t\t\t\t\tif (!variable) {\n\t\t\t\t\t\tcontext.report({\n\t\t\t\t\t\t\tnode: identifier,\n\t\t\t\t\t\t\tmessageId: 'undefinedVariable',\n\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\tname: identifier.name,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\tconst traverse = (node: AST.Node) => {\n\t\t\t\t\tif (!node) return;\n\n\t\t\t\t\tswitch (node.type) {\n\t\t\t\t\t\tcase 'Identifier':\n\t\t\t\t\t\t\tcheckIdentifier(node);\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'MemberExpression':\n\t\t\t\t\t\t\ttraverse(node.object);\n\n\t\t\t\t\t\t\tif (node.computed) {\n\t\t\t\t\t\t\t\ttraverse(node.property);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'BinaryExpression':\n\t\t\t\t\t\tcase 'LogicalExpression':\n\t\t\t\t\t\t\ttraverse(node.left);\n\t\t\t\t\t\t\ttraverse(node.right);\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'UnaryExpression':\n\t\t\t\t\t\t\ttraverse(node.argument);\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'CallExpression':\n\t\t\t\t\t\t\ttraverse(node.callee);\n\t\t\t\t\t\t\tnode.arguments.forEach(traverse);\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'ArrayExpression':\n\t\t\t\t\t\t\t(node.elements as (AST.Expression | AST.SpreadElement)[]).forEach(traverse);\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'ObjectExpression':\n\t\t\t\t\t\t\tnode.properties.forEach((prop: AST.Property | AST.SpreadElement) => {\n\t\t\t\t\t\t\t\tif (prop.type === 'Property') {\n\t\t\t\t\t\t\t\t\tif (prop.computed) {\n\t\t\t\t\t\t\t\t\t\ttraverse(prop.key);\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\ttraverse(prop.value);\n\t\t\t\t\t\t\t\t} else if (prop.type === 'SpreadElement') {\n\t\t\t\t\t\t\t\t\ttraverse(prop.argument);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'ConditionalExpression':\n\t\t\t\t\t\t\ttraverse(node.test);\n\t\t\t\t\t\t\ttraverse(node.consequent);\n\t\t\t\t\t\t\ttraverse(node.alternate);\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'TemplateLiteral':\n\t\t\t\t\t\t\tnode.expressions.forEach(traverse);\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\ttraverse(node.key);\n\t\t\t},\n\t\t};\n\t},\n};\n\nfunction findVariable(scope: Scope.Scope, name: string) {\n\tlet currentScope: Scope.Scope | null = scope;\n\n\twhile (currentScope) {\n\t\tconst variable = currentScope.variables.find((v: { name: string }) => v.name === name);\n\n\t\tif (variable) {\n\t\t\treturn variable;\n\t\t}\n\n\t\t// Also check references for global variables or variables defined in the loop itself (like the loop variable)\n\t\t// The loop variable might not be in the 'variables' list of the surrounding scope yet if we are inside the loop statement\n\t\t// But for 'for-of', the loop variable is in a special scope or the upper scope.\n\t\t// Let's rely on standard scope analysis.\n\n\t\t// Special case: check if the variable is the loop variable itself (left side of for-of)\n\t\t// The scope analysis might handle this, but let's be sure.\n\n\t\tcurrentScope = currentScope.upper;\n\t}\n\n\t// If not found in scopes, it might be a global variable.\n\t// ESLint scope analysis usually includes globals in the global scope.\n\t// However, if we are in a module, we might need to check if it's an implicit global or defined elsewhere.\n\t// For now, let's assume standard scope resolution works.\n\n\treturn null;\n}\n\nexport default rule;\n","import { createRequire } from 'module';\nimport noModuleScopeTrack from './rules/no-module-scope-track.js';\nimport preferOnInput from './rules/prefer-oninput.js';\nimport noReturnInComponent from './rules/no-return-in-component.js';\nimport controlFlowJsx from './rules/control-flow-jsx.js';\nimport noLazyDestructuringInModules from './rules/no-lazy-destructuring-in-modules.js';\nimport validForOfKey from './rules/valid-for-of-key.js';\n\nconst plugin = {\n\tmeta: {\n\t\tname: '@tsrx/eslint-plugin',\n\t\tversion: '0.1.3',\n\t},\n\trules: {\n\t\t'no-module-scope-track': noModuleScopeTrack,\n\t\t'prefer-oninput': preferOnInput,\n\t\t'no-return-in-component': noReturnInComponent,\n\t\t'control-flow-jsx': controlFlowJsx,\n\t\t'no-lazy-destructuring-in-modules': noLazyDestructuringInModules,\n\t\t'valid-for-of-key': validForOfKey,\n\t},\n\tconfigs: {} as any,\n};\n\n// Try to load optional parsers\nconst require = createRequire(import.meta.url);\n\nlet rippleParser: any;\nlet tsParser: any;\n\ntry {\n\trippleParser = require('@tsrx/eslint-parser');\n} catch {\n\t// @tsrx/eslint-parser is optional\n\trippleParser = null;\n}\n\ntry {\n\ttsParser = require('@typescript-eslint/parser');\n} catch {\n\t// @typescript-eslint/parser is optional\n\ttsParser = null;\n}\n\n// Helper to create config objects\nfunction createConfig(name: string, files: string[], parser: any) {\n\tconst config: any = {\n\t\tname,\n\t\tfiles,\n\t\tplugins: {\n\t\t\tripple: plugin,\n\t\t},\n\t\trules: {\n\t\t\t'ripple/no-module-scope-track': 'error',\n\t\t\t'ripple/prefer-oninput': 'warn',\n\t\t\t'ripple/no-return-in-component': 'error',\n\t\t\t'ripple/control-flow-jsx': 'error',\n\t\t\t'ripple/no-lazy-destructuring-in-modules': 'error',\n\t\t\t'ripple/valid-for-of-key': 'error',\n\t\t},\n\t};\n\n\t// Only add parser if it's available\n\tif (parser) {\n\t\tconfig.languageOptions = {\n\t\t\tparser,\n\t\t\tparserOptions: {\n\t\t\t\tecmaVersion: 'latest',\n\t\t\t\tsourceType: 'module',\n\t\t\t},\n\t\t};\n\t}\n\n\treturn config;\n}\n\n// Recommended configuration (flat config format)\nplugin.configs.recommended = [\n\tcreateConfig('ripple/recommended-ripple-files', ['**/*.tsrx'], rippleParser),\n\tcreateConfig('ripple/recommended-typescript-files', ['**/*.ts', '**/*.tsx'], tsParser),\n\t{\n\t\tname: 'ripple/ignores',\n\t\tignores: ['**/*.d.ts', '**/node_modules/**', '**/dist/**', '**/build/**'],\n\t},\n];\n\n// Strict configuration (flat config format)\nplugin.configs.strict = [\n\tcreateConfig('ripple/strict-ripple-files', ['**/*.tsrx'], rippleParser),\n\tcreateConfig('ripple/strict-typescript-files', ['**/*.ts', '**/*.tsx'], tsParser),\n\t{\n\t\tname: 'ripple/ignores',\n\t\tignores: ['**/*.d.ts', '**/node_modules/**', '**/dist/**', '**/build/**'],\n\t},\n];\n\nexport default plugin;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["rule","rule","rule","functionNode","rule","rule","noModuleScopeTrack","preferOnInput","noReturnInComponent","controlFlowJsx","noLazyDestructuringInModules","validForOfKey"],"sources":["../src/rules/no-module-scope-track.ts","../src/rules/prefer-oninput.ts","../src/rules/no-return-in-component.ts","../src/utils/tsrx.ts","../src/rules/control-flow-jsx.ts","../src/rules/no-lazy-destructuring-in-modules.ts","../src/rules/valid-for-of-key.ts","../src/index.ts"],"sourcesContent":["import type { Rule } from 'eslint';\nimport type * as AST from '@tsrx/core/types/estree';\n\nconst rule: Rule.RuleModule = {\n\tmeta: {\n\t\ttype: 'problem',\n\t\tdocs: {\n\t\t\tdescription: 'Disallow calling track() at module scope',\n\t\t\trecommended: true,\n\t\t},\n\t\tmessages: {\n\t\t\tmoduleScope: 'track() cannot be called at module scope. Move it into a function body.',\n\t\t},\n\t\tschema: [],\n\t},\n\tcreate(context) {\n\t\tlet functionDepth = 0;\n\n\t\tconst incrementFunctionDepth = () => functionDepth++;\n\t\tconst decrementFunctionDepth = () => functionDepth--;\n\n\t\treturn {\n\t\t\tFunctionDeclaration: incrementFunctionDepth,\n\t\t\t'FunctionDeclaration:exit': decrementFunctionDepth,\n\t\t\tFunctionExpression: incrementFunctionDepth,\n\t\t\t'FunctionExpression:exit': decrementFunctionDepth,\n\t\t\tArrowFunctionExpression: incrementFunctionDepth,\n\t\t\t'ArrowFunctionExpression:exit': decrementFunctionDepth,\n\n\t\t\t// Check track() calls\n\t\t\tCallExpression(node: AST.CallExpression) {\n\t\t\t\tif (\n\t\t\t\t\tnode.callee.type === 'Identifier' &&\n\t\t\t\t\tnode.callee.name === 'track' &&\n\t\t\t\t\tfunctionDepth === 0\n\t\t\t\t) {\n\t\t\t\t\tcontext.report({\n\t\t\t\t\t\tnode,\n\t\t\t\t\t\tmessageId: 'moduleScope',\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t},\n};\n\nexport default rule;\n","import type { Rule } from 'eslint';\nimport type * as AST from '@tsrx/core/types/estree';\nimport type * as ESTreeJSX from '@tsrx/core/types/estree-jsx';\n\nconst rule: Rule.RuleModule = {\n\tmeta: {\n\t\ttype: 'suggestion',\n\t\tdocs: {\n\t\t\tdescription: 'Prefer onInput over onChange for form inputs in Ripple',\n\t\t\trecommended: true,\n\t\t},\n\t\tmessages: {\n\t\t\tpreferOnInput:\n\t\t\t\t'Use \"onInput\" instead of \"onChange\". Ripple does not have synthetic events like React.',\n\t\t},\n\t\tfixable: 'code',\n\t\tschema: [],\n\t},\n\tcreate(context) {\n\t\tconst reported_ranges = new Set<string>();\n\n\t\tfunction report_onchange(node: AST.Attribute | ESTreeJSX.JSXAttribute) {\n\t\t\tconst range = node.range;\n\t\t\tif (!range) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst key = `${range[0]}:${range[1]}`;\n\t\t\tif (reported_ranges.has(key)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\treported_ranges.add(key);\n\n\t\t\tcontext.report({\n\t\t\t\tnode,\n\t\t\t\tmessageId: 'preferOnInput',\n\t\t\t\tfix(fixer) {\n\t\t\t\t\treturn fixer.replaceText(node.name, 'onInput');\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\treturn {\n\t\t\t// Check JSX attributes (standard JSX)\n\t\t\t'JSXAttribute[name.name=\"onChange\"]'(node: ESTreeJSX.JSXAttribute) {\n\t\t\t\treport_onchange(node);\n\t\t\t},\n\t\t\t// Check Attribute nodes (Ripple parser)\n\t\t\t'Attribute[name.name=\"onChange\"]'(node: AST.Attribute) {\n\t\t\t\treport_onchange(node);\n\t\t\t},\n\t\t\t// Check object properties (for spread props)\n\t\t\t'Property[key.name=\"onChange\"]'(node: AST.Property) {\n\t\t\t\t// Only report if this looks like it's in a props object\n\t\t\t\tconst ancestors = context.sourceCode.getAncestors(node);\n\t\t\t\tconst inObjectExpression = ancestors.some(\n\t\t\t\t\t(ancestor) => ancestor.type === 'ObjectExpression',\n\t\t\t\t);\n\n\t\t\t\tif (inObjectExpression) {\n\t\t\t\t\tcontext.report({\n\t\t\t\t\t\tnode,\n\t\t\t\t\t\tmessageId: 'preferOnInput',\n\t\t\t\t\t\tfix(fixer) {\n\t\t\t\t\t\t\treturn fixer.replaceText(node.key, 'onInput');\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t},\n};\n\nexport default rule;\n","import type { Rule } from 'eslint';\n\nconst rule: Rule.RuleModule = {\n\tmeta: {\n\t\ttype: 'problem',\n\t\tdocs: {\n\t\t\tdescription: 'Deprecated: TSRX components are functions that return native TSRX expressions.',\n\t\t\trecommended: false,\n\t\t},\n\t\tdeprecated: true,\n\t\tmessages: {\n\t\t\tnoReturn: 'TSRX components should return native TSRX expressions.',\n\t\t},\n\t\tschema: [],\n\t},\n\tcreate(context) {\n\t\tvoid context;\n\t\treturn {};\n\t},\n};\n\nexport default rule;\n","import type * as AST from '@tsrx/core/types/estree';\n\ntype AnyNode = AST.Node & Record<string, any>;\n\nconst NESTED_BOUNDARY_TYPES = new Set([\n\t'FunctionDeclaration',\n\t'FunctionExpression',\n\t'ArrowFunctionExpression',\n\t'ClassDeclaration',\n\t'ClassExpression',\n\t'MethodDefinition',\n\t'PropertyDefinition',\n\t'StaticBlock',\n]);\n\nexport function isNativeTsrxNode(node: AST.Node | null | undefined): boolean {\n\treturn node?.type === 'Element' || node?.type === 'Tsrx';\n}\n\nexport function functionReturnsNativeTsrx(node: AST.Node): boolean {\n\tconst functionNode = node as AnyNode;\n\tconst body = functionNode.body as AnyNode | undefined;\n\n\tif (!body) {\n\t\treturn false;\n\t}\n\n\tif (isNativeTsrxNode(body)) {\n\t\treturn true;\n\t}\n\n\tif (body.type !== 'BlockStatement') {\n\t\treturn false;\n\t}\n\n\treturn containsNativeTsrxReturn(body);\n}\n\nfunction containsNativeTsrxReturn(node: AnyNode): boolean {\n\tif (!node || typeof node !== 'object') {\n\t\treturn false;\n\t}\n\n\tif (node.type === 'ReturnStatement' && isNativeTsrxNode(node.argument)) {\n\t\treturn true;\n\t}\n\n\tif (node.type !== 'BlockStatement' && NESTED_BOUNDARY_TYPES.has(node.type)) {\n\t\treturn false;\n\t}\n\n\tfor (const key of Object.keys(node)) {\n\t\tif (key === 'parent' || key === 'loc' || key === 'range') {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst value = node[key];\n\t\tif (Array.isArray(value)) {\n\t\t\tfor (const child of value) {\n\t\t\t\tif (child?.type && containsNativeTsrxReturn(child)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (value?.type && containsNativeTsrxReturn(value)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n","import type { Rule } from 'eslint';\nimport type * as AST from '@tsrx/core/types/estree';\nimport { functionReturnsNativeTsrx, isNativeTsrxNode } from '../utils/tsrx.js';\n\nconst rule: Rule.RuleModule = {\n\tmeta: {\n\t\ttype: 'problem',\n\t\tdocs: {\n\t\t\tdescription:\n\t\t\t\t'Require JSX in for...of loops within components, but disallow JSX in for...of loops within effects',\n\t\t\trecommended: true,\n\t\t},\n\t\tmessages: {\n\t\t\trequireJsxInLoop:\n\t\t\t\t'For...of loops in returned TSRX should contain JSX elements. Use JSX to render items.',\n\t\t\tnoJsxInEffectLoop:\n\t\t\t\t'For...of loops inside effect() should not contain JSX. Effects are for side effects, not rendering.',\n\t\t},\n\t\tschema: [],\n\t},\n\tcreate(context) {\n\t\tlet insideComponent = 0;\n\t\tlet insideEffect = 0;\n\t\tlet nonComponentFunctionDepth = 0;\n\t\tconst functionStack: boolean[] = [];\n\n\t\tfunction containsJSX(node: AST.Node, visited: Set<AST.Node> = new Set()): boolean {\n\t\t\tif (!node) return false;\n\n\t\t\t// Avoid infinite loops from circular references\n\t\t\tif (visited.has(node)) return false;\n\t\t\tvisited.add(node);\n\n\t\t\tif (\n\t\t\t\tnode.type === ('JSXElement' as string) ||\n\t\t\t\tnode.type === ('JSXFragment' as string) ||\n\t\t\t\tisNativeTsrxNode(node)\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tconst keys = Object.keys(node);\n\t\t\tfor (const key of keys) {\n\t\t\t\tif (key === 'parent' || key === 'loc' || key === 'range') {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst value = (node as any)[key];\n\t\t\t\tif (value && typeof value === 'object') {\n\t\t\t\t\tif (Array.isArray(value)) {\n\t\t\t\t\t\tfor (const item of value) {\n\t\t\t\t\t\t\tif (item && typeof item === 'object' && containsJSX(item, visited)) {\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (value.type && containsJSX(value, visited)) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\treturn {\n\t\t\tFunctionDeclaration: enterFunction,\n\t\t\t'FunctionDeclaration:exit': exitFunction,\n\t\t\tFunctionExpression: enterFunction,\n\t\t\t'FunctionExpression:exit': exitFunction,\n\t\t\tArrowFunctionExpression: enterFunction,\n\t\t\t'ArrowFunctionExpression:exit': exitFunction,\n\n\t\t\t\"CallExpression[callee.name='effect']\"() {\n\t\t\t\tinsideEffect++;\n\t\t\t},\n\t\t\t\"CallExpression[callee.name='effect']:exit\"() {\n\t\t\t\tinsideEffect--;\n\t\t\t},\n\n\t\t\tForOfStatement(node: AST.ForOfStatement) {\n\t\t\t\tif (insideComponent === 0) return;\n\n\t\t\t\tconst hasJSX = containsJSX(node.body);\n\n\t\t\t\tif (insideEffect > 0) {\n\t\t\t\t\tif (hasJSX) {\n\t\t\t\t\t\tcontext.report({\n\t\t\t\t\t\t\tnode,\n\t\t\t\t\t\t\tmessageId: 'noJsxInEffectLoop',\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t} else if (nonComponentFunctionDepth > 0) {\n\t\t\t\t\treturn;\n\t\t\t\t} else {\n\t\t\t\t\tif (!hasJSX) {\n\t\t\t\t\t\tcontext.report({\n\t\t\t\t\t\t\tnode,\n\t\t\t\t\t\t\tmessageId: 'requireJsxInLoop',\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\n\t\tfunction enterFunction(node: AST.Node) {\n\t\t\tconst isComponent = functionReturnsNativeTsrx(node);\n\t\t\tfunctionStack.push(isComponent);\n\n\t\t\tif (isComponent) {\n\t\t\t\tinsideComponent++;\n\t\t\t} else if (insideComponent > 0) {\n\t\t\t\tnonComponentFunctionDepth++;\n\t\t\t}\n\t\t}\n\n\t\tfunction exitFunction() {\n\t\t\tconst isComponent = functionStack.pop();\n\n\t\t\tif (isComponent) {\n\t\t\t\tinsideComponent--;\n\t\t\t} else if (insideComponent > 0) {\n\t\t\t\tnonComponentFunctionDepth--;\n\t\t\t}\n\t\t}\n\t},\n};\n\nexport default rule;\n","import type { Rule } from 'eslint';\n\nconst rule: Rule.RuleModule = {\n\tmeta: {\n\t\ttype: 'problem',\n\t\tdocs: {\n\t\t\tdescription: 'Disallow lazy destructuring (&[] / &{}) in TypeScript/JavaScript modules',\n\t\t\trecommended: true,\n\t\t},\n\t\tmessages: {\n\t\t\tnoLazyDestructuring:\n\t\t\t\t'Lazy destructuring (&[] / &{}) cannot be used in TypeScript/JavaScript modules. Use .value to read and write tracked values instead.',\n\t\t},\n\t\tschema: [],\n\t},\n\tcreate(context) {\n\t\tconst filename = context.filename;\n\n\t\t// Skip TSRX files where lazy destructuring is valid\n\t\tif (filename && filename.endsWith('.tsrx')) {\n\t\t\treturn {};\n\t\t}\n\n\t\treturn {\n\t\t\tArrayPattern(node: any) {\n\t\t\t\tif (node.lazy === true) {\n\t\t\t\t\tcontext.report({\n\t\t\t\t\t\tnode,\n\t\t\t\t\t\tmessageId: 'noLazyDestructuring',\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\t\t\tObjectPattern(node: any) {\n\t\t\t\tif (node.lazy === true) {\n\t\t\t\t\tcontext.report({\n\t\t\t\t\t\tnode,\n\t\t\t\t\t\tmessageId: 'noLazyDestructuring',\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t},\n};\n\nexport default rule;\n","import type { Rule } from 'eslint';\nimport type * as AST from '@tsrx/core/types/estree';\nimport type { Scope } from 'eslint';\n\nconst rule: Rule.RuleModule = {\n\tmeta: {\n\t\ttype: 'problem',\n\t\tdocs: {\n\t\t\tdescription: 'Ensure variables used in for..of key expression are defined',\n\t\t\trecommended: true,\n\t\t},\n\t\tmessages: {\n\t\t\tundefinedVariable: \"Variable '{{name}}' is not defined.\",\n\t\t},\n\t\tschema: [],\n\t},\n\tcreate(context) {\n\t\treturn {\n\t\t\tForOfStatement(node: AST.ForOfStatement) {\n\t\t\t\tif (!node.key) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst checkIdentifier = (identifier: AST.Identifier) => {\n\t\t\t\t\tconst scope = context.sourceCode.getScope(node);\n\t\t\t\t\tconst variable = findVariable(scope, identifier.name);\n\n\t\t\t\t\tif (!variable) {\n\t\t\t\t\t\tcontext.report({\n\t\t\t\t\t\t\tnode: identifier,\n\t\t\t\t\t\t\tmessageId: 'undefinedVariable',\n\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\tname: identifier.name,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\tconst traverse = (node: AST.Node) => {\n\t\t\t\t\tif (!node) return;\n\n\t\t\t\t\tswitch (node.type) {\n\t\t\t\t\t\tcase 'Identifier':\n\t\t\t\t\t\t\tcheckIdentifier(node);\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'MemberExpression':\n\t\t\t\t\t\t\ttraverse(node.object);\n\n\t\t\t\t\t\t\tif (node.computed) {\n\t\t\t\t\t\t\t\ttraverse(node.property);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'BinaryExpression':\n\t\t\t\t\t\tcase 'LogicalExpression':\n\t\t\t\t\t\t\ttraverse(node.left);\n\t\t\t\t\t\t\ttraverse(node.right);\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'UnaryExpression':\n\t\t\t\t\t\t\ttraverse(node.argument);\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'CallExpression':\n\t\t\t\t\t\t\ttraverse(node.callee);\n\t\t\t\t\t\t\tnode.arguments.forEach(traverse);\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'ArrayExpression':\n\t\t\t\t\t\t\t(node.elements as (AST.Expression | AST.SpreadElement)[]).forEach(traverse);\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'ObjectExpression':\n\t\t\t\t\t\t\tnode.properties.forEach((prop: AST.Property | AST.SpreadElement) => {\n\t\t\t\t\t\t\t\tif (prop.type === 'Property') {\n\t\t\t\t\t\t\t\t\tif (prop.computed) {\n\t\t\t\t\t\t\t\t\t\ttraverse(prop.key);\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\ttraverse(prop.value);\n\t\t\t\t\t\t\t\t} else if (prop.type === 'SpreadElement') {\n\t\t\t\t\t\t\t\t\ttraverse(prop.argument);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'ConditionalExpression':\n\t\t\t\t\t\t\ttraverse(node.test);\n\t\t\t\t\t\t\ttraverse(node.consequent);\n\t\t\t\t\t\t\ttraverse(node.alternate);\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'TemplateLiteral':\n\t\t\t\t\t\t\tnode.expressions.forEach(traverse);\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\ttraverse(node.key);\n\t\t\t},\n\t\t};\n\t},\n};\n\nfunction findVariable(scope: Scope.Scope, name: string) {\n\tlet currentScope: Scope.Scope | null = scope;\n\n\twhile (currentScope) {\n\t\tconst variable = currentScope.variables.find((v: { name: string }) => v.name === name);\n\n\t\tif (variable) {\n\t\t\treturn variable;\n\t\t}\n\n\t\t// Also check references for global variables or variables defined in the loop itself (like the loop variable)\n\t\t// The loop variable might not be in the 'variables' list of the surrounding scope yet if we are inside the loop statement\n\t\t// But for 'for-of', the loop variable is in a special scope or the upper scope.\n\t\t// Let's rely on standard scope analysis.\n\n\t\t// Special case: check if the variable is the loop variable itself (left side of for-of)\n\t\t// The scope analysis might handle this, but let's be sure.\n\n\t\tcurrentScope = currentScope.upper;\n\t}\n\n\t// If not found in scopes, it might be a global variable.\n\t// ESLint scope analysis usually includes globals in the global scope.\n\t// However, if we are in a module, we might need to check if it's an implicit global or defined elsewhere.\n\t// For now, let's assume standard scope resolution works.\n\n\treturn null;\n}\n\nexport default rule;\n","import { createRequire } from 'module';\nimport noModuleScopeTrack from './rules/no-module-scope-track.js';\nimport preferOnInput from './rules/prefer-oninput.js';\nimport noReturnInComponent from './rules/no-return-in-component.js';\nimport controlFlowJsx from './rules/control-flow-jsx.js';\nimport noLazyDestructuringInModules from './rules/no-lazy-destructuring-in-modules.js';\nimport validForOfKey from './rules/valid-for-of-key.js';\n\nconst plugin = {\n\tmeta: {\n\t\tname: '@tsrx/eslint-plugin',\n\t\tversion: '0.1.3',\n\t},\n\trules: {\n\t\t'no-module-scope-track': noModuleScopeTrack,\n\t\t'prefer-oninput': preferOnInput,\n\t\t'no-return-in-component': noReturnInComponent,\n\t\t'control-flow-jsx': controlFlowJsx,\n\t\t'no-lazy-destructuring-in-modules': noLazyDestructuringInModules,\n\t\t'valid-for-of-key': validForOfKey,\n\t},\n\tconfigs: {} as any,\n};\n\n// Try to load optional parsers\nconst require = createRequire(import.meta.url);\n\nlet rippleParser: any;\nlet tsParser: any;\n\ntry {\n\trippleParser = require('@tsrx/eslint-parser');\n} catch {\n\t// @tsrx/eslint-parser is optional\n\trippleParser = null;\n}\n\ntry {\n\ttsParser = require('@typescript-eslint/parser');\n} catch {\n\t// @typescript-eslint/parser is optional\n\ttsParser = null;\n}\n\n// Helper to create config objects\nfunction createConfig(name: string, files: string[], parser: any) {\n\tconst config: any = {\n\t\tname,\n\t\tfiles,\n\t\tplugins: {\n\t\t\tripple: plugin,\n\t\t},\n\t\trules: {\n\t\t\t'ripple/no-module-scope-track': 'error',\n\t\t\t'ripple/prefer-oninput': 'warn',\n\t\t\t'ripple/control-flow-jsx': 'error',\n\t\t\t'ripple/no-lazy-destructuring-in-modules': 'error',\n\t\t\t'ripple/valid-for-of-key': 'error',\n\t\t},\n\t};\n\n\t// Only add parser if it's available\n\tif (parser) {\n\t\tconfig.languageOptions = {\n\t\t\tparser,\n\t\t\tparserOptions: {\n\t\t\t\tecmaVersion: 'latest',\n\t\t\t\tsourceType: 'module',\n\t\t\t},\n\t\t};\n\t}\n\n\treturn config;\n}\n\n// Recommended configuration (flat config format)\nplugin.configs.recommended = [\n\tcreateConfig('ripple/recommended-ripple-files', ['**/*.tsrx'], rippleParser),\n\tcreateConfig('ripple/recommended-typescript-files', ['**/*.ts', '**/*.tsx'], tsParser),\n\t{\n\t\tname: 'ripple/ignores',\n\t\tignores: ['**/*.d.ts', '**/node_modules/**', '**/dist/**', '**/build/**'],\n\t},\n];\n\n// Strict configuration (flat config format)\nplugin.configs.strict = [\n\tcreateConfig('ripple/strict-ripple-files', ['**/*.tsrx'], rippleParser),\n\tcreateConfig('ripple/strict-typescript-files', ['**/*.ts', '**/*.tsx'], tsParser),\n\t{\n\t\tname: 'ripple/ignores',\n\t\tignores: ['**/*.d.ts', '**/node_modules/**', '**/dist/**', '**/build/**'],\n\t},\n];\n\nexport default plugin;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tsrx/eslint-plugin",
3
- "version": "0.3.68",
3
+ "version": "0.3.69",
4
4
  "description": "ESLint plugin for Ripple",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -33,7 +33,7 @@
33
33
  "peerDependencies": {
34
34
  "eslint": ">=9.0.0",
35
35
  "@typescript-eslint/parser": "^8.56.1",
36
- "@tsrx/eslint-parser": "0.3.68"
36
+ "@tsrx/eslint-parser": "0.3.69"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/eslint": "^9.6.1",
@@ -43,8 +43,8 @@
43
43
  "tsdown": "^0.22.0",
44
44
  "typescript": "^5.9.3",
45
45
  "vitest": "^4.1.6",
46
- "@tsrx/eslint-parser": "0.3.68",
47
- "@tsrx/core": "0.1.16"
46
+ "@tsrx/eslint-parser": "0.3.69",
47
+ "@tsrx/core": "0.1.17"
48
48
  },
49
49
  "engines": {
50
50
  "node": ">=22.0.0"
package/src/index.ts CHANGED
@@ -53,7 +53,6 @@ function createConfig(name: string, files: string[], parser: any) {
53
53
  rules: {
54
54
  'ripple/no-module-scope-track': 'error',
55
55
  'ripple/prefer-oninput': 'warn',
56
- 'ripple/no-return-in-component': 'error',
57
56
  'ripple/control-flow-jsx': 'error',
58
57
  'ripple/no-lazy-destructuring-in-modules': 'error',
59
58
  'ripple/valid-for-of-key': 'error',