@reteps/tree-sitter-htmlmustache 0.8.0 → 0.9.0

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.
Files changed (67) hide show
  1. package/README.md +49 -33
  2. package/browser/out/browser/index.d.ts +43 -0
  3. package/browser/out/browser/index.d.ts.map +1 -0
  4. package/browser/out/browser/index.mjs +3612 -0
  5. package/browser/out/browser/index.mjs.map +7 -0
  6. package/browser/out/core/collectErrors.d.ts +36 -0
  7. package/browser/out/core/collectErrors.d.ts.map +1 -0
  8. package/browser/out/core/configSchema.d.ts +63 -0
  9. package/browser/out/core/configSchema.d.ts.map +1 -0
  10. package/browser/out/core/customCodeTags.d.ts +34 -0
  11. package/browser/out/core/customCodeTags.d.ts.map +1 -0
  12. package/browser/out/core/diagnostic.d.ts +24 -0
  13. package/browser/out/core/diagnostic.d.ts.map +1 -0
  14. package/browser/out/core/embeddedRegions.d.ts +12 -0
  15. package/browser/out/core/embeddedRegions.d.ts.map +1 -0
  16. package/browser/out/core/formatting/classifier.d.ts +68 -0
  17. package/browser/out/core/formatting/classifier.d.ts.map +1 -0
  18. package/browser/out/core/formatting/embedded.d.ts +19 -0
  19. package/browser/out/core/formatting/embedded.d.ts.map +1 -0
  20. package/browser/out/core/formatting/formatters.d.ts +85 -0
  21. package/browser/out/core/formatting/formatters.d.ts.map +1 -0
  22. package/browser/out/core/formatting/index.d.ts +44 -0
  23. package/browser/out/core/formatting/index.d.ts.map +1 -0
  24. package/browser/out/core/formatting/ir.d.ts +100 -0
  25. package/browser/out/core/formatting/ir.d.ts.map +1 -0
  26. package/browser/out/core/formatting/mergeOptions.d.ts +18 -0
  27. package/browser/out/core/formatting/mergeOptions.d.ts.map +1 -0
  28. package/browser/out/core/formatting/printer.d.ts +18 -0
  29. package/browser/out/core/formatting/printer.d.ts.map +1 -0
  30. package/browser/out/core/formatting/utils.d.ts +39 -0
  31. package/browser/out/core/formatting/utils.d.ts.map +1 -0
  32. package/browser/out/core/grammar.d.ts +3 -0
  33. package/browser/out/core/grammar.d.ts.map +1 -0
  34. package/browser/out/core/htmlBalanceChecker.d.ts +23 -0
  35. package/browser/out/core/htmlBalanceChecker.d.ts.map +1 -0
  36. package/browser/out/core/mustacheChecks.d.ts +24 -0
  37. package/browser/out/core/mustacheChecks.d.ts.map +1 -0
  38. package/browser/out/core/nodeHelpers.d.ts +54 -0
  39. package/browser/out/core/nodeHelpers.d.ts.map +1 -0
  40. package/browser/out/core/ruleMetadata.d.ts +12 -0
  41. package/browser/out/core/ruleMetadata.d.ts.map +1 -0
  42. package/browser/out/core/selectorMatcher.d.ts +74 -0
  43. package/browser/out/core/selectorMatcher.d.ts.map +1 -0
  44. package/cli/out/main.js +168 -122
  45. package/package.json +21 -3
  46. package/src/browser/browser.test.ts +207 -0
  47. package/src/browser/index.ts +128 -0
  48. package/src/browser/tsconfig.json +18 -0
  49. package/src/core/collectErrors.ts +233 -0
  50. package/src/core/configSchema.ts +273 -0
  51. package/src/core/customCodeTags.ts +159 -0
  52. package/src/core/diagnostic.ts +45 -0
  53. package/src/core/embeddedRegions.ts +70 -0
  54. package/src/core/formatting/classifier.ts +549 -0
  55. package/src/core/formatting/embedded.ts +56 -0
  56. package/src/core/formatting/formatters.ts +1272 -0
  57. package/src/core/formatting/index.ts +185 -0
  58. package/src/core/formatting/ir.ts +202 -0
  59. package/src/core/formatting/mergeOptions.ts +34 -0
  60. package/src/core/formatting/printer.ts +242 -0
  61. package/src/core/formatting/utils.ts +193 -0
  62. package/src/core/grammar.ts +2 -0
  63. package/src/core/htmlBalanceChecker.ts +382 -0
  64. package/src/core/mustacheChecks.ts +504 -0
  65. package/src/core/nodeHelpers.ts +126 -0
  66. package/src/core/ruleMetadata.ts +63 -0
  67. package/src/core/selectorMatcher.ts +719 -0
package/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
  <p align="center">
12
12
  <a href="https://github.com/reteps/tree-sitter-htmlmustache/actions/workflows/lint.yml"><img src="https://img.shields.io/github/actions/workflow/status/reteps/tree-sitter-htmlmustache/lint.yml?logo=github&label=Lint" alt="Lint"></a>
