@llui/lint-idiomatic 0.0.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/LICENSE +21 -0
- package/README.md +13 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +554 -0
- package/dist/index.js.map +1 -0
- package/package.json +43 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Franco Ponticelli
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# @llui/lint-idiomatic
|
|
2
|
+
|
|
3
|
+
AST linter for idiomatic [LLui](https://github.com/fponticelli/llui) patterns.
|
|
4
|
+
|
|
5
|
+
6 rules covering common anti-patterns: mutation in update, missing keys in each, state-derived map in view, and more.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add -D @llui/lint-idiomatic
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## License
|
|
12
|
+
|
|
13
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface LintViolation {
|
|
2
|
+
rule: string;
|
|
3
|
+
message: string;
|
|
4
|
+
file: string;
|
|
5
|
+
line: number;
|
|
6
|
+
column: number;
|
|
7
|
+
suggestion?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface LintResult {
|
|
10
|
+
violations: LintViolation[];
|
|
11
|
+
/** Score from 0 to 6. Starts at 6, -1 per violated rule category. */
|
|
12
|
+
score: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Lint a single source file for LLui idiomatic anti-patterns.
|
|
16
|
+
* Returns violations and a numeric score (6 = perfect).
|
|
17
|
+
*/
|
|
18
|
+
export declare function lintIdiomatic(source: string, filename?: string): LintResult;
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,aAAa,EAAE,CAAA;IAC3B,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAA;CACd;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,SAAa,GAAG,UAAU,CAgB/E"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,554 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
/**
|
|
3
|
+
* Lint a single source file for LLui idiomatic anti-patterns.
|
|
4
|
+
* Returns violations and a numeric score (6 = perfect).
|
|
5
|
+
*/
|
|
6
|
+
export function lintIdiomatic(source, filename = 'input.ts') {
|
|
7
|
+
const sf = ts.createSourceFile(filename, source, ts.ScriptTarget.Latest, true);
|
|
8
|
+
const violations = [];
|
|
9
|
+
checkStateMutation(sf, filename, violations);
|
|
10
|
+
checkMissingMemo(sf, filename, violations);
|
|
11
|
+
checkEachClosureViolation(sf, filename, violations);
|
|
12
|
+
checkMapOnStateArrays(sf, filename, violations);
|
|
13
|
+
checkUnnecessaryChild(sf, filename, violations);
|
|
14
|
+
checkFormBoilerplate(sf, filename, violations);
|
|
15
|
+
// Score: unique violated rule categories
|
|
16
|
+
const violatedRules = new Set(violations.map((v) => v.rule));
|
|
17
|
+
const score = Math.max(0, 6 - violatedRules.size);
|
|
18
|
+
return { violations, score };
|
|
19
|
+
}
|
|
20
|
+
// ── Helpers ─────────────────────────────────────────────────────────
|
|
21
|
+
function pos(node, sf) {
|
|
22
|
+
const { line, character } = sf.getLineAndCharacterOfPosition(node.getStart(sf));
|
|
23
|
+
return { line: line + 1, column: character + 1 };
|
|
24
|
+
}
|
|
25
|
+
function isStatePropertyAccess(node, stateName) {
|
|
26
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
27
|
+
if (ts.isIdentifier(node.expression) && node.expression.text === stateName)
|
|
28
|
+
return true;
|
|
29
|
+
return isStatePropertyAccess(node.expression, stateName);
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
function isInsideViewFunction(node) {
|
|
34
|
+
let current = node.parent;
|
|
35
|
+
while (current) {
|
|
36
|
+
if (ts.isPropertyAssignment(current)) {
|
|
37
|
+
if (ts.isIdentifier(current.name) && current.name.text === 'view') {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
current = current.parent;
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
function referencesStateParam(node) {
|
|
46
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
47
|
+
return referencesStateParam(node.expression);
|
|
48
|
+
}
|
|
49
|
+
if (ts.isIdentifier(node)) {
|
|
50
|
+
const name = node.text;
|
|
51
|
+
return name === 'state' || name === 's' || name === '_state';
|
|
52
|
+
}
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
// ── Rule 1: state-mutation ──────────────────────────────────────────
|
|
56
|
+
function checkStateMutation(sf, filename, violations) {
|
|
57
|
+
function visit(node) {
|
|
58
|
+
if (ts.isPropertyAssignment(node) &&
|
|
59
|
+
ts.isIdentifier(node.name) &&
|
|
60
|
+
node.name.text === 'update') {
|
|
61
|
+
const fn = node.initializer;
|
|
62
|
+
if (ts.isArrowFunction(fn) || ts.isFunctionExpression(fn)) {
|
|
63
|
+
const stateParam = fn.parameters[0];
|
|
64
|
+
if (stateParam && ts.isIdentifier(stateParam.name)) {
|
|
65
|
+
const stateName = stateParam.name.text;
|
|
66
|
+
checkMutationsInBody(fn.body, stateName, sf, filename, violations);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
ts.forEachChild(node, visit);
|
|
71
|
+
}
|
|
72
|
+
visit(sf);
|
|
73
|
+
}
|
|
74
|
+
function checkMutationsInBody(node, stateName, sf, filename, violations) {
|
|
75
|
+
// Check for direct assignment: state.x = y
|
|
76
|
+
if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken) {
|
|
77
|
+
if (isStatePropertyAccess(node.left, stateName)) {
|
|
78
|
+
const { line, column } = pos(node, sf);
|
|
79
|
+
violations.push({
|
|
80
|
+
rule: 'state-mutation',
|
|
81
|
+
message: `Direct mutation of state via assignment in update(). Use spread: { ...${stateName}, field: newValue }`,
|
|
82
|
+
file: filename,
|
|
83
|
+
line,
|
|
84
|
+
column,
|
|
85
|
+
suggestion: `Return a new object: { ...${stateName}, ... }`,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Check for compound assignment: state.x += y
|
|
90
|
+
if (ts.isBinaryExpression(node) &&
|
|
91
|
+
[
|
|
92
|
+
ts.SyntaxKind.PlusEqualsToken,
|
|
93
|
+
ts.SyntaxKind.MinusEqualsToken,
|
|
94
|
+
ts.SyntaxKind.AsteriskEqualsToken,
|
|
95
|
+
ts.SyntaxKind.SlashEqualsToken,
|
|
96
|
+
].includes(node.operatorToken.kind)) {
|
|
97
|
+
if (isStatePropertyAccess(node.left, stateName)) {
|
|
98
|
+
const { line, column } = pos(node, sf);
|
|
99
|
+
violations.push({
|
|
100
|
+
rule: 'state-mutation',
|
|
101
|
+
message: 'Compound assignment on state in update(). State is immutable.',
|
|
102
|
+
file: filename,
|
|
103
|
+
line,
|
|
104
|
+
column,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Check for prefix/postfix increment/decrement: state.x++, ++state.x
|
|
109
|
+
if ((ts.isPostfixUnaryExpression(node) || ts.isPrefixUnaryExpression(node)) &&
|
|
110
|
+
isStatePropertyAccess(node.operand, stateName)) {
|
|
111
|
+
const { line, column } = pos(node, sf);
|
|
112
|
+
violations.push({
|
|
113
|
+
rule: 'state-mutation',
|
|
114
|
+
message: 'Increment/decrement on state in update(). State is immutable.',
|
|
115
|
+
file: filename,
|
|
116
|
+
line,
|
|
117
|
+
column,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
// Check for mutating method calls: state.items.push(...)
|
|
121
|
+
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression)) {
|
|
122
|
+
const methodName = node.expression.name.text;
|
|
123
|
+
if (['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse', 'fill'].includes(methodName)) {
|
|
124
|
+
if (isStatePropertyAccess(node.expression.expression, stateName)) {
|
|
125
|
+
const { line, column } = pos(node, sf);
|
|
126
|
+
violations.push({
|
|
127
|
+
rule: 'state-mutation',
|
|
128
|
+
message: `Mutating method .${methodName}() called on state property in update(). Use immutable alternatives.`,
|
|
129
|
+
file: filename,
|
|
130
|
+
line,
|
|
131
|
+
column,
|
|
132
|
+
suggestion: methodName === 'push'
|
|
133
|
+
? 'Use [...array, newItem]'
|
|
134
|
+
: `Use immutable alternative to .${methodName}()`,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
ts.forEachChild(node, (child) => checkMutationsInBody(child, stateName, sf, filename, violations));
|
|
140
|
+
}
|
|
141
|
+
// ── Rule 2: missing-memo ────────────────────────────────────────────
|
|
142
|
+
function checkMissingMemo(sf, filename, violations) {
|
|
143
|
+
// Collect arrow functions used as arguments in binding positions (text(), prop values)
|
|
144
|
+
// Group by printed source text. Flag groups with count >= 2 not wrapped in memo().
|
|
145
|
+
const arrowsByText = new Map();
|
|
146
|
+
function isInMemoCall(node) {
|
|
147
|
+
const parent = node.parent;
|
|
148
|
+
if (parent &&
|
|
149
|
+
ts.isCallExpression(parent) &&
|
|
150
|
+
ts.isIdentifier(parent.expression) &&
|
|
151
|
+
parent.expression.text === 'memo') {
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
function visit(node) {
|
|
157
|
+
if (ts.isArrowFunction(node) && isInsideViewFunction(node)) {
|
|
158
|
+
// Check if this arrow is in a binding position:
|
|
159
|
+
// - first arg to text()
|
|
160
|
+
// - prop value in element helper call
|
|
161
|
+
const parent = node.parent;
|
|
162
|
+
const isBinding = (parent &&
|
|
163
|
+
ts.isCallExpression(parent) &&
|
|
164
|
+
ts.isIdentifier(parent.expression) &&
|
|
165
|
+
parent.expression.text === 'text' &&
|
|
166
|
+
parent.arguments[0] === node) ||
|
|
167
|
+
(parent && ts.isPropertyAssignment(parent));
|
|
168
|
+
if (isBinding) {
|
|
169
|
+
const sourceText = node.getText(sf).replace(/\s+/g, ' ').trim();
|
|
170
|
+
const inMemo = isInMemoCall(node);
|
|
171
|
+
const entries = arrowsByText.get(sourceText) ?? [];
|
|
172
|
+
entries.push({ node, inMemo });
|
|
173
|
+
arrowsByText.set(sourceText, entries);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
ts.forEachChild(node, visit);
|
|
177
|
+
}
|
|
178
|
+
visit(sf);
|
|
179
|
+
for (const [_sourceText, entries] of arrowsByText) {
|
|
180
|
+
if (entries.length < 2)
|
|
181
|
+
continue;
|
|
182
|
+
const unmemoized = entries.filter((e) => !e.inMemo);
|
|
183
|
+
if (unmemoized.length < 2)
|
|
184
|
+
continue;
|
|
185
|
+
// Report on all but the first occurrence
|
|
186
|
+
for (let i = 1; i < unmemoized.length; i++) {
|
|
187
|
+
const entry = unmemoized[i];
|
|
188
|
+
const { line, column } = pos(entry.node, sf);
|
|
189
|
+
violations.push({
|
|
190
|
+
rule: 'missing-memo',
|
|
191
|
+
message: 'Duplicate accessor arrow function used in multiple binding sites without memo(). Wrap in memo() to share computation.',
|
|
192
|
+
file: filename,
|
|
193
|
+
line,
|
|
194
|
+
column,
|
|
195
|
+
suggestion: 'Wrap the accessor in memo() and reuse the reference.',
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// ── Rule 3: each-closure-violation ──────────────────────────────────
|
|
201
|
+
function checkEachClosureViolation(sf, filename, violations) {
|
|
202
|
+
function visit(node) {
|
|
203
|
+
// Look for each() calls
|
|
204
|
+
if (ts.isCallExpression(node) &&
|
|
205
|
+
ts.isIdentifier(node.expression) &&
|
|
206
|
+
node.expression.text === 'each') {
|
|
207
|
+
// each() typically takes an object with a render callback
|
|
208
|
+
const arg = node.arguments[0];
|
|
209
|
+
if (arg && ts.isObjectLiteralExpression(arg)) {
|
|
210
|
+
for (const prop of arg.properties) {
|
|
211
|
+
if (ts.isPropertyAssignment(prop) &&
|
|
212
|
+
ts.isIdentifier(prop.name) &&
|
|
213
|
+
prop.name.text === 'render') {
|
|
214
|
+
const renderFn = prop.initializer;
|
|
215
|
+
if (ts.isArrowFunction(renderFn) || ts.isFunctionExpression(renderFn)) {
|
|
216
|
+
checkClosureCaptures(renderFn, sf, filename, violations);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
ts.forEachChild(node, visit);
|
|
223
|
+
}
|
|
224
|
+
visit(sf);
|
|
225
|
+
}
|
|
226
|
+
function checkClosureCaptures(renderFn, sf, filename, violations) {
|
|
227
|
+
// Collect parameter names of the render callback
|
|
228
|
+
const paramNames = new Set();
|
|
229
|
+
for (const param of renderFn.parameters) {
|
|
230
|
+
if (ts.isIdentifier(param.name)) {
|
|
231
|
+
paramNames.add(param.name.text);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
// Collect locally declared names inside the render body
|
|
235
|
+
const localNames = new Set();
|
|
236
|
+
function collectLocals(node) {
|
|
237
|
+
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {
|
|
238
|
+
localNames.add(node.name.text);
|
|
239
|
+
}
|
|
240
|
+
if (ts.isParameter(node) && ts.isIdentifier(node.name)) {
|
|
241
|
+
localNames.add(node.name.text);
|
|
242
|
+
}
|
|
243
|
+
ts.forEachChild(node, collectLocals);
|
|
244
|
+
}
|
|
245
|
+
if (renderFn.body) {
|
|
246
|
+
collectLocals(renderFn.body);
|
|
247
|
+
}
|
|
248
|
+
// Known safe globals/imports that should not be flagged
|
|
249
|
+
const safeNames = new Set([
|
|
250
|
+
'send',
|
|
251
|
+
'console',
|
|
252
|
+
'Math',
|
|
253
|
+
'JSON',
|
|
254
|
+
'String',
|
|
255
|
+
'Number',
|
|
256
|
+
'Boolean',
|
|
257
|
+
'Array',
|
|
258
|
+
'Object',
|
|
259
|
+
'Date',
|
|
260
|
+
'Promise',
|
|
261
|
+
'undefined',
|
|
262
|
+
'null',
|
|
263
|
+
'true',
|
|
264
|
+
'false',
|
|
265
|
+
'div',
|
|
266
|
+
'span',
|
|
267
|
+
'p',
|
|
268
|
+
'text',
|
|
269
|
+
'button',
|
|
270
|
+
'input',
|
|
271
|
+
'each',
|
|
272
|
+
'memo',
|
|
273
|
+
'show',
|
|
274
|
+
'branch',
|
|
275
|
+
'child',
|
|
276
|
+
'h1',
|
|
277
|
+
'h2',
|
|
278
|
+
'h3',
|
|
279
|
+
'h4',
|
|
280
|
+
'h5',
|
|
281
|
+
'h6',
|
|
282
|
+
'ul',
|
|
283
|
+
'ol',
|
|
284
|
+
'li',
|
|
285
|
+
'a',
|
|
286
|
+
'img',
|
|
287
|
+
'form',
|
|
288
|
+
'label',
|
|
289
|
+
'select',
|
|
290
|
+
'textarea',
|
|
291
|
+
'table',
|
|
292
|
+
'tr',
|
|
293
|
+
'td',
|
|
294
|
+
'th',
|
|
295
|
+
'header',
|
|
296
|
+
'footer',
|
|
297
|
+
'nav',
|
|
298
|
+
'main',
|
|
299
|
+
'section',
|
|
300
|
+
'article',
|
|
301
|
+
]);
|
|
302
|
+
// Find identifiers in binding positions that reference parent scope
|
|
303
|
+
function checkBindings(node) {
|
|
304
|
+
if (ts.isIdentifier(node)) {
|
|
305
|
+
const name = node.text;
|
|
306
|
+
// Skip if it's a parameter, local, or safe name
|
|
307
|
+
if (paramNames.has(name) || localNames.has(name) || safeNames.has(name))
|
|
308
|
+
return;
|
|
309
|
+
// Skip if it's a property name in a property access (rhs of dot)
|
|
310
|
+
if (node.parent && ts.isPropertyAccessExpression(node.parent) && node.parent.name === node)
|
|
311
|
+
return;
|
|
312
|
+
// Skip if it's a property name in a property assignment
|
|
313
|
+
if (node.parent && ts.isPropertyAssignment(node.parent) && node.parent.name === node)
|
|
314
|
+
return;
|
|
315
|
+
// Skip type references
|
|
316
|
+
if (node.parent && ts.isTypeReferenceNode(node.parent))
|
|
317
|
+
return;
|
|
318
|
+
// Check if this identifier is used in a binding context (arrow fn arg to text(), prop value)
|
|
319
|
+
if (isInBindingContext(node)) {
|
|
320
|
+
const { line, column } = pos(node, sf);
|
|
321
|
+
violations.push({
|
|
322
|
+
rule: 'each-closure-violation',
|
|
323
|
+
message: `Identifier '${name}' captured from parent scope inside each() render callback. Use the item accessor instead.`,
|
|
324
|
+
file: filename,
|
|
325
|
+
line,
|
|
326
|
+
column,
|
|
327
|
+
suggestion: 'Access data through the item/index parameters provided by each().',
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
ts.forEachChild(node, checkBindings);
|
|
332
|
+
}
|
|
333
|
+
if (renderFn.body) {
|
|
334
|
+
checkBindings(renderFn.body);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
function isInBindingContext(node) {
|
|
338
|
+
// Walk up to find if we're inside an arrow function used as a binding
|
|
339
|
+
let current = node;
|
|
340
|
+
while (current) {
|
|
341
|
+
if (ts.isArrowFunction(current)) {
|
|
342
|
+
const parent = current.parent;
|
|
343
|
+
// First arg to text()
|
|
344
|
+
if (parent &&
|
|
345
|
+
ts.isCallExpression(parent) &&
|
|
346
|
+
ts.isIdentifier(parent.expression) &&
|
|
347
|
+
parent.expression.text === 'text' &&
|
|
348
|
+
parent.arguments[0] === current) {
|
|
349
|
+
return true;
|
|
350
|
+
}
|
|
351
|
+
// Prop value in object literal
|
|
352
|
+
if (parent && ts.isPropertyAssignment(parent)) {
|
|
353
|
+
return true;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
current = current.parent;
|
|
357
|
+
}
|
|
358
|
+
return false;
|
|
359
|
+
}
|
|
360
|
+
// ── Rule 4: map-on-state-array ──────────────────────────────────────
|
|
361
|
+
function checkMapOnStateArrays(sf, filename, violations) {
|
|
362
|
+
function visit(node) {
|
|
363
|
+
if (!ts.isCallExpression(node)) {
|
|
364
|
+
ts.forEachChild(node, visit);
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
if (!ts.isPropertyAccessExpression(node.expression)) {
|
|
368
|
+
ts.forEachChild(node, visit);
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
if (node.expression.name.text !== 'map') {
|
|
372
|
+
ts.forEachChild(node, visit);
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
if (!referencesStateParam(node.expression.expression)) {
|
|
376
|
+
ts.forEachChild(node, visit);
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
if (!isInsideViewFunction(node)) {
|
|
380
|
+
ts.forEachChild(node, visit);
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
const { line, column } = pos(node, sf);
|
|
384
|
+
violations.push({
|
|
385
|
+
rule: 'map-on-state-array',
|
|
386
|
+
message: 'Array .map() on state-derived value in view(). Use each() for reactive lists.',
|
|
387
|
+
file: filename,
|
|
388
|
+
line,
|
|
389
|
+
column,
|
|
390
|
+
suggestion: 'Replace .map() with each({ source: ..., key: ..., render: ... }).',
|
|
391
|
+
});
|
|
392
|
+
ts.forEachChild(node, visit);
|
|
393
|
+
}
|
|
394
|
+
visit(sf);
|
|
395
|
+
}
|
|
396
|
+
// ── Rule 5: unnecessary-child ───────────────────────────────────────
|
|
397
|
+
function checkUnnecessaryChild(sf, filename, violations) {
|
|
398
|
+
// Collect component definitions: look for component() calls and count state access paths
|
|
399
|
+
const componentInfo = new Map();
|
|
400
|
+
function collectComponents(node) {
|
|
401
|
+
// Look for: const X = component({ ... })
|
|
402
|
+
if (ts.isVariableDeclaration(node) &&
|
|
403
|
+
ts.isIdentifier(node.name) &&
|
|
404
|
+
node.initializer &&
|
|
405
|
+
ts.isCallExpression(node.initializer) &&
|
|
406
|
+
ts.isIdentifier(node.initializer.expression) &&
|
|
407
|
+
node.initializer.expression.text === 'component') {
|
|
408
|
+
const arg = node.initializer.arguments[0];
|
|
409
|
+
if (arg && ts.isObjectLiteralExpression(arg)) {
|
|
410
|
+
let hasReceives = false;
|
|
411
|
+
let stateAccessCount = 0;
|
|
412
|
+
for (const prop of arg.properties) {
|
|
413
|
+
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
|
|
414
|
+
if (prop.name.text === 'receives') {
|
|
415
|
+
hasReceives = true;
|
|
416
|
+
}
|
|
417
|
+
if (prop.name.text === 'view' || prop.name.text === 'update') {
|
|
418
|
+
// Count unique state property accesses
|
|
419
|
+
const accesses = new Set();
|
|
420
|
+
countStateAccesses(prop.initializer, accesses);
|
|
421
|
+
stateAccessCount += accesses.size;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
componentInfo.set(node.name.text, {
|
|
426
|
+
stateAccessCount,
|
|
427
|
+
hasReceives,
|
|
428
|
+
node: node.initializer,
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
ts.forEachChild(node, collectComponents);
|
|
433
|
+
}
|
|
434
|
+
collectComponents(sf);
|
|
435
|
+
// Now find child() calls that reference these components
|
|
436
|
+
function findChildCalls(node) {
|
|
437
|
+
if (ts.isCallExpression(node) &&
|
|
438
|
+
ts.isIdentifier(node.expression) &&
|
|
439
|
+
node.expression.text === 'child') {
|
|
440
|
+
// child() first arg is typically { component: X, ... }
|
|
441
|
+
const arg = node.arguments[0];
|
|
442
|
+
if (arg && ts.isObjectLiteralExpression(arg)) {
|
|
443
|
+
for (const prop of arg.properties) {
|
|
444
|
+
if (ts.isPropertyAssignment(prop) &&
|
|
445
|
+
ts.isIdentifier(prop.name) &&
|
|
446
|
+
prop.name.text === 'component') {
|
|
447
|
+
if (ts.isIdentifier(prop.initializer)) {
|
|
448
|
+
const compName = prop.initializer.text;
|
|
449
|
+
const info = componentInfo.get(compName);
|
|
450
|
+
if (info && info.stateAccessCount < 10 && !info.hasReceives) {
|
|
451
|
+
const { line, column } = pos(node, sf);
|
|
452
|
+
violations.push({
|
|
453
|
+
rule: 'unnecessary-child',
|
|
454
|
+
message: `child() used for component '${compName}' which has fewer than 10 state access paths and no receives. Consider using a view function (Level 1 composition) instead.`,
|
|
455
|
+
file: filename,
|
|
456
|
+
line,
|
|
457
|
+
column,
|
|
458
|
+
suggestion: 'Use Level 1 composition (view function) for simple components.',
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
ts.forEachChild(node, findChildCalls);
|
|
467
|
+
}
|
|
468
|
+
findChildCalls(sf);
|
|
469
|
+
}
|
|
470
|
+
function countStateAccesses(node, accesses) {
|
|
471
|
+
if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression)) {
|
|
472
|
+
const name = node.expression.text;
|
|
473
|
+
if (name === 'state' || name === 's' || name === '_state') {
|
|
474
|
+
accesses.add(node.name.text);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
ts.forEachChild(node, (child) => countStateAccesses(child, accesses));
|
|
478
|
+
}
|
|
479
|
+
// ── Rule 6: form-boilerplate ────────────────────────────────────────
|
|
480
|
+
function checkFormBoilerplate(sf, filename, violations) {
|
|
481
|
+
// Find Msg type alias declarations that are union types
|
|
482
|
+
for (const stmt of sf.statements) {
|
|
483
|
+
if (!ts.isTypeAliasDeclaration(stmt))
|
|
484
|
+
continue;
|
|
485
|
+
if (stmt.name.text !== 'Msg')
|
|
486
|
+
continue;
|
|
487
|
+
const variants = collectMsgVariantShapes(stmt.type);
|
|
488
|
+
if (variants.length < 3)
|
|
489
|
+
continue;
|
|
490
|
+
// Group variants by their "shape" — same fields except the type literal value
|
|
491
|
+
// A variant shape is: sorted field names + field types (excluding the 'type' field value)
|
|
492
|
+
const shapeGroups = new Map();
|
|
493
|
+
for (const variant of variants) {
|
|
494
|
+
const shape = variant.shape;
|
|
495
|
+
const group = shapeGroups.get(shape) ?? [];
|
|
496
|
+
group.push(variant.typeName);
|
|
497
|
+
shapeGroups.set(shape, group);
|
|
498
|
+
}
|
|
499
|
+
for (const [_shape, group] of shapeGroups) {
|
|
500
|
+
if (group.length >= 3) {
|
|
501
|
+
const { line, column } = pos(stmt, sf);
|
|
502
|
+
violations.push({
|
|
503
|
+
rule: 'form-boilerplate',
|
|
504
|
+
message: `Msg type has ${group.length} variants with identical shapes (${group
|
|
505
|
+
.slice(0, 3)
|
|
506
|
+
.map((g) => `'${g}'`)
|
|
507
|
+
.join(', ')}${group.length > 3 ? ', ...' : ''}). Consider using a generic field-update message pattern.`,
|
|
508
|
+
file: filename,
|
|
509
|
+
line,
|
|
510
|
+
column,
|
|
511
|
+
suggestion: "Use a single { type: 'setField'; field: string; value: string } variant instead.",
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
function collectMsgVariantShapes(type) {
|
|
518
|
+
const variants = [];
|
|
519
|
+
if (ts.isUnionTypeNode(type)) {
|
|
520
|
+
for (const member of type.types) {
|
|
521
|
+
variants.push(...collectMsgVariantShapes(member));
|
|
522
|
+
}
|
|
523
|
+
return variants;
|
|
524
|
+
}
|
|
525
|
+
if (ts.isTypeLiteralNode(type)) {
|
|
526
|
+
let typeName = '';
|
|
527
|
+
const fields = [];
|
|
528
|
+
for (const member of type.members) {
|
|
529
|
+
if (!ts.isPropertySignature(member))
|
|
530
|
+
continue;
|
|
531
|
+
if (!member.name || !ts.isIdentifier(member.name))
|
|
532
|
+
continue;
|
|
533
|
+
const fieldName = member.name.text;
|
|
534
|
+
const fieldType = member.type ? member.type.getText() : 'unknown';
|
|
535
|
+
if (fieldName === 'type') {
|
|
536
|
+
// Extract the literal value as the variant name
|
|
537
|
+
if (member.type &&
|
|
538
|
+
ts.isLiteralTypeNode(member.type) &&
|
|
539
|
+
ts.isStringLiteral(member.type.literal)) {
|
|
540
|
+
typeName = member.type.literal.text;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
else {
|
|
544
|
+
fields.push(`${fieldName}:${fieldType}`);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
if (typeName && fields.length > 0) {
|
|
548
|
+
fields.sort();
|
|
549
|
+
variants.push({ typeName, shape: fields.join(',') });
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
return variants;
|
|
553
|
+
}
|
|
554
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@llui/lint-idiomatic",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"import": "./dist/index.js"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc -p tsconfig.build.json",
|
|
17
|
+
"check": "tsc --noEmit",
|
|
18
|
+
"lint": "eslint src",
|
|
19
|
+
"test": "vitest run"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"typescript": "^6.0.2"
|
|
23
|
+
},
|
|
24
|
+
"description": "LLui linter — AST rules for idiomatic LLui patterns",
|
|
25
|
+
"keywords": [
|
|
26
|
+
"llui",
|
|
27
|
+
"lint",
|
|
28
|
+
"linter",
|
|
29
|
+
"eslint",
|
|
30
|
+
"idiomatic"
|
|
31
|
+
],
|
|
32
|
+
"author": "Franco Ponticelli <franco.ponticelli@gmail.com>",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "git+https://github.com/fponticelli/llui.git",
|
|
37
|
+
"directory": "packages/lint-idiomatic"
|
|
38
|
+
},
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/fponticelli/llui/issues"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://github.com/fponticelli/llui/tree/main/packages/lint-idiomatic#readme"
|
|
43
|
+
}
|