@llui/lint-idiomatic
v0.0.3
Published
LLui linter — AST rules for idiomatic LLui patterns
Downloads
266
Maintainers
Readme
@llui/lint-idiomatic
AST linter for idiomatic LLui patterns. Catches common anti-patterns at the source level.
pnpm add -D @llui/lint-idiomaticUsage
import { lintIdiomatic } from '@llui/lint-idiomatic'
const source = `
function update(state: State, msg: Msg): [State, Effect[]] {
switch (msg.type) {
case 'increment':
state.count++ // mutation!
return [state, []]
}
}
`
const { violations, score } = lintIdiomatic(source, 'counter.ts')
console.log(score) // 5 (out of 6)
console.log(violations) // [{ rule: 'state-mutation', line: 5, message: '...' }]API
lintIdiomatic(source: string, filename?: string) => { violations: Violation[], score: number }| Field | Type | Description |
| ------------ | ------------- | ------------------------------------------- |
| violations | Violation[] | List of rule violations found |
| score | number | Idiomatic score 0-15 (15 = fully idiomatic) |
Violation
| Field | Type | Description |
| --------- | -------- | -------------------------- |
| rule | string | Rule identifier |
| line | number | Source line number |
| message | string | Human-readable explanation |
Rules
| Rule | Description |
| ---------------------------- | -------------------------------------------------------------------------- |
| state-mutation | Direct mutation of state in update() instead of returning a new object |
| missing-memo | Expensive derived computation in view() without memo() |
| each-closure-violation | Capturing mutable outer variable inside each() render callback |
| map-on-state-array | Calling .map() on a state array in view() (use each() instead) |
| unnecessary-child | Using child() boundary when a view function would suffice |
| form-boilerplate | Repetitive form field pattern that could use a view function |
| async-update | Using async/await in update() — must be synchronous and pure |
| direct-state-in-view | Stale state capture in event handler instead of using an accessor |
| exhaustive-effect-handling | Empty .else() handler silently drops unhandled effects |
| effect-without-handler | Component returns effects but has no onEffect handler |
| forgotten-spread | show()/branch()/each() used without spread in children array |
| string-effect-callback | Deprecated string-based onSuccess/onError in effect declarations |
| nested-send-in-update | Calling send() inside update() causes recursive dispatch |
| imperative-dom-in-view | Using document.querySelector etc. in view() instead of primitives |
| accessor-side-effect | Side effects (fetch, console.log, etc.) inside reactive accessor functions |
License
MIT
