Skip to content

Commit 5f0e73a

Browse files
committed
working v1
1 parent f069f5a commit 5f0e73a

File tree

3 files changed

+59
-6
lines changed

3 files changed

+59
-6
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
'use client';
2+
import { useScopedUI } from '@react-zero-ui/core';
3+
4+
/**
5+
* This component is intentionally WRONG.
6+
* – Missing data-attr on <section>
7+
* – Missing ref attachment on <aside>
8+
*
9+
* The Zero-UI ESLint rule should flag both.
10+
*/
11+
export default function LintFailures() {
12+
// #1 Setter attached but no data-scope attr → missingAttr error
13+
const [scope, setScope] = useScopedUI<'off' | 'on'>('scope', 'off');
14+
15+
// #2 No ref at all → missingRef error
16+
const [, setDialog] = useScopedUI<'open' | 'closed'>('dialog', 'closed');
17+
18+
return (
19+
<main className="space-y-6 p-6">
20+
{/* ❌ lint error expected here */}
21+
<section
22+
ref={setScope.ref}
23+
className="scope-off:bg-red-100 scope-on:bg-red-600 scope-on:text-white p-4 rounded">
24+
<button
25+
className="border px-3 py-1"
26+
onClick={() => setScope((prev) => (prev === 'on' ? 'off' : 'on'))}>
27+
Toggle scope
28+
</button>
29+
</section>
30+
31+
{/* ❌ second lint error (missing .ref) */}
32+
<aside className="dialog-open:block dialog-closed:hidden">
33+
This dialog was never linked via <code>ref</code>
34+
</aside>
35+
</main>
36+
);
37+
}
38+
39+
/* ------------------------------------------------------------------ *
40+
| Correct version (for reference) |
41+
* ------------------------------------------------------------------ *
42+
const [scope, setScope] = useScopedUI<'off' | 'on'>('scope', 'off');
43+
<section
44+
data-scope={scope}
45+
ref={setScope.ref}
46+
>
47+
48+
</section>
49+
50+
const [, setDialog] = useScopedUI<'open'|'closed'>('dialog','closed');
51+
<aside ref={setDialog.ref} data-dialog="closed">…</aside>
52+
*/

packages/eslint-plugin-react-zero-ui/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
],
1313
"scripts": {
1414
"build": "tsc -p tsconfig.json",
15-
"prepack": "pnpm build"
15+
"prepack": "pnpm build",
16+
"prepare": "pnpm run build"
1617
},
1718
"peerDependencies": {
1819
"eslint": "^9 || ^8",

packages/eslint-plugin-react-zero-ui/src/rules/require-data-attr.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ import { ESLintUtils, TSESTree as T } from '@typescript-eslint/utils';
22

33
const createRule = ESLintUtils.RuleCreator((name) => `https://github.com/serbyte/eslint-plugin-react-zero-ui/blob/main/docs/${name}.md`);
44

5+
// At top of create()
6+
const hookLoc = new Map<string /*setter*/, T.SourceLocation>();
7+
58
export default createRule({
69
name: 'require-data-attr',
710
meta: {
@@ -46,6 +49,7 @@ export default createRule({
4649
if (!keyArg || keyArg.type !== 'Literal' || typeof keyArg.value !== 'string') return;
4750

4851
scopedSetters.set(setter.name, keyArg.value);
52+
hookLoc.set(setter.name, node.loc!);
4953
},
5054

5155
//----------------------------------------------------------------
@@ -81,11 +85,7 @@ export default createRule({
8185
'Program:exit'() {
8286
for (const [setter, key] of scopedSetters) {
8387
if (!seenRef.has(setter)) {
84-
ctx.report({
85-
messageId: 'missingRef',
86-
loc: ctx.getScope().block.loc!, // entire file
87-
data: { setter, key },
88-
});
88+
ctx.report({ messageId: 'missingRef', loc: hookLoc.get(setter)!, data: { setter, key } });
8989
}
9090
}
9191
},

0 commit comments

Comments
 (0)