@ripple-ts/eslint-plugin 0.2.216 → 0.3.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/README.md +9 -13
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -13
- package/dist/index.js.map +1 -1
- package/package.json +10 -10
- package/dist/index-DcKta1tZ.d.ts +0 -22
- package/dist/index-DcKta1tZ.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -90,10 +90,8 @@ a component context.
|
|
|
90
90
|
❌ **Incorrect:**
|
|
91
91
|
|
|
92
92
|
```js
|
|
93
|
-
import { track } from 'ripple';
|
|
94
|
-
|
|
95
93
|
// This will cause runtime errors
|
|
96
|
-
let globalCount = track(0);
|
|
94
|
+
let globalCount = #ripple.track(0);
|
|
97
95
|
|
|
98
96
|
export component App() {
|
|
99
97
|
<div>{@globalCount}</div>
|
|
@@ -103,11 +101,9 @@ export component App() {
|
|
|
103
101
|
✅ **Correct:**
|
|
104
102
|
|
|
105
103
|
```js
|
|
106
|
-
import { track } from 'ripple';
|
|
107
|
-
|
|
108
104
|
export component App() {
|
|
109
105
|
// track() called within component
|
|
110
|
-
let count = track(0);
|
|
106
|
+
let count = #ripple.track(0);
|
|
111
107
|
|
|
112
108
|
<div>{@count}</div>
|
|
113
109
|
}
|
|
@@ -184,7 +180,7 @@ expressions.
|
|
|
184
180
|
|
|
185
181
|
```js
|
|
186
182
|
export component App() {
|
|
187
|
-
let count = track(0);
|
|
183
|
+
let count = #ripple.track(0);
|
|
188
184
|
|
|
189
185
|
// Missing @ operator
|
|
190
186
|
<div>{count}</div>
|
|
@@ -195,7 +191,7 @@ export component App() {
|
|
|
195
191
|
|
|
196
192
|
```js
|
|
197
193
|
export component App() {
|
|
198
|
-
let count = track(0);
|
|
194
|
+
let count = #ripple.track(0);
|
|
199
195
|
|
|
200
196
|
// Properly unboxed with @
|
|
201
197
|
<div>{@count}</div>
|
|
@@ -212,8 +208,8 @@ Prevents using the `@` introspection operator in TypeScript/JavaScript modules.
|
|
|
212
208
|
```ts
|
|
213
209
|
// count.ts
|
|
214
210
|
export function useCount() {
|
|
215
|
-
const count = track(1);
|
|
216
|
-
effect(() => {
|
|
211
|
+
const count = #ripple.track(1);
|
|
212
|
+
#ripple.effect(() => {
|
|
217
213
|
console.log(@count); // Error: Cannot use @ in TypeScript modules
|
|
218
214
|
});
|
|
219
215
|
return { count };
|
|
@@ -227,12 +223,12 @@ export function useCount() {
|
|
|
227
223
|
import { get, set } from 'ripple';
|
|
228
224
|
|
|
229
225
|
export function useCount() {
|
|
230
|
-
const count = track(1);
|
|
226
|
+
const count = #ripple.track(1);
|
|
231
227
|
|
|
232
228
|
// Use get() to read tracked values
|
|
233
|
-
const double =
|
|
229
|
+
const double = #ripple.track(() => get(count) * 2);
|
|
234
230
|
|
|
235
|
-
effect(() => {
|
|
231
|
+
#ripple.effect(() => {
|
|
236
232
|
console.log('count is', get(count));
|
|
237
233
|
});
|
|
238
234
|
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as eslint from "eslint";
|
|
2
|
+
|
|
3
|
+
//#region src/index.d.ts
|
|
4
|
+
declare const plugin: {
|
|
5
|
+
meta: {
|
|
6
|
+
name: string;
|
|
7
|
+
version: string;
|
|
8
|
+
};
|
|
9
|
+
rules: {
|
|
10
|
+
'no-module-scope-track': eslint.Rule.RuleModule;
|
|
11
|
+
'prefer-oninput': eslint.Rule.RuleModule;
|
|
12
|
+
'no-return-in-component': eslint.Rule.RuleModule;
|
|
13
|
+
'unbox-tracked-values': eslint.Rule.RuleModule;
|
|
14
|
+
'control-flow-jsx': eslint.Rule.RuleModule;
|
|
15
|
+
'no-introspect-in-modules': eslint.Rule.RuleModule;
|
|
16
|
+
'valid-for-of-key': eslint.Rule.RuleModule;
|
|
17
|
+
};
|
|
18
|
+
configs: any;
|
|
19
|
+
};
|
|
20
|
+
//#endregion
|
|
21
|
+
export { plugin as default };
|
|
22
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;cASM,MAAA"}
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,6 @@ const rule$6 = {
|
|
|
6
6
|
type: "problem",
|
|
7
7
|
docs: {
|
|
8
8
|
description: "Disallow calling track() at module scope",
|
|
9
|
-
category: "Possible Errors",
|
|
10
9
|
recommended: true
|
|
11
10
|
},
|
|
12
11
|
messages: { moduleScope: "track() cannot be called at module scope. It must be called within a component context." },
|
|
@@ -45,7 +44,6 @@ const rule$5 = {
|
|
|
45
44
|
type: "suggestion",
|
|
46
45
|
docs: {
|
|
47
46
|
description: "Prefer onInput over onChange for form inputs in Ripple",
|
|
48
|
-
category: "Best Practices",
|
|
49
47
|
recommended: true
|
|
50
48
|
},
|
|
51
49
|
messages: { preferOnInput: "Use \"onInput\" instead of \"onChange\". Ripple does not have synthetic events like React." },
|
|
@@ -54,9 +52,6 @@ const rule$5 = {
|
|
|
54
52
|
},
|
|
55
53
|
create(context) {
|
|
56
54
|
const reported_ranges = /* @__PURE__ */ new Set();
|
|
57
|
-
/**
|
|
58
|
-
* @param {any} node
|
|
59
|
-
*/
|
|
60
55
|
function report_onchange(node) {
|
|
61
56
|
const range = node.range;
|
|
62
57
|
if (!range) return;
|
|
@@ -98,7 +93,6 @@ const rule$4 = {
|
|
|
98
93
|
type: "problem",
|
|
99
94
|
docs: {
|
|
100
95
|
description: "Disallow return statements with JSX in Ripple components",
|
|
101
|
-
category: "Possible Errors",
|
|
102
96
|
recommended: true
|
|
103
97
|
},
|
|
104
98
|
messages: { noReturn: "Do not return JSX from Ripple components. Use JSX as statements instead." },
|
|
@@ -138,7 +132,6 @@ const rule$3 = {
|
|
|
138
132
|
type: "problem",
|
|
139
133
|
docs: {
|
|
140
134
|
description: "Ensure tracked values are unboxed with @ operator",
|
|
141
|
-
category: "Possible Errors",
|
|
142
135
|
recommended: true
|
|
143
136
|
},
|
|
144
137
|
messages: { needsUnbox: "Tracked value should be unboxed with @ operator. Did you mean \"@{{name}}\"?" },
|
|
@@ -150,7 +143,7 @@ const rule$3 = {
|
|
|
150
143
|
let parent = node.parent;
|
|
151
144
|
while (parent) {
|
|
152
145
|
const parentType = parent.type;
|
|
153
|
-
if (parentType === "JSXExpressionContainer" || parentType === "JSXElement" || parentType === "JSXFragment" || parentType === "
|
|
146
|
+
if (parentType === "JSXExpressionContainer" || parentType === "JSXElement" || parentType === "JSXFragment" || parentType === "Element") return true;
|
|
154
147
|
parent = parent.parent;
|
|
155
148
|
}
|
|
156
149
|
return false;
|
|
@@ -159,7 +152,7 @@ const rule$3 = {
|
|
|
159
152
|
if (trackedVariables.has(node.name) && isInJSXContext(node)) {
|
|
160
153
|
const parent = node.parent;
|
|
161
154
|
let isUnboxed = parent && parent.type === "TrackedExpression" || node.tracked === true;
|
|
162
|
-
if (!isUnboxed) isUnboxed = context.
|
|
155
|
+
if (!isUnboxed) isUnboxed = context.sourceCode.text.substring(Math.max(0, node.range[0] - 1), node.range[0]) === "@";
|
|
163
156
|
if (!isUnboxed) context.report({
|
|
164
157
|
node,
|
|
165
158
|
messageId: "needsUnbox",
|
|
@@ -185,12 +178,11 @@ const rule$2 = {
|
|
|
185
178
|
type: "problem",
|
|
186
179
|
docs: {
|
|
187
180
|
description: "Require JSX in for...of loops within components, but disallow JSX in for...of loops within effects",
|
|
188
|
-
category: "Possible Errors",
|
|
189
181
|
recommended: true
|
|
190
182
|
},
|
|
191
183
|
messages: {
|
|
192
184
|
requireJsxInLoop: "For...of loops in component bodies should contain JSX elements. Use JSX to render items.",
|
|
193
|
-
noJsxInEffectLoop: "For...of loops inside effect() should not contain JSX. Effects are for side effects, not rendering."
|
|
185
|
+
noJsxInEffectLoop: "For...of loops inside #ripple.effect() should not contain JSX. Effects are for side effects, not rendering."
|
|
194
186
|
},
|
|
195
187
|
schema: []
|
|
196
188
|
},
|
|
@@ -251,14 +243,13 @@ const rule$1 = {
|
|
|
251
243
|
type: "problem",
|
|
252
244
|
docs: {
|
|
253
245
|
description: "Disallow @ introspection operator in TypeScript/JavaScript modules",
|
|
254
|
-
category: "Possible Errors",
|
|
255
246
|
recommended: true
|
|
256
247
|
},
|
|
257
248
|
messages: { noIntrospect: "The @ operator cannot be used in TypeScript/JavaScript modules. Use get() to read tracked values and set() to update them instead." },
|
|
258
249
|
schema: []
|
|
259
250
|
},
|
|
260
251
|
create(context) {
|
|
261
|
-
const filename = context.filename
|
|
252
|
+
const filename = context.filename;
|
|
262
253
|
if (filename && filename.endsWith(".ripple")) return {};
|
|
263
254
|
return { Identifier(node) {
|
|
264
255
|
if (node.tracked === true) context.report({
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["rule","rule","rule","rule","rule","rule","noModuleScopeTrack","preferOnInput","noReturnInComponent","unboxTrackedValues","controlFlowJsx","noIntrospectInModules","validForOfKey"],"sources":["../src/rules/no-module-scope-track.ts","../src/rules/prefer-oninput.ts","../src/rules/no-return-in-component.ts","../src/rules/unbox-tracked-values.ts","../src/rules/control-flow-jsx.ts","../src/rules/no-introspect-in-modules.ts","../src/rules/valid-for-of-key.ts","../src/index.ts"],"sourcesContent":["import type { Rule } from 'eslint';\nimport type { CallExpression } from '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\tcategory: 'Possible Errors',\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: 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';\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\tcategory: 'Best Practices',\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\t/**\n\t\t * @param {any} node\n\t\t */\n\t\tfunction report_onchange(node: any) {\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: any) {\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: any) {\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: any) {\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 { ReturnStatement } from '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\tcategory: 'Possible Errors',\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: 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';\n\nconst rule: Rule.RuleModule = {\n\tmeta: {\n\t\ttype: 'problem',\n\t\tdocs: {\n\t\t\tdescription: 'Ensure tracked values are unboxed with @ operator',\n\t\t\tcategory: 'Possible Errors',\n\t\t\trecommended: true,\n\t\t},\n\t\tmessages: {\n\t\t\tneedsUnbox: 'Tracked value should be unboxed with @ operator. Did you mean \"@{{name}}\"?',\n\t\t},\n\t\tschema: [],\n\t},\n\tcreate(context) {\n\t\tconst trackedVariables = new Set<string>();\n\n\t\tfunction isInJSXContext(node: any): boolean {\n\t\t\tlet parent = node.parent;\n\n\t\t\t// Walk up the AST to find if we're inside JSX/Element\n\t\t\twhile (parent) {\n\t\t\t\tconst parentType = parent.type;\n\t\t\t\t// Check for JSX context\n\t\t\t\tif (\n\t\t\t\t\tparentType === 'JSXExpressionContainer' ||\n\t\t\t\t\tparentType === 'JSXElement' ||\n\t\t\t\t\tparentType === 'JSXFragment' ||\n\t\t\t\t\t// Check for Ripple Element context\n\t\t\t\t\tparentType === 'ExpressionContainer' ||\n\t\t\t\t\tparentType === 'Element'\n\t\t\t\t) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tparent = parent.parent;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tfunction checkTrackedIdentifier(node: any) {\n\t\t\tif (trackedVariables.has(node.name) && isInJSXContext(node)) {\n\t\t\t\tconst parent = node.parent;\n\t\t\t\tlet isUnboxed = (parent && parent.type === 'TrackedExpression') || node.tracked === true;\n\n\t\t\t\t// Fallback: check source code for @ character as the first character\n\t\t\t\tif (!isUnboxed) {\n\t\t\t\t\tconst sourceCode = context.getSourceCode();\n\t\t\t\t\tconst firstChar = sourceCode.text.substring(Math.max(0, node.range![0]), node.range![0]);\n\t\t\t\t\tisUnboxed = firstChar === '@';\n\t\t\t\t}\n\n\t\t\t\tif (!isUnboxed) {\n\t\t\t\t\tcontext.report({\n\t\t\t\t\t\tnode,\n\t\t\t\t\t\tmessageId: 'needsUnbox',\n\t\t\t\t\t\tdata: { name: node.name },\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\t// Track variables that are assigned from track()\n\t\t\t'VariableDeclarator[init.callee.name=\"track\"]'(node: any) {\n\t\t\t\tif (node.id.type === 'Identifier') {\n\t\t\t\t\ttrackedVariables.add(node.id.name);\n\t\t\t\t}\n\t\t\t},\n\t\t\t// Check all identifiers\n\t\t\tIdentifier(node: any) {\n\t\t\t\tcheckTrackedIdentifier(node);\n\t\t\t},\n\t\t};\n\t},\n};\n\nexport default rule;\n","import type { Rule } from 'eslint';\nimport type { ForOfStatement, Node } from '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\tcategory: 'Possible Errors',\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: Node, visited: Set<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: 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 @ introspection operator in TypeScript/JavaScript modules',\n\t\t\tcategory: 'Possible Errors',\n\t\t\trecommended: true,\n\t\t},\n\t\tmessages: {\n\t\t\tnoIntrospect:\n\t\t\t\t'The @ operator cannot be used in TypeScript/JavaScript modules. Use get() to read tracked values and set() to update them instead.',\n\t\t},\n\t\tschema: [],\n\t},\n\tcreate(context) {\n\t\tconst filename = context.filename || context.getFilename();\n\n\t\t// Skip .ripple files where @ operator is valid\n\t\tif (filename && filename.endsWith('.ripple')) {\n\t\t\treturn {};\n\t\t}\n\n\t\treturn {\n\t\t\t// Check for identifiers with the 'tracked' property\n\t\t\t// The @ operator is parsed by Ripple as an identifier with tracked=true\n\t\t\tIdentifier(node: any) {\n\t\t\t\tif (node.tracked === true) {\n\t\t\t\t\tcontext.report({\n\t\t\t\t\t\tnode,\n\t\t\t\t\t\tmessageId: 'noIntrospect',\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: '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: any) {\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: any) => {\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: any) => {\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\tnode.elements.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: any) => {\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: any, name: string) {\n\tlet currentScope = 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 unboxTrackedValues from './rules/unbox-tracked-values.js';\nimport controlFlowJsx from './rules/control-flow-jsx.js';\nimport noIntrospectInModules from './rules/no-introspect-in-modules.js';\nimport validForOfKey from './rules/valid-for-of-key.js';\n\nconst plugin = {\n\tmeta: {\n\t\tname: '@ripple-ts/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'unbox-tracked-values': unboxTrackedValues,\n\t\t'control-flow-jsx': controlFlowJsx,\n\t\t'no-introspect-in-modules': noIntrospectInModules,\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('@ripple-ts/eslint-parser');\n} catch {\n\t// @ripple-ts/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/unbox-tracked-values': 'error',\n\t\t\t'ripple/control-flow-jsx': 'error',\n\t\t\t'ripple/no-introspect-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', ['**/*.ripple'], 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', ['**/*.ripple'], 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","rule","rule","rule","noModuleScopeTrack","preferOnInput","noReturnInComponent","unboxTrackedValues","controlFlowJsx","noIntrospectInModules","validForOfKey"],"sources":["../src/rules/no-module-scope-track.ts","../src/rules/prefer-oninput.ts","../src/rules/no-return-in-component.ts","../src/rules/unbox-tracked-values.ts","../src/rules/control-flow-jsx.ts","../src/rules/no-introspect-in-modules.ts","../src/rules/valid-for-of-key.ts","../src/index.ts"],"sourcesContent":["import type { Rule } from 'eslint';\nimport type * as AST from 'ripple/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 'ripple/types/estree';\nimport type * as ESTreeJSX from 'ripple/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 'ripple/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 'ripple/types/estree';\n\nconst rule: Rule.RuleModule = {\n\tmeta: {\n\t\ttype: 'problem',\n\t\tdocs: {\n\t\t\tdescription: 'Ensure tracked values are unboxed with @ operator',\n\t\t\trecommended: true,\n\t\t},\n\t\tmessages: {\n\t\t\tneedsUnbox: 'Tracked value should be unboxed with @ operator. Did you mean \"@{{name}}\"?',\n\t\t},\n\t\tschema: [],\n\t},\n\tcreate(context) {\n\t\tconst trackedVariables = new Set<string>();\n\n\t\tfunction isInJSXContext(node: AST.Node & { parent: AST.Node }): boolean {\n\t\t\tlet parent = node.parent;\n\n\t\t\t// Walk up the AST to find if we're inside JSX/Element\n\t\t\twhile (parent) {\n\t\t\t\tconst parentType = parent.type;\n\t\t\t\t// Check for JSX context\n\t\t\t\tif (\n\t\t\t\t\tparentType === 'JSXExpressionContainer' ||\n\t\t\t\t\tparentType === 'JSXElement' ||\n\t\t\t\t\tparentType === 'JSXFragment' ||\n\t\t\t\t\t// Check for Ripple Element context\n\t\t\t\t\tparentType === 'Element'\n\t\t\t\t) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tparent = (parent as AST.Node & { parent: AST.Node }).parent;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tfunction checkTrackedIdentifier(node: AST.Identifier & { parent: AST.Node }) {\n\t\t\tif (trackedVariables.has(node.name) && isInJSXContext(node)) {\n\t\t\t\tconst parent = node.parent;\n\t\t\t\tlet isUnboxed = (parent && parent.type === 'TrackedExpression') || node.tracked === true;\n\n\t\t\t\t// Fallback: check source code for @ character as the first character\n\t\t\t\tif (!isUnboxed) {\n\t\t\t\t\tconst firstChar = context.sourceCode.text.substring(\n\t\t\t\t\t\tMath.max(0, node.range![0] - 1),\n\t\t\t\t\t\tnode.range![0],\n\t\t\t\t\t);\n\t\t\t\t\tisUnboxed = firstChar === '@';\n\t\t\t\t}\n\n\t\t\t\tif (!isUnboxed) {\n\t\t\t\t\tcontext.report({\n\t\t\t\t\t\tnode,\n\t\t\t\t\t\tmessageId: 'needsUnbox',\n\t\t\t\t\t\tdata: { name: node.name },\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\t// Track variables that are assigned from track()\n\t\t\t'VariableDeclarator[init.callee.name=\"track\"]'(node: AST.VariableDeclarator) {\n\t\t\t\tif (node.id.type === 'Identifier') {\n\t\t\t\t\ttrackedVariables.add(node.id.name);\n\t\t\t\t}\n\t\t\t},\n\t\t\t// Check all identifiers\n\t\t\tIdentifier(node: AST.Identifier & { parent: AST.Node }) {\n\t\t\t\tcheckTrackedIdentifier(node);\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 'ripple/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 #ripple.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';\nimport type * as AST from 'ripple/types/estree';\n\nconst rule: Rule.RuleModule = {\n\tmeta: {\n\t\ttype: 'problem',\n\t\tdocs: {\n\t\t\tdescription: 'Disallow @ introspection operator in TypeScript/JavaScript modules',\n\t\t\trecommended: true,\n\t\t},\n\t\tmessages: {\n\t\t\tnoIntrospect:\n\t\t\t\t'The @ operator cannot be used in TypeScript/JavaScript modules. Use get() to read tracked values and set() to update them instead.',\n\t\t},\n\t\tschema: [],\n\t},\n\tcreate(context) {\n\t\tconst filename = context.filename;\n\n\t\t// Skip .ripple files where @ operator is valid\n\t\tif (filename && filename.endsWith('.ripple')) {\n\t\t\treturn {};\n\t\t}\n\n\t\treturn {\n\t\t\t// Check for identifiers with the 'tracked' property\n\t\t\t// The @ operator is parsed by Ripple as an identifier with tracked=true\n\t\t\tIdentifier(node: AST.Identifier) {\n\t\t\t\tif (node.tracked === true) {\n\t\t\t\t\tcontext.report({\n\t\t\t\t\t\tnode,\n\t\t\t\t\t\tmessageId: 'noIntrospect',\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 'ripple/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 unboxTrackedValues from './rules/unbox-tracked-values.js';\nimport controlFlowJsx from './rules/control-flow-jsx.js';\nimport noIntrospectInModules from './rules/no-introspect-in-modules.js';\nimport validForOfKey from './rules/valid-for-of-key.js';\n\nconst plugin = {\n\tmeta: {\n\t\tname: '@ripple-ts/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'unbox-tracked-values': unboxTrackedValues,\n\t\t'control-flow-jsx': controlFlowJsx,\n\t\t'no-introspect-in-modules': noIntrospectInModules,\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('@ripple-ts/eslint-parser');\n} catch {\n\t// @ripple-ts/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/unbox-tracked-values': 'error',\n\t\t\t'ripple/control-flow-jsx': 'error',\n\t\t\t'ripple/no-introspect-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', ['**/*.ripple'], 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', ['**/*.ripple'], 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": "@ripple-ts/eslint-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "ESLint plugin for Ripple",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -32,19 +32,19 @@
|
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"eslint": ">=9.0.0",
|
|
35
|
-
"@typescript-eslint/parser": "^8.
|
|
36
|
-
"@ripple-ts/eslint-parser": "0.
|
|
35
|
+
"@typescript-eslint/parser": "^8.56.1",
|
|
36
|
+
"@ripple-ts/eslint-parser": "0.3.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/eslint": "^9.6.1",
|
|
40
|
-
"@types/estree": "^1.0.8",
|
|
41
40
|
"@types/node": "^24.3.0",
|
|
42
|
-
"@typescript-eslint/parser": "^8.
|
|
43
|
-
"eslint": "^
|
|
44
|
-
"tsdown": "^0.
|
|
45
|
-
"typescript": "^5.9.
|
|
46
|
-
"vitest": "^
|
|
47
|
-
"@ripple-ts/eslint-parser": "0.
|
|
41
|
+
"@typescript-eslint/parser": "^8.56.1",
|
|
42
|
+
"eslint": "^10.0.2",
|
|
43
|
+
"tsdown": "^0.20.3",
|
|
44
|
+
"typescript": "^5.9.3",
|
|
45
|
+
"vitest": "^4.0.18",
|
|
46
|
+
"@ripple-ts/eslint-parser": "0.3.0",
|
|
47
|
+
"ripple": "0.3.0"
|
|
48
48
|
},
|
|
49
49
|
"engines": {
|
|
50
50
|
"node": ">=20.0.0"
|
package/dist/index-DcKta1tZ.d.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import * as eslint0 from "eslint";
|
|
2
|
-
|
|
3
|
-
//#region src/index.d.ts
|
|
4
|
-
declare const plugin: {
|
|
5
|
-
meta: {
|
|
6
|
-
name: string;
|
|
7
|
-
version: string;
|
|
8
|
-
};
|
|
9
|
-
rules: {
|
|
10
|
-
'no-module-scope-track': eslint0.Rule.RuleModule;
|
|
11
|
-
'prefer-oninput': eslint0.Rule.RuleModule;
|
|
12
|
-
'no-return-in-component': eslint0.Rule.RuleModule;
|
|
13
|
-
'unbox-tracked-values': eslint0.Rule.RuleModule;
|
|
14
|
-
'control-flow-jsx': eslint0.Rule.RuleModule;
|
|
15
|
-
'no-introspect-in-modules': eslint0.Rule.RuleModule;
|
|
16
|
-
'valid-for-of-key': eslint0.Rule.RuleModule;
|
|
17
|
-
};
|
|
18
|
-
configs: any;
|
|
19
|
-
};
|
|
20
|
-
//#endregion
|
|
21
|
-
export { plugin as default };
|
|
22
|
-
//# sourceMappingURL=index-DcKta1tZ.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-DcKta1tZ.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;;cASM;;;IAAA,OAeL,EAAA,MAAA;EAAA,CAAA"}
|