Skip to content

Commit 4c2c9b0

Browse files
committed
lint
1 parent 8378e1e commit 4c2c9b0

2 files changed

Lines changed: 69 additions & 16 deletions

File tree

README.md

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -228,36 +228,87 @@ Additionally, the following rules are configurable. Set their severities (`"erro
228228
{
229229
"rules": {
230230
"consecutiveDuplicateSections": "off",
231-
"preferMustacheComments": "warning"
232-
}
231+
"preferMustacheComments": "warning",
232+
},
233233
}
234234
```
235235

236236
<!-- RULES_TABLE_START -->
237237

238-
| Rule | Default | Description |
239-
| --- | --- | --- |
240-
| `nestedDuplicateSections` | `error` | Flags `{{#name}}` nested inside another `{{#name}}` with the same name |
241-
| `unquotedMustacheAttributes` | `error` | Requires quotes around mustache expressions used as attribute values |
242-
| `consecutiveDuplicateSections` | `warning` | Warns when adjacent same-name sections can be merged |
243-
| `selfClosingNonVoidTags` | `error` | Disallows self-closing syntax on non-void HTML elements (e.g. `<div/>`) |
244-
| `duplicateAttributes` | `error` | Detects duplicate HTML attributes on the same element |
245-
| `unescapedEntities` | `warning` | Flags unescaped `&` and `>` characters in text content |
246-
| `preferMustacheComments` | `off` | Suggests replacing HTML comments with mustache comments |
247-
| `unrecognizedHtmlTags` | `error` | Flags HTML tags that are not standard HTML elements or valid custom elements |
238+
| Rule | Default | Description |
239+
| ------------------------------ | --------- | ---------------------------------------------------------------------------- |
240+
| `nestedDuplicateSections` | `error` | Flags `{{#name}}` nested inside another `{{#name}}` with the same name |
241+
| `unquotedMustacheAttributes` | `error` | Requires quotes around mustache expressions used as attribute values |
242+
| `consecutiveDuplicateSections` | `warning` | Warns when adjacent same-name sections can be merged |
243+
| `selfClosingNonVoidTags` | `error` | Disallows self-closing syntax on non-void HTML elements (e.g. `<div/>`) |
244+
| `duplicateAttributes` | `error` | Detects duplicate HTML attributes on the same element |
245+
| `unescapedEntities` | `warning` | Flags unescaped `&` and `>` characters in text content |
246+
| `preferMustacheComments` | `off` | Suggests replacing HTML comments with mustache comments |
247+
| `unrecognizedHtmlTags` | `error` | Flags HTML tags that are not standard HTML elements or valid custom elements |
248248

249249
<!-- RULES_TABLE_END -->
250250

251+
### Custom Rules
252+
253+
Define project-specific lint rules using CSS-like selectors to match HTML elements and Mustache sections:
254+
255+
```jsonc
256+
{
257+
"customRules": [
258+
{
259+
"id": "no-font",
260+
"selector": "font",
261+
"message": "The <font> tag is deprecated. Use CSS instead.",
262+
},
263+
{
264+
"id": "no-inline-styles",
265+
"selector": "[style]",
266+
"message": "Avoid inline styles",
267+
"severity": "warning",
268+
},
269+
{
270+
"id": "images-need-alt",
271+
"selector": "img:not([alt])",
272+
"message": "Images must have alt text for accessibility",
273+
},
274+
{
275+
"id": "no-hidden-inputs-in-list",
276+
"selector": "#items > input[type=hidden]",
277+
"message": "Hidden inputs inside {{#items}} sections are usually a mistake",
278+
},
279+
],
280+
}
281+
```
282+
283+
Each custom rule requires an `id`, `selector`, and `message`. The `severity` defaults to `"error"` but can be set to `"warning"` or `"off"`.
284+
285+
**Selector syntax:**
286+
287+
| Selector | Matches |
288+
| -------------------- | ---------------------------------------- |
289+
| `div` | HTML elements by tag name |
290+
| `#items` | Mustache sections by name (`{{#items}}`) |
291+
| `*` | Any HTML element |
292+
| `#` | Any Mustache section |
293+
| `div span` | Descendant (span anywhere inside div) |
294+
| `div > span` | Direct child (span directly inside div) |
295+
| `[style]` | Attribute presence |
296+
| `input[type=hidden]` | Attribute value |
297+
| `img:not([alt])` | Negated attribute |
298+
| `div, span` | Comma-separated alternatives |
299+
300+
The `>` (child) combinator is kind-transparent: `div > span` matches even if a Mustache section sits between them (e.g. `<div>{{#show}}<span>{{/show}}</div>`), and `#a > #b` matches across intervening HTML elements.
301+
251302
### Disabling Lint Rules
252303

253-
Disable a configurable lint rule for an entire file with an inline comment:
304+
Disable a lint rule for an entire file with an inline comment:
254305

255306
```html
256307
<!-- htmlmustache-disable preferMustacheComments -->
257308
{{! htmlmustache-disable selfClosingNonVoidTags }}
258309
```
259310

260-
The comment can appear anywhere in the file. Only configurable rules (listed above) can be disabled. Use multiple comments to disable multiple rules.
311+
The comment can appear anywhere in the file. Both built-in and custom rules can be disabled by name/id. Use multiple comments to disable multiple rules.
261312

262313
### EditorConfig
263314

scripts/generate-rule-docs.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const END_MARKER = '<!-- RULES_TABLE_END -->';
1010
const header = '| Rule | Default | Description |';
1111
const separator = '| --- | --- | --- |';
1212
const rows = RULES.map(
13-
r => `| \`${r.name}\` | \`${r.defaultSeverity}\` | ${r.description} |`,
13+
(r) => `| \`${r.name}\` | \`${r.defaultSeverity}\` | ${r.description} |`,
1414
);
1515
const table = [header, separator, ...rows].join('\n');
1616

@@ -23,7 +23,9 @@ const startIdx = readme.indexOf(START_MARKER);
2323
const endIdx = readme.indexOf(END_MARKER);
2424

2525
if (startIdx === -1 || endIdx === -1) {
26-
console.error(`Could not find ${START_MARKER} / ${END_MARKER} markers in README.md`);
26+
console.error(
27+
`Could not find ${START_MARKER} / ${END_MARKER} markers in README.md`,
28+
);
2729
process.exit(1);
2830
}
2931

0 commit comments

Comments
 (0)