@reteps/tree-sitter-htmlmustache 0.0.34 → 0.0.35
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 +29 -11
- package/cli/out/main.js +202 -167
- package/grammar.js +7 -1
- package/package.json +8 -6
- package/tree-sitter-htmlmustache.wasm +0 -0
package/README.md
CHANGED
|
@@ -79,6 +79,12 @@ Check templates for parse errors:
|
|
|
79
79
|
htmlmustache check '**/*.mustache' '**/*.hbs'
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
+
If `include` is configured in `.htmlmustache.jsonc`, patterns are optional:
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
htmlmustache check
|
|
86
|
+
```
|
|
87
|
+
|
|
82
88
|
```
|
|
83
89
|
file.mustache:3:3 error: Mismatched mustache section: {{/wrong}}
|
|
84
90
|
|
|
|
@@ -100,6 +106,12 @@ Format templates:
|
|
|
100
106
|
htmlmustache format --write '**/*.mustache'
|
|
101
107
|
```
|
|
102
108
|
|
|
109
|
+
If `include` is configured in `.htmlmustache.jsonc`, patterns are optional:
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
htmlmustache format --write
|
|
113
|
+
```
|
|
114
|
+
|
|
103
115
|
Check formatting in CI (exits 1 if any files would change):
|
|
104
116
|
|
|
105
117
|
```
|
|
@@ -114,14 +126,14 @@ echo '<div><p>hi</p></div>' | htmlmustache format --stdin
|
|
|
114
126
|
|
|
115
127
|
**Options:**
|
|
116
128
|
|
|
117
|
-
| Flag
|
|
118
|
-
|
|
|
119
|
-
| `--write`
|
|
120
|
-
| `--check`
|
|
121
|
-
| `--stdin`
|
|
122
|
-
| `--indent-size N`
|
|
123
|
-
| `--print-width N`
|
|
124
|
-
| `--mustache-spaces`
|
|
129
|
+
| Flag | Description |
|
|
130
|
+
| ------------------- | ------------------------------------------------ |
|
|
131
|
+
| `--write` | Modify files in-place (default: print to stdout) |
|
|
132
|
+
| `--check` | Exit 1 if any files would change (for CI) |
|
|
133
|
+
| `--stdin` | Read from stdin, write to stdout |
|
|
134
|
+
| `--indent-size N` | Spaces per indent level (default: 2) |
|
|
135
|
+
| `--print-width N` | Max line width (default: 80) |
|
|
136
|
+
| `--mustache-spaces` | Add spaces inside mustache delimiters |
|
|
125
137
|
|
|
126
138
|
## Configuration
|
|
127
139
|
|
|
@@ -131,6 +143,12 @@ Create a `.htmlmustache.jsonc` file in your project root to configure formatting
|
|
|
131
143
|
|
|
132
144
|
```jsonc
|
|
133
145
|
{
|
|
146
|
+
// File patterns for CLI commands (used when no patterns are passed as arguments)
|
|
147
|
+
"include": ["**/*.mustache", "**/*.hbs"],
|
|
148
|
+
|
|
149
|
+
// Patterns to always exclude (node_modules and .git are excluded by default)
|
|
150
|
+
"exclude": ["**/vendor/**"],
|
|
151
|
+
|
|
134
152
|
// Max line width before wrapping (default: 80)
|
|
135
153
|
"printWidth": 100,
|
|
136
154
|
|
|
@@ -144,9 +162,9 @@ Create a `.htmlmustache.jsonc` file in your project root to configure formatting
|
|
|
144
162
|
"customCodeTags": [
|
|
145
163
|
{
|
|
146
164
|
"name": "x-code",
|
|
147
|
-
"languageDefault": "javascript"
|
|
148
|
-
}
|
|
149
|
-
]
|
|
165
|
+
"languageDefault": "javascript",
|
|
166
|
+
},
|
|
167
|
+
],
|
|
150
168
|
}
|
|
151
169
|
```
|
|
152
170
|
|
package/cli/out/main.js
CHANGED
|
@@ -1580,29 +1580,142 @@ var import_chalk3 = __toESM(require_source());
|
|
|
1580
1580
|
var import_node_fs = __toESM(require("node:fs"));
|
|
1581
1581
|
var import_node_path = __toESM(require("node:path"));
|
|
1582
1582
|
var import_chalk = __toESM(require_source());
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1583
|
+
|
|
1584
|
+
// cli/src/wasm.ts
|
|
1585
|
+
var path = __toESM(require("node:path"));
|
|
1586
|
+
var import_web_tree_sitter = require("web-tree-sitter");
|
|
1587
|
+
var parser;
|
|
1588
|
+
async function initializeParser() {
|
|
1589
|
+
await import_web_tree_sitter.Parser.init();
|
|
1590
|
+
parser = new import_web_tree_sitter.Parser();
|
|
1591
|
+
const wasmPath = path.resolve(__dirname, "..", "..", "tree-sitter-htmlmustache.wasm");
|
|
1592
|
+
const language = await import_web_tree_sitter.Language.load(wasmPath);
|
|
1593
|
+
parser.setLanguage(language);
|
|
1594
|
+
}
|
|
1595
|
+
function parseDocument(source) {
|
|
1596
|
+
const tree = parser.parse(source);
|
|
1597
|
+
if (!tree) {
|
|
1598
|
+
throw new Error("Failed to parse document");
|
|
1592
1599
|
}
|
|
1593
|
-
|
|
1600
|
+
return tree;
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
// lsp/server/src/configFile.ts
|
|
1604
|
+
var fs = __toESM(require("fs"));
|
|
1605
|
+
var path2 = __toESM(require("path"));
|
|
1606
|
+
var CONFIG_FILENAME = ".htmlmustache.jsonc";
|
|
1607
|
+
function parseJsonc(text2) {
|
|
1608
|
+
let result = "";
|
|
1609
|
+
let i = 0;
|
|
1610
|
+
while (i < text2.length) {
|
|
1611
|
+
if (text2[i] === '"') {
|
|
1612
|
+
result += '"';
|
|
1613
|
+
i++;
|
|
1614
|
+
while (i < text2.length && text2[i] !== '"') {
|
|
1615
|
+
if (text2[i] === "\\") {
|
|
1616
|
+
result += text2[i] + (text2[i + 1] ?? "");
|
|
1617
|
+
i += 2;
|
|
1618
|
+
} else {
|
|
1619
|
+
result += text2[i];
|
|
1620
|
+
i++;
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
if (i < text2.length) {
|
|
1624
|
+
result += '"';
|
|
1625
|
+
i++;
|
|
1626
|
+
}
|
|
1627
|
+
continue;
|
|
1628
|
+
}
|
|
1629
|
+
if (text2[i] === "/" && text2[i + 1] === "/") {
|
|
1630
|
+
while (i < text2.length && text2[i] !== "\n") i++;
|
|
1631
|
+
continue;
|
|
1632
|
+
}
|
|
1633
|
+
if (text2[i] === "/" && text2[i + 1] === "*") {
|
|
1634
|
+
i += 2;
|
|
1635
|
+
while (i < text2.length && !(text2[i] === "*" && text2[i + 1] === "/")) i++;
|
|
1636
|
+
i += 2;
|
|
1637
|
+
continue;
|
|
1638
|
+
}
|
|
1639
|
+
result += text2[i];
|
|
1640
|
+
i++;
|
|
1641
|
+
}
|
|
1642
|
+
result = result.replace(/,\s*([}\]])/g, "$1");
|
|
1643
|
+
return JSON.parse(result);
|
|
1644
|
+
}
|
|
1645
|
+
function findConfigFile(startDir) {
|
|
1646
|
+
let dir = path2.resolve(startDir);
|
|
1647
|
+
const root = path2.parse(dir).root;
|
|
1648
|
+
while (true) {
|
|
1649
|
+
const candidate = path2.join(dir, CONFIG_FILENAME);
|
|
1650
|
+
try {
|
|
1651
|
+
fs.accessSync(candidate, fs.constants.R_OK);
|
|
1652
|
+
return candidate;
|
|
1653
|
+
} catch {
|
|
1654
|
+
}
|
|
1655
|
+
const parent = path2.dirname(dir);
|
|
1656
|
+
if (parent === dir || dir === root) return null;
|
|
1657
|
+
dir = parent;
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
var VALID_INDENT_MODES = /* @__PURE__ */ new Set(["never", "always", "attribute"]);
|
|
1661
|
+
function validateConfig(raw) {
|
|
1662
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return {};
|
|
1663
|
+
const obj = raw;
|
|
1664
|
+
const config = {};
|
|
1665
|
+
if (typeof obj.printWidth === "number" && obj.printWidth > 0) {
|
|
1666
|
+
config.printWidth = obj.printWidth;
|
|
1667
|
+
}
|
|
1668
|
+
if (typeof obj.indentSize === "number" && obj.indentSize > 0) {
|
|
1669
|
+
config.indentSize = obj.indentSize;
|
|
1670
|
+
}
|
|
1671
|
+
if (typeof obj.mustacheSpaces === "boolean") {
|
|
1672
|
+
config.mustacheSpaces = obj.mustacheSpaces;
|
|
1673
|
+
}
|
|
1674
|
+
if (Array.isArray(obj.include)) {
|
|
1675
|
+
const items = obj.include.filter((s) => typeof s === "string" && s.length > 0);
|
|
1676
|
+
if (items.length > 0) config.include = items;
|
|
1677
|
+
}
|
|
1678
|
+
if (Array.isArray(obj.exclude)) {
|
|
1679
|
+
const items = obj.exclude.filter((s) => typeof s === "string" && s.length > 0);
|
|
1680
|
+
if (items.length > 0) config.exclude = items;
|
|
1681
|
+
}
|
|
1682
|
+
if (Array.isArray(obj.customCodeTags)) {
|
|
1683
|
+
const tags = [];
|
|
1684
|
+
for (const entry of obj.customCodeTags) {
|
|
1685
|
+
if (entry && typeof entry === "object" && "name" in entry) {
|
|
1686
|
+
const e = entry;
|
|
1687
|
+
if (typeof e.name !== "string" || e.name.length === 0) continue;
|
|
1688
|
+
const tag = { name: e.name };
|
|
1689
|
+
if (typeof e.languageAttribute === "string") tag.languageAttribute = e.languageAttribute;
|
|
1690
|
+
if (e.languageMap && typeof e.languageMap === "object" && !Array.isArray(e.languageMap)) {
|
|
1691
|
+
tag.languageMap = e.languageMap;
|
|
1692
|
+
}
|
|
1693
|
+
if (typeof e.languageDefault === "string") tag.languageDefault = e.languageDefault;
|
|
1694
|
+
if (typeof e.indent === "string" && VALID_INDENT_MODES.has(e.indent)) {
|
|
1695
|
+
tag.indent = e.indent;
|
|
1696
|
+
}
|
|
1697
|
+
if (typeof e.indentAttribute === "string") tag.indentAttribute = e.indentAttribute;
|
|
1698
|
+
tags.push(tag);
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
if (tags.length > 0) config.customCodeTags = tags;
|
|
1702
|
+
}
|
|
1703
|
+
return config;
|
|
1704
|
+
}
|
|
1705
|
+
function loadConfigFileForPath(filePath) {
|
|
1706
|
+
const dir = path2.dirname(path2.resolve(filePath));
|
|
1707
|
+
const configPath = findConfigFile(dir);
|
|
1708
|
+
if (!configPath) return null;
|
|
1594
1709
|
try {
|
|
1595
|
-
|
|
1710
|
+
const text2 = fs.readFileSync(configPath, "utf-8");
|
|
1711
|
+
const raw = parseJsonc(text2);
|
|
1712
|
+
return validateConfig(raw);
|
|
1596
1713
|
} catch {
|
|
1597
|
-
|
|
1598
|
-
import_chalk.default.red("Error: could not load tree-sitter-htmlmustache bindings.\n") + 'Run "npm install" in the tree-sitter-htmlmustache root first.'
|
|
1599
|
-
);
|
|
1600
|
-
process.exit(1);
|
|
1714
|
+
return null;
|
|
1601
1715
|
}
|
|
1602
|
-
const parser2 = new Parser2();
|
|
1603
|
-
parser2.setLanguage(language);
|
|
1604
|
-
return parser2;
|
|
1605
1716
|
}
|
|
1717
|
+
|
|
1718
|
+
// cli/src/check.ts
|
|
1606
1719
|
function errorMessageForNode(nodeType, node) {
|
|
1607
1720
|
if (nodeType === "mustache_erroneous_section_end" || nodeType === "mustache_erroneous_inverted_section_end") {
|
|
1608
1721
|
const tagNameNode = node.children.find((c) => c.type === "mustache_erroneous_tag_name");
|
|
@@ -1707,36 +1820,81 @@ function expandGlobs(patterns) {
|
|
|
1707
1820
|
}
|
|
1708
1821
|
return [...files].sort();
|
|
1709
1822
|
}
|
|
1710
|
-
var
|
|
1823
|
+
var DEFAULT_EXCLUDE_SEGMENTS = ["/node_modules/", "/.git/"];
|
|
1824
|
+
function resolveFiles(cliPatterns) {
|
|
1825
|
+
const configPath = findConfigFile(process.cwd());
|
|
1826
|
+
let config = null;
|
|
1827
|
+
if (configPath) {
|
|
1828
|
+
try {
|
|
1829
|
+
const text2 = import_node_fs.default.readFileSync(configPath, "utf-8");
|
|
1830
|
+
const raw = parseJsonc(text2);
|
|
1831
|
+
config = validateConfig(raw);
|
|
1832
|
+
} catch {
|
|
1833
|
+
config = null;
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
let patterns;
|
|
1837
|
+
if (cliPatterns.length > 0) {
|
|
1838
|
+
patterns = cliPatterns;
|
|
1839
|
+
} else if (config?.include && config.include.length > 0) {
|
|
1840
|
+
patterns = config.include;
|
|
1841
|
+
} else {
|
|
1842
|
+
return { files: [], config };
|
|
1843
|
+
}
|
|
1844
|
+
let files = expandGlobs(patterns);
|
|
1845
|
+
files = files.filter((f) => !DEFAULT_EXCLUDE_SEGMENTS.some((seg) => f.includes(seg)));
|
|
1846
|
+
if (config?.exclude && config.exclude.length > 0) {
|
|
1847
|
+
const cwd = process.cwd();
|
|
1848
|
+
const excludeSet = /* @__PURE__ */ new Set();
|
|
1849
|
+
for (const pattern of config.exclude) {
|
|
1850
|
+
if (!pattern.includes("*") && !pattern.includes("?")) {
|
|
1851
|
+
excludeSet.add(import_node_path.default.resolve(cwd, pattern));
|
|
1852
|
+
} else {
|
|
1853
|
+
for (const match of import_node_fs.default.globSync(pattern, { cwd })) {
|
|
1854
|
+
excludeSet.add(import_node_path.default.resolve(cwd, match));
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
files = files.filter((f) => !excludeSet.has(f));
|
|
1859
|
+
}
|
|
1860
|
+
return { files, config };
|
|
1861
|
+
}
|
|
1862
|
+
var USAGE = `Usage: htmlmustache check [patterns...]
|
|
1711
1863
|
|
|
1712
1864
|
Check HTML Mustache templates for errors.
|
|
1713
1865
|
|
|
1714
1866
|
Arguments:
|
|
1715
|
-
patterns One or more glob patterns (
|
|
1867
|
+
patterns One or more glob patterns (optional if "include" is set in config)
|
|
1716
1868
|
|
|
1717
1869
|
Options:
|
|
1718
1870
|
--help Show this help message
|
|
1719
1871
|
|
|
1720
1872
|
Examples:
|
|
1721
1873
|
htmlmustache check '**/*.mustache'
|
|
1722
|
-
htmlmustache check 'templates/**/*.hbs' 'partials/**/*.mustache'
|
|
1723
|
-
|
|
1874
|
+
htmlmustache check 'templates/**/*.hbs' 'partials/**/*.mustache'
|
|
1875
|
+
htmlmustache check (uses "include" from .htmlmustache.jsonc)`;
|
|
1876
|
+
async function run(args) {
|
|
1724
1877
|
if (args[0] === "check") {
|
|
1725
1878
|
args = args.slice(1);
|
|
1726
1879
|
}
|
|
1727
|
-
if (args.includes("--help")
|
|
1880
|
+
if (args.includes("--help")) {
|
|
1728
1881
|
console.log(USAGE);
|
|
1729
|
-
return
|
|
1882
|
+
return 0;
|
|
1730
1883
|
}
|
|
1731
|
-
const files =
|
|
1884
|
+
const { files, config } = resolveFiles(args);
|
|
1732
1885
|
if (files.length === 0) {
|
|
1886
|
+
if (args.length === 0 && (!config?.include || config.include.length === 0)) {
|
|
1887
|
+
console.log(USAGE);
|
|
1888
|
+
return 1;
|
|
1889
|
+
}
|
|
1890
|
+
const patterns = args.length > 0 ? args : config?.include ?? [];
|
|
1733
1891
|
console.error(import_chalk.default.yellow("No files matched the given patterns:"));
|
|
1734
|
-
for (const
|
|
1735
|
-
console.error(import_chalk.default.yellow(` ${
|
|
1892
|
+
for (const p of patterns) {
|
|
1893
|
+
console.error(import_chalk.default.yellow(` ${p}`));
|
|
1736
1894
|
}
|
|
1737
1895
|
return 1;
|
|
1738
1896
|
}
|
|
1739
|
-
|
|
1897
|
+
await initializeParser();
|
|
1740
1898
|
let totalErrors = 0;
|
|
1741
1899
|
let filesWithErrors = 0;
|
|
1742
1900
|
const cwd = process.cwd();
|
|
@@ -1744,7 +1902,7 @@ function run(args) {
|
|
|
1744
1902
|
for (const file of files) {
|
|
1745
1903
|
const displayPath = import_node_path.default.relative(cwd, file) || file;
|
|
1746
1904
|
const source = import_node_fs.default.readFileSync(file, "utf-8");
|
|
1747
|
-
const tree =
|
|
1905
|
+
const tree = parseDocument(source);
|
|
1748
1906
|
const errors = collectErrors(tree, displayPath);
|
|
1749
1907
|
if (errors.length > 0) {
|
|
1750
1908
|
filesWithErrors++;
|
|
@@ -2524,7 +2682,7 @@ function shouldTreatAsBlock(node, index, nodes) {
|
|
|
2524
2682
|
}
|
|
2525
2683
|
|
|
2526
2684
|
// lsp/server/src/customCodeTags.ts
|
|
2527
|
-
var
|
|
2685
|
+
var VALID_INDENT_MODES2 = /* @__PURE__ */ new Set(["never", "always", "attribute"]);
|
|
2528
2686
|
function parseCustomCodeTagSettings(tags) {
|
|
2529
2687
|
const tagNames = [];
|
|
2530
2688
|
const configs = [];
|
|
@@ -2535,7 +2693,7 @@ function parseCustomCodeTagSettings(tags) {
|
|
|
2535
2693
|
if (typeof t.languageAttribute === "string") config.languageAttribute = t.languageAttribute;
|
|
2536
2694
|
if (t.languageMap && typeof t.languageMap === "object") config.languageMap = t.languageMap;
|
|
2537
2695
|
if (typeof t.languageDefault === "string") config.languageDefault = t.languageDefault;
|
|
2538
|
-
if (typeof t.indent === "string" &&
|
|
2696
|
+
if (typeof t.indent === "string" && VALID_INDENT_MODES2.has(t.indent)) {
|
|
2539
2697
|
config.indent = t.indent;
|
|
2540
2698
|
}
|
|
2541
2699
|
if (typeof t.indentAttribute === "string") config.indentAttribute = t.indentAttribute;
|
|
@@ -3278,139 +3436,13 @@ function buildConfigMap(configs) {
|
|
|
3278
3436
|
return map;
|
|
3279
3437
|
}
|
|
3280
3438
|
|
|
3281
|
-
// lsp/server/src/configFile.ts
|
|
3282
|
-
var fs2 = __toESM(require("fs"));
|
|
3283
|
-
var path2 = __toESM(require("path"));
|
|
3284
|
-
var CONFIG_FILENAME = ".htmlmustache.jsonc";
|
|
3285
|
-
function parseJsonc(text2) {
|
|
3286
|
-
let result = "";
|
|
3287
|
-
let i = 0;
|
|
3288
|
-
while (i < text2.length) {
|
|
3289
|
-
if (text2[i] === '"') {
|
|
3290
|
-
result += '"';
|
|
3291
|
-
i++;
|
|
3292
|
-
while (i < text2.length && text2[i] !== '"') {
|
|
3293
|
-
if (text2[i] === "\\") {
|
|
3294
|
-
result += text2[i] + (text2[i + 1] ?? "");
|
|
3295
|
-
i += 2;
|
|
3296
|
-
} else {
|
|
3297
|
-
result += text2[i];
|
|
3298
|
-
i++;
|
|
3299
|
-
}
|
|
3300
|
-
}
|
|
3301
|
-
if (i < text2.length) {
|
|
3302
|
-
result += '"';
|
|
3303
|
-
i++;
|
|
3304
|
-
}
|
|
3305
|
-
continue;
|
|
3306
|
-
}
|
|
3307
|
-
if (text2[i] === "/" && text2[i + 1] === "/") {
|
|
3308
|
-
while (i < text2.length && text2[i] !== "\n") i++;
|
|
3309
|
-
continue;
|
|
3310
|
-
}
|
|
3311
|
-
if (text2[i] === "/" && text2[i + 1] === "*") {
|
|
3312
|
-
i += 2;
|
|
3313
|
-
while (i < text2.length && !(text2[i] === "*" && text2[i + 1] === "/")) i++;
|
|
3314
|
-
i += 2;
|
|
3315
|
-
continue;
|
|
3316
|
-
}
|
|
3317
|
-
result += text2[i];
|
|
3318
|
-
i++;
|
|
3319
|
-
}
|
|
3320
|
-
result = result.replace(/,\s*([}\]])/g, "$1");
|
|
3321
|
-
return JSON.parse(result);
|
|
3322
|
-
}
|
|
3323
|
-
function findConfigFile(startDir) {
|
|
3324
|
-
let dir = path2.resolve(startDir);
|
|
3325
|
-
const root = path2.parse(dir).root;
|
|
3326
|
-
while (true) {
|
|
3327
|
-
const candidate = path2.join(dir, CONFIG_FILENAME);
|
|
3328
|
-
try {
|
|
3329
|
-
fs2.accessSync(candidate, fs2.constants.R_OK);
|
|
3330
|
-
return candidate;
|
|
3331
|
-
} catch {
|
|
3332
|
-
}
|
|
3333
|
-
const parent = path2.dirname(dir);
|
|
3334
|
-
if (parent === dir || dir === root) return null;
|
|
3335
|
-
dir = parent;
|
|
3336
|
-
}
|
|
3337
|
-
}
|
|
3338
|
-
var VALID_INDENT_MODES2 = /* @__PURE__ */ new Set(["never", "always", "attribute"]);
|
|
3339
|
-
function validateConfig(raw) {
|
|
3340
|
-
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return {};
|
|
3341
|
-
const obj = raw;
|
|
3342
|
-
const config = {};
|
|
3343
|
-
if (typeof obj.printWidth === "number" && obj.printWidth > 0) {
|
|
3344
|
-
config.printWidth = obj.printWidth;
|
|
3345
|
-
}
|
|
3346
|
-
if (typeof obj.indentSize === "number" && obj.indentSize > 0) {
|
|
3347
|
-
config.indentSize = obj.indentSize;
|
|
3348
|
-
}
|
|
3349
|
-
if (typeof obj.mustacheSpaces === "boolean") {
|
|
3350
|
-
config.mustacheSpaces = obj.mustacheSpaces;
|
|
3351
|
-
}
|
|
3352
|
-
if (Array.isArray(obj.customCodeTags)) {
|
|
3353
|
-
const tags = [];
|
|
3354
|
-
for (const entry of obj.customCodeTags) {
|
|
3355
|
-
if (entry && typeof entry === "object" && "name" in entry) {
|
|
3356
|
-
const e = entry;
|
|
3357
|
-
if (typeof e.name !== "string" || e.name.length === 0) continue;
|
|
3358
|
-
const tag = { name: e.name };
|
|
3359
|
-
if (typeof e.languageAttribute === "string") tag.languageAttribute = e.languageAttribute;
|
|
3360
|
-
if (e.languageMap && typeof e.languageMap === "object" && !Array.isArray(e.languageMap)) {
|
|
3361
|
-
tag.languageMap = e.languageMap;
|
|
3362
|
-
}
|
|
3363
|
-
if (typeof e.languageDefault === "string") tag.languageDefault = e.languageDefault;
|
|
3364
|
-
if (typeof e.indent === "string" && VALID_INDENT_MODES2.has(e.indent)) {
|
|
3365
|
-
tag.indent = e.indent;
|
|
3366
|
-
}
|
|
3367
|
-
if (typeof e.indentAttribute === "string") tag.indentAttribute = e.indentAttribute;
|
|
3368
|
-
tags.push(tag);
|
|
3369
|
-
}
|
|
3370
|
-
}
|
|
3371
|
-
if (tags.length > 0) config.customCodeTags = tags;
|
|
3372
|
-
}
|
|
3373
|
-
return config;
|
|
3374
|
-
}
|
|
3375
|
-
function loadConfigFileForPath(filePath) {
|
|
3376
|
-
const dir = path2.dirname(path2.resolve(filePath));
|
|
3377
|
-
const configPath = findConfigFile(dir);
|
|
3378
|
-
if (!configPath) return null;
|
|
3379
|
-
try {
|
|
3380
|
-
const text2 = fs2.readFileSync(configPath, "utf-8");
|
|
3381
|
-
const raw = parseJsonc(text2);
|
|
3382
|
-
return validateConfig(raw);
|
|
3383
|
-
} catch {
|
|
3384
|
-
return null;
|
|
3385
|
-
}
|
|
3386
|
-
}
|
|
3387
|
-
|
|
3388
|
-
// cli/src/wasm.ts
|
|
3389
|
-
var path3 = __toESM(require("node:path"));
|
|
3390
|
-
var import_web_tree_sitter = require("web-tree-sitter");
|
|
3391
|
-
var parser;
|
|
3392
|
-
async function initializeParser() {
|
|
3393
|
-
await import_web_tree_sitter.Parser.init();
|
|
3394
|
-
parser = new import_web_tree_sitter.Parser();
|
|
3395
|
-
const wasmPath = path3.resolve(__dirname, "..", "..", "tree-sitter-htmlmustache.wasm");
|
|
3396
|
-
const language = await import_web_tree_sitter.Language.load(wasmPath);
|
|
3397
|
-
parser.setLanguage(language);
|
|
3398
|
-
}
|
|
3399
|
-
function parseDocument(source) {
|
|
3400
|
-
const tree = parser.parse(source);
|
|
3401
|
-
if (!tree) {
|
|
3402
|
-
throw new Error("Failed to parse document");
|
|
3403
|
-
}
|
|
3404
|
-
return tree;
|
|
3405
|
-
}
|
|
3406
|
-
|
|
3407
3439
|
// cli/src/format.ts
|
|
3408
|
-
var USAGE2 = `Usage: htmlmustache format [options]
|
|
3440
|
+
var USAGE2 = `Usage: htmlmustache format [options] [patterns...]
|
|
3409
3441
|
|
|
3410
3442
|
Format HTML Mustache templates.
|
|
3411
3443
|
|
|
3412
3444
|
Arguments:
|
|
3413
|
-
patterns One or more glob patterns (
|
|
3445
|
+
patterns One or more glob patterns (optional if "include" is set in config)
|
|
3414
3446
|
|
|
3415
3447
|
Options:
|
|
3416
3448
|
--write Modify files in-place (default: print to stdout)
|
|
@@ -3424,6 +3456,7 @@ Options:
|
|
|
3424
3456
|
Examples:
|
|
3425
3457
|
htmlmustache format --write '**/*.mustache'
|
|
3426
3458
|
htmlmustache format --check 'templates/**/*.hbs'
|
|
3459
|
+
htmlmustache format --write (uses "include" from .htmlmustache.jsonc)
|
|
3427
3460
|
echo '<div><p>hi</p></div>' | htmlmustache format --stdin`;
|
|
3428
3461
|
function parseFlags(args) {
|
|
3429
3462
|
const flags = {
|
|
@@ -3527,26 +3560,28 @@ async function run2(args) {
|
|
|
3527
3560
|
return 0;
|
|
3528
3561
|
}
|
|
3529
3562
|
const flags = parseFlags(args);
|
|
3530
|
-
if (!flags.stdin && flags.patterns.length === 0) {
|
|
3531
|
-
console.log(USAGE2);
|
|
3532
|
-
return 1;
|
|
3533
|
-
}
|
|
3534
|
-
await initializeParser();
|
|
3535
3563
|
if (flags.stdin) {
|
|
3564
|
+
await initializeParser();
|
|
3536
3565
|
const { options, ...params } = resolveSettings(flags);
|
|
3537
3566
|
const source = import_node_fs2.default.readFileSync(0, "utf-8");
|
|
3538
3567
|
const formatted = formatSource(source, options, params);
|
|
3539
3568
|
process.stdout.write(formatted);
|
|
3540
3569
|
return 0;
|
|
3541
3570
|
}
|
|
3542
|
-
const files =
|
|
3571
|
+
const { files, config } = resolveFiles(flags.patterns);
|
|
3543
3572
|
if (files.length === 0) {
|
|
3573
|
+
if (flags.patterns.length === 0 && (!config?.include || config.include.length === 0)) {
|
|
3574
|
+
console.log(USAGE2);
|
|
3575
|
+
return 1;
|
|
3576
|
+
}
|
|
3577
|
+
const patterns = flags.patterns.length > 0 ? flags.patterns : config?.include ?? [];
|
|
3544
3578
|
console.error(import_chalk2.default.yellow("No files matched the given patterns:"));
|
|
3545
|
-
for (const pattern of
|
|
3579
|
+
for (const pattern of patterns) {
|
|
3546
3580
|
console.error(import_chalk2.default.yellow(` ${pattern}`));
|
|
3547
3581
|
}
|
|
3548
3582
|
return 1;
|
|
3549
3583
|
}
|
|
3584
|
+
await initializeParser();
|
|
3550
3585
|
const cwd = process.cwd();
|
|
3551
3586
|
let changedCount = 0;
|
|
3552
3587
|
for (const file of files) {
|
|
@@ -3593,7 +3628,7 @@ async function main() {
|
|
|
3593
3628
|
const command = args[0];
|
|
3594
3629
|
switch (command) {
|
|
3595
3630
|
case "check":
|
|
3596
|
-
process.exit(run(args));
|
|
3631
|
+
process.exit(await run(args));
|
|
3597
3632
|
break;
|
|
3598
3633
|
case "format":
|
|
3599
3634
|
process.exit(await run2(args));
|
package/grammar.js
CHANGED
|
@@ -218,7 +218,13 @@ module.exports = grammar({
|
|
|
218
218
|
html_erroneous_end_tag: ($) =>
|
|
219
219
|
seq('</', $.html_erroneous_end_tag_name, '>'),
|
|
220
220
|
|
|
221
|
-
_attribute: ($) =>
|
|
221
|
+
_attribute: ($) =>
|
|
222
|
+
choice(
|
|
223
|
+
$.mustache_attribute,
|
|
224
|
+
$.html_attribute,
|
|
225
|
+
$.mustache_interpolation,
|
|
226
|
+
$.mustache_triple,
|
|
227
|
+
),
|
|
222
228
|
html_attribute: ($) =>
|
|
223
229
|
seq(
|
|
224
230
|
seq(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reteps/tree-sitter-htmlmustache",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.35",
|
|
4
4
|
"description": "HTML with Mustache/Handlebars template syntax grammar for tree-sitter",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -37,12 +37,14 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"chalk": "^4.1.2",
|
|
39
39
|
"editorconfig": "^2.0.1",
|
|
40
|
-
"node-addon-api": "^8.2.2",
|
|
41
|
-
"node-gyp-build": "^4.8.2",
|
|
42
|
-
"tree-sitter": "^0.25.0",
|
|
43
40
|
"vscode-languageserver-textdocument": "^1.0.12",
|
|
44
41
|
"web-tree-sitter": "^0.25.0"
|
|
45
42
|
},
|
|
43
|
+
"optionalDependencies": {
|
|
44
|
+
"node-addon-api": "^8.2.2",
|
|
45
|
+
"node-gyp-build": "^4.8.2",
|
|
46
|
+
"tree-sitter": "^0.25.0"
|
|
47
|
+
},
|
|
46
48
|
"devDependencies": {
|
|
47
49
|
"@eslint/js": "^9.39.2",
|
|
48
50
|
"@types/node": "^22.19.11",
|
|
@@ -65,9 +67,9 @@
|
|
|
65
67
|
]
|
|
66
68
|
},
|
|
67
69
|
"scripts": {
|
|
68
|
-
"install": "node-gyp-build",
|
|
70
|
+
"install": "node-gyp-build || exit 0",
|
|
69
71
|
"build": "tree-sitter build --wasm",
|
|
70
|
-
"prepack": "node cli/esbuild.mjs",
|
|
72
|
+
"prepack": "tree-sitter build --wasm && node cli/esbuild.mjs",
|
|
71
73
|
"build:cli": "node cli/esbuild.mjs",
|
|
72
74
|
"check": "node cli/out/check.js check",
|
|
73
75
|
"lint": "eslint .",
|
|
Binary file
|