13
13
  <a href="https://github.com/reteps/tree-sitter-htmlmustache/actions/workflows/lsp.yml"><img src="https://img.shields.io/github/actions/workflow/status/reteps/tree-sitter-htmlmustache/lsp.yml?logo=github&label=LSP" alt="LSP"></a>
14
- <a href="https://marketplace.visualstudio.com/items?itemName=reteps.htmlmustache-lsp"><img src="https://img.shields.io/visual-studio-marketplace/v/reteps.htmlmustache-lsp?logo=visualstudiocode&label=VS%20Code" alt="VS Code Marketplace"></a>
14
+ <a href="https://open-vsx.org/extension/reteps/htmlmustache-lsp"><img src="https://img.shields.io/open-vsx/v/reteps/htmlmustache-lsp?logo=visualstudiocode&label=VS%20Code" alt="Open VSX"></a>
15
15
  </p>
16
16
 
17
17
  ---
@@ -294,41 +294,57 @@ Each custom rule requires an `id`, `selector`, and `message`. The `severity` def
294
294
 
295
295
  **Selector syntax:**
296
296
 
297
- | Selector | Matches |
298
- | ----------------------------------------- | --------------------------------------------- |
299
- | `div` | HTML elements by tag name |
300
- | `*` | Any HTML element |
301
- | `#main` | ID (shorthand for `[id="main"]`) |
302
- | `.panel` | Class (shorthand for `[class~="panel"]`) |
303
- | `div span` | Descendant (span anywhere inside div) |
304
- | `div > span` | Direct child |
305
- | `[style]` | Attribute presence |
306
- | `input[type=hidden]` | Attribute value (exact) |
307
- | `[src^="prefix/"]` | Attribute starts with |
308
- | `[href*="substring"]` | Attribute contains |
309
- | `[src$=".png"]` | Attribute ends with |
310
- | `[class~="warning"]` | Attribute contains whitespace-token |
311
- | `img:not([alt])` | Negated attribute / class / id |
312
- | `{{foo}}` | Escaped variable `{{foo}}` |
313
- | `{{data.foo}}` | Variable with a dotted path |
314
- | `{{{foo}}}` | Triple / unescaped variable |
315
- | `{{options.*}}` | Variable path prefix match |
316
- | `{{*.deprecated}}` | Variable path suffix match |
317
- | `{{*}}` | Any escaped variable |
318
- | `{{{*}}}` | Any triple |
319
- | `{{#items}}` | Section `{{#items}}...{{/items}}` |
320
- | `{{^items}}` | Inverted section `{{^items}}...{{/items}}` |
321
- | `{{#items}} > li` | Direct child inside a section |
322
- | `{{!TODO}}` | Comment with exact content |
323
- | `{{!*TODO*}}` | Comment containing "TODO" |
324
- | `{{>header}}` | Partial invocation |
325
- | `{{>legacy_*}}` | Partial name prefix |
326
- | `pl-multiple-choice:has({{foo}})` | Element containing a given variable |
327
- | `pl-multiple-choice:not(:has(pl-answer))` | Element missing a required descendant |
328
- | `div, span` | Comma-separated alternatives |
297
+ | Selector | Matches |
298
+ | ----------------------------------------- | ------------------------------------------ |
299
+ | `div` | HTML elements by tag name |
300
+ | `*` | Any HTML element |
301
+ | `#main` | ID (shorthand for `[id="main"]`) |
302
+ | `.panel` | Class (shorthand for `[class~="panel"]`) |
303
+ | `div span` | Descendant (span anywhere inside div) |
304
+ | `div > span` | Direct child |
305
+ | `[style]` | Attribute presence |
306
+ | `input[type=hidden]` | Attribute value (exact) |
307
+ | `[src^="prefix/"]` | Attribute starts with |
308
+ | `[href*="substring"]` | Attribute contains |
309
+ | `[src$=".png"]` | Attribute ends with |
310
+ | `[class~="warning"]` | Attribute contains whitespace-token |
311
+ | `img:not([alt])` | Negated attribute / class / id |
312
+ | `{{foo}}` | Escaped variable `{{foo}}` |
313
+ | `{{data.foo}}` | Variable with a dotted path |
314
+ | `{{{foo}}}` | Triple / unescaped variable |
315
+ | `{{options.*}}` | Variable path prefix match |
316
+ | `{{*.deprecated}}` | Variable path suffix match |
317
+ | `{{*}}` | Any escaped variable |
318
+ | `{{{*}}}` | Any triple |
319
+ | `{{#items}}` | Section `{{#items}}...{{/items}}` |
320
+ | `{{^items}}` | Inverted section `{{^items}}...{{/items}}` |
321
+ | `{{#items}} > li` | Direct child inside a section |
322
+ | `{{!TODO}}` | Comment with exact content |
323
+ | `{{!*TODO*}}` | Comment containing "TODO" |
324
+ | `{{>header}}` | Partial invocation |
325
+ | `{{>legacy_*}}` | Partial name prefix |
326
+ | `pl-multiple-choice:has({{foo}})` | Element containing a given variable |
327
+ | `pl-multiple-choice:not(:has(pl-answer))` | Element missing a required descendant |
328
+ | `div, span` | Comma-separated alternatives |
329
+ | `:root` | The document root (the whole parse tree) |
330
+ | `:root:has(pl-answer-panel)` | Document contains a descendant anywhere |
331
+ | `:root:not(:has(pl-answer-panel))` | Document is missing a descendant anywhere |
332
+ | `:root > section` | Top-level element (direct child of root) |
329
333
 
