@round-core/lint 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,14 @@
1
+ # @round-core/lint
2
+
3
+ ESLint plugin for RoundJS. Enables linting for `.round` files using standard JavaScript parsers (espree).
4
+
5
+ ## How it works
6
+
7
+ 1. **Preprocessing**: Transforms the `.round` file into valid JSX.
8
+ 2. **Global Injection**: Automatically detects loop variables (like `t` in `for(t in list)`) and injects `/* globals */` comments at the end of the file to prevent "undefined variable" errors.
9
+ 3. **Component Tracking**: Identifies JSX-style component usage within RoundJS blocks and ensures ESLint doesn't mark them as unused variables.
10
+ 4. **1:1 Mapping**: Using the `SourceMapper`, ESLint reported errors are translated back to the original `.round` file lines and columns, ensuring perfectly aligned highlights in VS Code.
11
+
12
+ ## Configuration
13
+
14
+ Recommended usage is via the `eslint.config.js` generated by the RoundJS CLI.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@round-core/lint",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "ESLint processor for RoundJS files",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/processor.js CHANGED
@@ -4,14 +4,8 @@ import { remapMessages } from './offset-map.js';
4
4
 
5
5
  export default {
6
6
  preprocess(code, filename) {
7
- const mapper = new SourceMapper();
8
- runPreprocess(code, mapper, 0);
9
-
10
- // MAGIC: Suppress false positives for RoundJS syntax without react-plugin
11
-
12
- // 1. Identify top-level names (imports and declarations)
13
7
  const topLevelNames = new Set();
14
- const declMatches = mapper.code.matchAll(/^\s*(?:export\s+)?(?:function|const|let|var|class|import)\s+({[\s\S]*?}|[a-zA-Z0-9_$]+)/gm);
8
+ const declMatches = code.matchAll(/^\s*(?:export\s+)?(?:function|const|let|var|class|import)\s+({[\s\S]*?}|[a-zA-Z0-9_$]+)/gm);
15
9
  for (const m of declMatches) {
16
10
  const inner = m[1];
17
11
  if (inner.startsWith('{')) {
@@ -22,21 +16,28 @@ export default {
22
16
  }
23
17
  }
24
18
 
25
- // 2. Mark components used in JSX as "used"
26
- const cleanForComponents = mapper.code.replace(/`[\s\S]*?`/g, '');
27
- const componentMatches = cleanForComponents.matchAll(/<([A-Z][a-zA-Z0-9_$]*)/g);
19
+ const componentMatches = code.matchAll(/<([A-Z][a-zA-Z0-9_$]*)/g);
28
20
  const components = new Set([...componentMatches].map(m => m[1]));
29
21
 
30
- let magic = '\n\n/* eslint-disable */\n/* globals RoundControlFlow, e, item */\n;';
31
-
32
- // Usage for top-level components only
22
+ // Dynamic Global Injection for for/catch variables
23
+ const magicVars = new Set(['RoundControlFlow', 'Fragment']);
24
+ const forMatches = code.matchAll(/\{for\s*\(\s*([a-zA-Z0-9_$]+)/g);
25
+ for (const m of forMatches) magicVars.add(m[1]);
26
+ const catchMatches = code.matchAll(/catch\s*\(\s*([a-zA-Z0-9_$]+)/g);
27
+ for (const m of catchMatches) magicVars.add(m[1]);
28
+
29
+ const globalsList = Array.from(magicVars).join(', ');
30
+ let magic = `/* globals ${globalsList} */\n(void RoundControlFlow); (void Fragment);`;
33
31
  for (const comp of components) {
34
32
  if (topLevelNames.has(comp)) {
35
- magic += `${comp};`;
33
+ magic += ` (void ${comp});`;
36
34
  }
37
35
  }
38
-
39
- mapper.add(magic, code.length);
36
+ magic += '\n';
37
+
38
+ const mapper = new SourceMapper();
39
+ runPreprocess(code, mapper, 0);
40
+ mapper.add('\n' + magic, code.length);
40
41
 
41
42
  fileState.set(filename, {
42
43
  source: code,
@@ -49,10 +50,6 @@ export default {
49
50
  postprocess(messages, filename) {
50
51
  const state = fileState.get(filename);
51
52
 
52
- // Clean up state (optional, but good for memory if ESLint is long running)
53
- // However, ESLint might run multiple fixes?
54
- // For now we keep it simple. If we delete here, we might lose it if
55
- // specific flows access it again. But usually postprocess is the end.
56
53
  fileState.delete(filename);
57
54
 
58
55
  if (!state) return messages[0];