330
334
  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. `{{#foo}}` matches only positive sections — to target inverted sections use `{{^foo}}`.
331
335
 
336
+ **Document-scoped conditional rules.** Use `:root` with `:has(...)` / `:not(:has(...))` to express rules that depend on the overall document. Chained `:has(...)` acts as AND, so you can combine "contains X" and "missing Y" in one selector:
337
+
338
+ ```jsonc
339
+ {
340
+ "id": "question-needs-answer-panel",
341
+ "selector": ":root:has(pl-question-panel):not(:has(pl-answer-panel))",
342
+ "message": "A question-panel document must also declare a pl-answer-panel.",
343
+ }
344
+ ```
345
+
346
+ When `:root` matches, the diagnostic is reported at the start of the document (row 0, column 0) so the squiggle doesn't span the whole file. `:root` here is the tree-sitter fragment root, so it works on partial templates and fragments — unlike browser CSS, which anchors `:root` on `<html>`. Inside `:has(...)`, `:root` refers to the element being has-checked, not the document.
347
+
332
348
  ### Disabling Lint Rules
333
349
 
334
350
  Disable a lint rule for an entire file with an inline comment:
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Browser entry point for `@reteps/tree-sitter-htmlmustache`.
3
+ *
4
+ * Exposes `createLinter({ locateWasm, prettier? })` returning a handle with
5
+ * `lint(source, config)` and `format(source, config, opts)`. Internally reuses
6
+ * the shared rule engine and formatter in `src/core/` — browser-safe, no fs.
7
+ */
8
+ import type { PrettierLike } from '../core/formatting/embedded.js';
9
+ import type { Diagnostic } from '../core/diagnostic.js';
10
+ import type { HtmlMustacheConfig, RulesConfig, RuleSeverity, CustomRule as CustomRuleType } from '../core/configSchema.js';
11
+ import type { CustomCodeTagConfig } from '../core/customCodeTags.js';
12
+ export type Config = Omit<HtmlMustacheConfig, 'include' | 'exclude'>;
13
+ export type CustomRule = CustomRuleType;
14
+ export type CustomTag = CustomCodeTagConfig;
15
+ export type { RulesConfig, RuleSeverity, PrettierLike, Diagnostic };
16
+ export type LocateWasm = string | ((filename: string) => string);
17
+ export interface CreateLinterOptions {
18
+ /**
19
+ * Locates the grammar WASM (`tree-sitter-htmlmustache.wasm`). If a string,
20
+ * treated as the URL for the grammar — web-tree-sitter's own
21
+ * `tree-sitter.wasm` will resolve via its default `locateFile`. Pass a
22
+ * callback to resolve both names explicitly.
23
+ */
24
+ locateWasm: LocateWasm;
25
+ /** Default prettier used for embedded-region formatting. */
26
+ prettier?: PrettierLike;
27
+ }
28
+ export interface FormatOptions {
29
+ /** Override the factory-level prettier for this call. */
30
+ prettier?: PrettierLike;
31
+ }
32
+ export interface Linter {
33
+ lint(source: string, config?: Config): Diagnostic[];
34
+ format(source: string, config?: Config, opts?: FormatOptions): Promise<string>;
35
+ }
36
+ /** Default severities for every built-in rule. */
37
+ export declare const DEFAULT_CONFIG: Config;
38
+ /**
39
+ * Create a linter/formatter handle. Consumers should cache the result — each
40
+ * call reloads the grammar WASM.
41
+ */
42
+ export declare function createLinter(opts: CreateLinterOptions): Promise<Linter>;
43
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/browser/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAWH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAGnE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,KAAK,EACV,kBAAkB,EAClB,WAAW,EACX,YAAY,EACZ,UAAU,IAAI,cAAc,EAC7B,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAErE,MAAM,MAAM,MAAM,GAAG,IAAI,CAAC,kBAAkB,EAAE,SAAS,GAAG,SAAS,CAAC,CAAC;AACrE,MAAM,MAAM,UAAU,GAAG,cAAc,CAAC;AACxC,MAAM,MAAM,SAAS,GAAG,mBAAmB,CAAC;AAC5C,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC;AAEpE,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC;AAEjE,MAAM,WAAW,mBAAmB;IAClC;;;;;OAKG;IACH,UAAU,EAAE,UAAU,CAAC;IACvB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,yDAAyD;IACzD,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB;AAED,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,UAAU,EAAE,CAAC;IACpD,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAChF;AAED,kDAAkD;AAClD,eAAO,MAAM,cAAc,EAAE,MAAgD,CAAC;AAc9E;;;GAGG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAiD7E"}