@reteps/tree-sitter-htmlmustache 0.2.1 → 0.3.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/cli/out/main.js CHANGED
@@ -1715,16 +1715,39 @@ function loadConfigFileForPath(filePath) {
1715
1715
  }
1716
1716
  }
1717
1717
 
1718
- // lsp/server/src/htmlBalanceChecker.ts
1719
- function getTagName(element) {
1720
- const startTag = element.children.find((c) => c.type === "html_start_tag");
1721
- if (!startTag) return null;
1722
- const tagNameNode = startTag.children.find((c) => c.type === "html_tag_name");
1723
- return tagNameNode?.text?.toLowerCase() ?? null;
1718
+ // lsp/server/src/nodeHelpers.ts
1719
+ var MUSTACHE_SECTION_TYPES = /* @__PURE__ */ new Set([
1720
+ "mustache_section",
1721
+ "mustache_inverted_section"
1722
+ ]);
1723
+ var RAW_CONTENT_ELEMENT_TYPES = /* @__PURE__ */ new Set([
1724
+ "html_script_element",
1725
+ "html_style_element",
1726
+ "html_raw_element"
1727
+ ]);
1728
+ var HTML_ELEMENT_TYPES = /* @__PURE__ */ new Set([
1729
+ "html_element",
1730
+ "html_script_element",
1731
+ "html_style_element",
1732
+ "html_raw_element"
1733
+ ]);
1734
+ function isMustacheSection(node) {
1735
+ return MUSTACHE_SECTION_TYPES.has(node.type);
1724
1736
  }
1725
- function getErroneousEndTagName(node) {
1726
- const nameNode = node.children.find((c) => c.type === "html_erroneous_end_tag_name");
1727
- return nameNode?.text?.toLowerCase() ?? null;
1737
+ function isRawContentElement(node) {
1738
+ return RAW_CONTENT_ELEMENT_TYPES.has(node.type);
1739
+ }
1740
+ function isHtmlElementType(node) {
1741
+ return HTML_ELEMENT_TYPES.has(node.type);
1742
+ }
1743
+ function getTagName(node) {
1744
+ for (const child of node.children) {
1745
+ if (child.type === "html_start_tag" || child.type === "html_self_closing_tag") {
1746
+ const tagNameNode = child.children.find((c) => c.type === "html_tag_name");
1747
+ if (tagNameNode) return tagNameNode.text;
1748
+ }
1749
+ }
1750
+ return null;
1728
1751
  }
1729
1752
  function getSectionName(node) {
1730
1753
  const beginNode = node.children.find(
@@ -1734,6 +1757,18 @@ function getSectionName(node) {
1734
1757
  const tagNameNode = beginNode.children.find((c) => c.type === "mustache_tag_name");
1735
1758
  return tagNameNode?.text ?? null;
1736
1759
  }
1760
+ function getErroneousEndTagName(node) {
1761
+ const nameNode = node.children.find((c) => c.type === "html_erroneous_end_tag_name");
1762
+ return nameNode?.text?.toLowerCase() ?? null;
1763
+ }
1764
+
1765
+ // lsp/server/src/htmlBalanceChecker.ts
1766
+ function getTagNameLower(element) {
1767
+ return getTagName(element)?.toLowerCase() ?? null;
1768
+ }
1769
+ function getErroneousEndTagNameLower(node) {
1770
+ return getErroneousEndTagName(node)?.toLowerCase() ?? null;
1771
+ }
1737
1772
  function hasForcedEndTag(element) {
1738
1773
  return element.children.some((c) => c.type === "html_forced_end_tag");
1739
1774
  }
@@ -1750,7 +1785,7 @@ function extractFromNode(node) {
1750
1785
  (c) => c.type !== "html_start_tag" && c.type !== "html_end_tag" && c.type !== "html_forced_end_tag"
1751
1786
  );
1752
1787
  if (hasForcedEndTag(node)) {
1753
- const tagName = getTagName(node);
1788
+ const tagName = getTagNameLower(node);
1754
1789
  const items = [];
1755
1790
  if (tagName) {
1756
1791
  const startTag = node.children.find((c) => c.type === "html_start_tag");
@@ -1765,7 +1800,7 @@ function extractFromNode(node) {
1765
1800
  return [];
1766
1801
  }
1767
1802
  if (node.type === "html_erroneous_end_tag") {
1768
- const tagName = getErroneousEndTagName(node);
1803
+ const tagName = getErroneousEndTagNameLower(node);
1769
1804
  if (tagName) {
1770
1805
  return [{ type: "close", tagName, node }];
1771
1806
  }
@@ -1967,7 +2002,7 @@ function checkUnclosedTags(rootNode) {
1967
2002
  const hasEndTag = node.children.some((c) => c.type === "html_end_tag");
1968
2003
  const hasForcedEnd = node.children.some((c) => c.type === "html_forced_end_tag");
1969
2004
  if (!hasEndTag && !hasForcedEnd) {
1970
- const tagName = getTagName(node);
2005
+ const tagName = getTagNameLower(node);
1971
2006
  if (tagName && !VOID_ELEMENTS.has(tagName) && !OPTIONAL_END_TAG_ELEMENTS.has(tagName)) {
1972
2007
  const startTag = node.children.find((c) => c.type === "html_start_tag");
1973
2008
  errors.push({
@@ -2017,7 +2052,7 @@ function checkHtmlBalance(rootNode) {
2017
2052
  function checkNestedSameNameSections(rootNode) {
2018
2053
  const errors = [];
2019
2054
  function visit(node, ancestors) {
2020
- if (node.type === "mustache_section" || node.type === "mustache_inverted_section") {
2055
+ if (isMustacheSection(node)) {
2021
2056
  const name = getSectionName(node);
2022
2057
  if (name) {
2023
2058
  if (ancestors.has(name)) {
@@ -2077,7 +2112,7 @@ function checkConsecutiveSameNameSections(rootNode, sourceText) {
2077
2112
  for (let i = 0; i < children.length - 1; i++) {
2078
2113
  const current = children[i];
2079
2114
  const next = children[i + 1];
2080
- if (current.type !== "mustache_section" && current.type !== "mustache_inverted_section" || current.type !== next.type) {
2115
+ if (!isMustacheSection(current) || current.type !== next.type) {
2081
2116
  continue;
2082
2117
  }
2083
2118
  const currentName = getSectionName(current);
@@ -2113,6 +2148,58 @@ function checkConsecutiveSameNameSections(rootNode, sourceText) {
2113
2148
  visit(rootNode);
2114
2149
  return errors;
2115
2150
  }
2151
+ var VOID_ELEMENTS2 = /* @__PURE__ */ new Set([
2152
+ "area",
2153
+ "base",
2154
+ "basefont",
2155
+ "bgsound",
2156
+ "br",
2157
+ "col",
2158
+ "command",
2159
+ "embed",
2160
+ "frame",
2161
+ "hr",
2162
+ "image",
2163
+ "img",
2164
+ "input",
2165
+ "isindex",
2166
+ "keygen",
2167
+ "link",
2168
+ "menuitem",
2169
+ "meta",
2170
+ "nextid",
2171
+ "param",
2172
+ "source",
2173
+ "track",
2174
+ "wbr"
2175
+ ]);
2176
+ function checkSelfClosingNonVoidTags(rootNode) {
2177
+ const errors = [];
2178
+ function visit(node) {
2179
+ if (node.type === "html_self_closing_tag") {
2180
+ const tagNameNode = node.children.find((c) => c.type === "html_tag_name");
2181
+ const tagName = tagNameNode?.text.toLowerCase();
2182
+ if (tagName && !VOID_ELEMENTS2.has(tagName)) {
2183
+ errors.push({
2184
+ node,
2185
+ message: `Self-closing non-void element: <${tagNameNode.text}/>`,
2186
+ fix: [{
2187
+ startIndex: node.startIndex,
2188
+ endIndex: node.endIndex,
2189
+ newText: node.text.replace(/\s*\/>$/, ">") + `</${tagNameNode.text}>`
2190
+ }],
2191
+ fixDescription: "Replace self-closing syntax with explicit close tag"
2192
+ });
2193
+ }
2194
+ return;
2195
+ }
2196
+ for (const child of node.children) {
2197
+ visit(child);
2198
+ }
2199
+ }
2200
+ visit(rootNode);
2201
+ return errors;
2202
+ }
2116
2203
  function areMutuallyExclusive(a, b) {
2117
2204
  for (const ac of a) {
2118
2205
  for (const bc of b) {
@@ -2145,9 +2232,7 @@ function collectAttributes(node, conditions, out) {
2145
2232
  out.push({ nameNode, conditions: [...conditions] });
2146
2233
  }
2147
2234
  } else if (child.type === "mustache_attribute") {
2148
- const section = child.children.find(
2149
- (c) => c.type === "mustache_section" || c.type === "mustache_inverted_section"
2150
- );
2235
+ const section = child.children.find((c) => isMustacheSection(c));
2151
2236
  if (section) {
2152
2237
  const name = getSectionName(section);
2153
2238
  if (name) {
@@ -2158,6 +2243,55 @@ function collectAttributes(node, conditions, out) {
2158
2243
  }
2159
2244
  }
2160
2245
  }
2246
+ function checkUnescapedEntities(rootNode) {
2247
+ const errors = [];
2248
+ function visit(node) {
2249
+ if (node.type === "text") {
2250
+ if (node.text === "&") {
2251
+ errors.push({
2252
+ node,
2253
+ message: 'Unescaped "&" in text content \u2014 use &amp; instead',
2254
+ severity: "warning",
2255
+ fix: [{
2256
+ startIndex: node.startIndex,
2257
+ endIndex: node.endIndex,
2258
+ newText: "&amp;"
2259
+ }],
2260
+ fixDescription: "Replace & with &amp;"
2261
+ });
2262
+ return;
2263
+ }
2264
+ if (node.text.includes(">")) {
2265
+ const fixes = [];
2266
+ let searchFrom = 0;
2267
+ const text2 = node.text;
2268
+ while (true) {
2269
+ const idx = text2.indexOf(">", searchFrom);
2270
+ if (idx === -1) break;
2271
+ fixes.push({
2272
+ startIndex: node.startIndex + idx,
2273
+ endIndex: node.startIndex + idx + 1,
2274
+ newText: "&gt;"
2275
+ });
2276
+ searchFrom = idx + 1;
2277
+ }
2278
+ errors.push({
2279
+ node,
2280
+ message: 'Unescaped ">" in text content \u2014 use &gt; instead',
2281
+ severity: "warning",
2282
+ fix: fixes,
2283
+ fixDescription: "Replace > with &gt;"
2284
+ });
2285
+ return;
2286
+ }
2287
+ }
2288
+ for (const child of node.children) {
2289
+ visit(child);
2290
+ }
2291
+ }
2292
+ visit(rootNode);
2293
+ return errors;
2294
+ }
2161
2295
  function checkDuplicateAttributes(rootNode) {
2162
2296
  const errors = [];
2163
2297
  function visit(node) {
@@ -2203,7 +2337,12 @@ function checkDuplicateAttributes(rootNode) {
2203
2337
  return errors;
2204
2338
  }
2205
2339
 
2206
- // cli/src/check.ts
2340
+ // lsp/server/src/collectErrors.ts
2341
+ var ERROR_NODE_TYPES = /* @__PURE__ */ new Set([
2342
+ "ERROR",
2343
+ "mustache_erroneous_section_end",
2344
+ "mustache_erroneous_inverted_section_end"
2345
+ ]);
2207
2346
  function errorMessageForNode(nodeType, node) {
2208
2347
  if (nodeType === "mustache_erroneous_section_end" || nodeType === "mustache_erroneous_inverted_section_end") {
2209
2348
  const tagNameNode = node.children.find((c) => c.type === "mustache_erroneous_tag_name");
@@ -2214,12 +2353,7 @@ function errorMessageForNode(nodeType, node) {
2214
2353
  }
2215
2354
  return `Missing ${nodeType}`;
2216
2355
  }
2217
- var ERROR_NODE_TYPES = /* @__PURE__ */ new Set([
2218
- "ERROR",
2219
- "mustache_erroneous_section_end",
2220
- "mustache_erroneous_inverted_section_end"
2221
- ]);
2222
- function collectErrors(tree, file) {
2356
+ function collectErrors(tree) {
2223
2357
  const errors = [];
2224
2358
  const cursor = tree.walk();
2225
2359
  function visit() {
@@ -2227,13 +2361,8 @@ function collectErrors(tree, file) {
2227
2361
  const nodeType = cursor.nodeType;
2228
2362
  if (ERROR_NODE_TYPES.has(nodeType) || cursor.nodeIsMissing) {
2229
2363
  errors.push({
2230
- file,
2231
- line: node.startPosition.row + 1,
2232
- column: node.startPosition.column + 1,
2233
- endLine: node.endPosition.row + 1,
2234
- endColumn: node.endPosition.column + 1,
2235
- message: errorMessageForNode(nodeType, node),
2236
- nodeText: node.text
2364
+ node,
2365
+ message: errorMessageForNode(nodeType, node)
2237
2366
  });
2238
2367
  if (nodeType === "ERROR") return;
2239
2368
  }
@@ -2245,47 +2374,27 @@ function collectErrors(tree, file) {
2245
2374
  }
2246
2375
  }
2247
2376
  visit();
2248
- const rootNode = tree.rootNode;
2249
- const balanceErrors = checkHtmlBalance(rootNode);
2377
+ const balanceErrors = checkHtmlBalance(tree.rootNode);
2250
2378
  for (const error of balanceErrors) {
2251
- errors.push({
2252
- file,
2253
- line: error.node.startPosition.row + 1,
2254
- column: error.node.startPosition.column + 1,
2255
- endLine: error.node.endPosition.row + 1,
2256
- endColumn: error.node.endPosition.column + 1,
2257
- message: error.message,
2258
- nodeText: error.node.text
2259
- });
2379
+ errors.push({ node: error.node, message: error.message });
2260
2380
  }
2261
- const unclosedErrors = checkUnclosedTags(rootNode);
2381
+ const unclosedErrors = checkUnclosedTags(tree.rootNode);
2262
2382
  for (const error of unclosedErrors) {
2263
- errors.push({
2264
- file,
2265
- line: error.node.startPosition.row + 1,
2266
- column: error.node.startPosition.column + 1,
2267
- endLine: error.node.endPosition.row + 1,
2268
- endColumn: error.node.endPosition.column + 1,
2269
- message: error.message,
2270
- nodeText: error.node.text
2271
- });
2383
+ errors.push({ node: error.node, message: error.message });
2272
2384
  }
2273
- const sourceText = rootNode.text;
2385
+ const sourceText = tree.rootNode.text;
2274
2386
  const mustacheChecks = [
2275
- ...checkNestedSameNameSections(rootNode),
2276
- ...checkUnquotedMustacheAttributes(rootNode),
2277
- ...checkConsecutiveSameNameSections(rootNode, sourceText),
2278
- ...checkDuplicateAttributes(rootNode)
2387
+ ...checkNestedSameNameSections(tree.rootNode),
2388
+ ...checkUnquotedMustacheAttributes(tree.rootNode),
2389
+ ...checkConsecutiveSameNameSections(tree.rootNode, sourceText),
2390
+ ...checkSelfClosingNonVoidTags(tree.rootNode),
2391
+ ...checkDuplicateAttributes(tree.rootNode),
2392
+ ...checkUnescapedEntities(tree.rootNode)
2279
2393
  ];
2280
2394
  for (const error of mustacheChecks) {
2281
2395
  errors.push({
2282
- file,
2283
- line: error.node.startPosition.row + 1,
2284
- column: error.node.startPosition.column + 1,
2285
- endLine: error.node.endPosition.row + 1,
2286
- endColumn: error.node.endPosition.column + 1,
2396
+ node: error.node,
2287
2397
  message: error.message,
2288
- nodeText: error.node.text,
2289
2398
  severity: error.severity,
2290
2399
  fix: error.fix,
2291
2400
  fixDescription: error.fixDescription
@@ -2293,6 +2402,23 @@ function collectErrors(tree, file) {
2293
2402
  }
2294
2403
  return errors;
2295
2404
  }
2405
+
2406
+ // cli/src/check.ts
2407
+ function collectErrors2(tree, file) {
2408
+ const errors = collectErrors(tree);
2409
+ return errors.map((error) => ({
2410
+ file,
2411
+ line: error.node.startPosition.row + 1,
2412
+ column: error.node.startPosition.column + 1,
2413
+ endLine: error.node.endPosition.row + 1,
2414
+ endColumn: error.node.endPosition.column + 1,
2415
+ message: error.message,
2416
+ nodeText: error.node.text,
2417
+ severity: error.severity,
2418
+ fix: error.fix,
2419
+ fixDescription: error.fixDescription
2420
+ }));
2421
+ }
2296
2422
  function formatError(error, source) {
2297
2423
  const lines = source.split("\n");
2298
2424
  const errorLine = error.line - 1;
@@ -2467,7 +2593,7 @@ async function run(args) {
2467
2593
  let source = import_node_fs.default.readFileSync(file, "utf-8");
2468
2594
  if (fixMode) {
2469
2595
  const tree2 = parseDocument(source);
2470
- const errors2 = collectErrors(tree2, displayPath);
2596
+ const errors2 = collectErrors2(tree2, displayPath);
2471
2597
  const fixed = applyFixes(source, errors2);
2472
2598
  if (fixed !== source) {
2473
2599
  import_node_fs.default.writeFileSync(file, fixed, "utf-8");
@@ -2475,7 +2601,7 @@ async function run(args) {
2475
2601
  }
2476
2602
  }
2477
2603
  const tree = parseDocument(source);
2478
- const errors = collectErrors(tree, displayPath);
2604
+ const errors = collectErrors2(tree, displayPath);
2479
2605
  const fileErrors = errors.filter((e) => e.severity !== "warning");
2480
2606
  const fileWarnings = errors.filter((e) => e.severity === "warning");
2481
2607
  if (errors.length > 0) {
@@ -2918,21 +3044,6 @@ function isLine(doc) {
2918
3044
  }
2919
3045
 
2920
3046
  // lsp/server/src/formatting/utils.ts
2921
- function getTagName2(node) {
2922
- for (let i = 0; i < node.childCount; i++) {
2923
- const child = node.child(i);
2924
- if (!child) continue;
2925
- if (child.type === "html_start_tag" || child.type === "html_self_closing_tag") {
2926
- for (let j = 0; j < child.childCount; j++) {
2927
- const tagChild = child.child(j);
2928
- if (tagChild && tagChild.type === "html_tag_name") {
2929
- return tagChild.text;
2930
- }
2931
- }
2932
- }
2933
- }
2934
- return null;
2935
- }
2936
3047
  function normalizeText(text2) {
2937
3048
  return text2.split("\n").map((line2) => line2.replace(/[ \t]+/g, " ").trim()).filter((line2, i, arr) => line2 || i > 0 && i < arr.length - 1).join("\n");
2938
3049
  }
@@ -3009,10 +3120,7 @@ function getIgnoreDirective(node) {
3009
3120
  }
3010
3121
 
3011
3122
  // lsp/server/src/formatting/classifier.ts
3012
- var customCodeTags = /* @__PURE__ */ new Set();
3013
- function setCustomCodeTags(tags) {
3014
- customCodeTags = new Set(tags.map((t) => t.toLowerCase()));
3015
- }
3123
+ var EMPTY_SET = /* @__PURE__ */ new Set();
3016
3124
  var CSS_DISPLAY_MAP = {
3017
3125
  // Block elements
3018
3126
  address: "block",
@@ -3103,10 +3211,10 @@ var PRESERVE_CONTENT_ELEMENTS = /* @__PURE__ */ new Set([
3103
3211
  "script",
3104
3212
  "style"
3105
3213
  ]);
3106
- function getCSSDisplay(node) {
3214
+ function getCSSDisplay(node, customCodeTags = EMPTY_SET) {
3107
3215
  const type = node.type;
3108
3216
  if (type === "html_element") {
3109
- const tagName = getTagName2(node);
3217
+ const tagName = getTagName(node);
3110
3218
  if (tagName) {
3111
3219
  if (customCodeTags.has(tagName.toLowerCase())) {
3112
3220
  return "block";
@@ -3115,11 +3223,11 @@ function getCSSDisplay(node) {
3115
3223
  }
3116
3224
  return "block";
3117
3225
  }
3118
- if (type === "html_script_element" || type === "html_style_element" || type === "html_raw_element") {
3226
+ if (isRawContentElement(node)) {
3119
3227
  return "block";
3120
3228
  }
3121
- if (type === "mustache_section" || type === "mustache_inverted_section") {
3122
- return hasBlockContent(node) ? "block" : "inline";
3229
+ if (isMustacheSection(node)) {
3230
+ return hasBlockContent(node, customCodeTags) ? "block" : "inline";
3123
3231
  }
3124
3232
  return "inline";
3125
3233
  }
@@ -3142,55 +3250,55 @@ function isWhitespaceInsensitive(display) {
3142
3250
  return false;
3143
3251
  }
3144
3252
  }
3145
- function isBlockLevel(node) {
3253
+ function isBlockLevel(node, customCodeTags = EMPTY_SET) {
3146
3254
  const type = node.type;
3147
- if (type === "mustache_section" || type === "mustache_inverted_section") {
3148
- return hasBlockContent(node);
3255
+ if (isMustacheSection(node)) {
3256
+ return hasBlockContent(node, customCodeTags);
3149
3257
  }
3150
3258
  if (type === "html_element") {
3151
- const display = getCSSDisplay(node);
3259
+ const display = getCSSDisplay(node, customCodeTags);
3152
3260
  return isWhitespaceInsensitive(display);
3153
3261
  }
3154
- if (type === "html_script_element" || type === "html_style_element" || type === "html_raw_element") {
3262
+ if (isRawContentElement(node)) {
3155
3263
  return true;
3156
3264
  }
3157
3265
  return false;
3158
3266
  }
3159
- function shouldPreserveContent(node) {
3267
+ function shouldPreserveContent(node, customCodeTags = EMPTY_SET) {
3160
3268
  const type = node.type;
3161
- if (type === "html_script_element" || type === "html_style_element" || type === "html_raw_element") {
3269
+ if (isRawContentElement(node)) {
3162
3270
  return true;
3163
3271
  }
3164
3272
  if (type === "html_element") {
3165
- const tagName = getTagName2(node);
3273
+ const tagName = getTagName(node);
3166
3274
  if (!tagName) return false;
3167
3275
  const lower = tagName.toLowerCase();
3168
3276
  return PRESERVE_CONTENT_ELEMENTS.has(lower) || customCodeTags.has(lower);
3169
3277
  }
3170
3278
  return false;
3171
3279
  }
3172
- function hasBlockContent(sectionNode) {
3280
+ function hasBlockContent(sectionNode, customCodeTags = EMPTY_SET) {
3173
3281
  const contentNodes = getContentNodes(sectionNode);
3174
3282
  if (hasImplicitEndTags(contentNodes)) {
3175
3283
  return true;
3176
3284
  }
3177
3285
  for (const node of contentNodes) {
3178
- if (isBlockLevelContent(node)) {
3286
+ if (isBlockLevelContent(node, customCodeTags)) {
3179
3287
  return true;
3180
3288
  }
3181
3289
  }
3182
3290
  return false;
3183
3291
  }
3184
- function isBlockLevelContent(node) {
3292
+ function isBlockLevelContent(node, customCodeTags = EMPTY_SET) {
3185
3293
  const type = node.type;
3186
3294
  if (type === "html_element") {
3187
3295
  return true;
3188
3296
  }
3189
- if (type === "html_script_element" || type === "html_style_element" || type === "html_raw_element") {
3297
+ if (isRawContentElement(node)) {
3190
3298
  return true;
3191
3299
  }
3192
- if (type === "mustache_section" || type === "mustache_inverted_section") {
3193
- return hasBlockContent(node);
3300
+ if (isMustacheSection(node)) {
3301
+ return hasBlockContent(node, customCodeTags);
3194
3302
  }
3195
3303
  return false;
3196
3304
  }
@@ -3297,10 +3405,10 @@ function shouldHtmlElementStayInline(node, index, nodes) {
3297
3405
  }
3298
3406
  return false;
3299
3407
  }
3300
- function shouldTreatAsBlock(node, index, nodes) {
3301
- const isHtmlElement = node.type === "html_element" || node.type === "html_script_element" || node.type === "html_style_element" || node.type === "html_raw_element";
3302
- const isMustacheSection = node.type === "mustache_section" || node.type === "mustache_inverted_section";
3303
- return isHtmlElement && !shouldHtmlElementStayInline(node, index, nodes) || isMustacheSection && !isInTextFlow(node, index, nodes) || isBlockLevel(node) && !isInTextFlow(node, index, nodes);
3408
+ function shouldTreatAsBlock(node, index, nodes, customCodeTags = EMPTY_SET) {
3409
+ const isHtmlEl = isHtmlElementType(node);
3410
+ const isMustacheSec = isMustacheSection(node);
3411
+ return isHtmlEl && !shouldHtmlElementStayInline(node, index, nodes) || isMustacheSec && !isInTextFlow(node, index, nodes) || isBlockLevel(node, customCodeTags) && !isInTextFlow(node, index, nodes);
3304
3412
  }
3305
3413
 
3306
3414
  // lsp/server/src/customCodeTags.ts
@@ -3443,9 +3551,10 @@ function formatText(node) {
3443
3551
  return text(normalizeText(node.text));
3444
3552
  }
3445
3553
  function formatHtmlElement(node, context) {
3446
- const display = getCSSDisplay(node);
3554
+ const tags = context.customCodeTags;
3555
+ const display = getCSSDisplay(node, tags);
3447
3556
  const isBlock = isWhitespaceInsensitive(display);
3448
- const preserveContent = shouldPreserveContent(node);
3557
+ const preserveContent = shouldPreserveContent(node, tags);
3449
3558
  const selfClosing = node.childCount === 1 && node.child(0)?.type === "html_self_closing_tag";
3450
3559
  if (selfClosing) {
3451
3560
  const tag = node.child(0);
@@ -3474,7 +3583,7 @@ function formatHtmlElement(node, context) {
3474
3583
  parts.push(formatStartTag(startTag, context));
3475
3584
  }
3476
3585
  const hasHtmlElementChildren = contentNodes.some(
3477
- (child) => child.type === "html_element" || child.type === "html_script_element" || child.type === "html_style_element" || child.type === "html_raw_element" || isBlockLevel(child)
3586
+ (child) => child.type === "html_element" || isRawContentElement(child) || isBlockLevel(child, tags)
3478
3587
  );
3479
3588
  if (preserveContent) {
3480
3589
  const tagNameLower = startTag ? getTagNameFromStartTag(startTag) : null;
@@ -3538,11 +3647,11 @@ function formatHtmlElement(node, context) {
3538
3647
  const hasContent = hasDocContent(formattedContent);
3539
3648
  if (hasContent) {
3540
3649
  const hasBlockChildren = contentNodes.some((child, i) => {
3541
- if (!shouldTreatAsBlock(child, i, contentNodes)) {
3650
+ if (!shouldTreatAsBlock(child, i, contentNodes, tags)) {
3542
3651
  return false;
3543
3652
  }
3544
- const childDisplay = getCSSDisplay(child);
3545
- return isWhitespaceInsensitive(childDisplay) || child.type === "html_script_element" || child.type === "html_style_element" || child.type === "html_raw_element";
3653
+ const childDisplay = getCSSDisplay(child, tags);
3654
+ return isWhitespaceInsensitive(childDisplay) || isRawContentElement(child);
3546
3655
  });
3547
3656
  if (isBlock && !hasBlockChildren) {
3548
3657
  const doc = group(
@@ -3693,11 +3802,11 @@ function formatMustacheSection(node, context) {
3693
3802
  parts.push(hardline);
3694
3803
  } else {
3695
3804
  const hasBlockChildren = contentNodes.some((child, i) => {
3696
- if (!shouldTreatAsBlock(child, i, contentNodes)) {
3805
+ if (!shouldTreatAsBlock(child, i, contentNodes, context.customCodeTags)) {
3697
3806
  return false;
3698
3807
  }
3699
- const childDisplay = getCSSDisplay(child);
3700
- return isWhitespaceInsensitive(childDisplay) || child.type === "html_script_element" || child.type === "html_style_element" || child.type === "html_raw_element";
3808
+ const childDisplay = getCSSDisplay(child, context.customCodeTags);
3809
+ return isWhitespaceInsensitive(childDisplay) || isRawContentElement(child);
3701
3810
  });
3702
3811
  if (!hasBlockChildren) {
3703
3812
  parts.push(indent(concat([softline, formattedContent])));
@@ -3914,10 +4023,10 @@ function formatBlockChildren(nodes, context) {
3914
4023
  lastNodeEnd = node.endIndex;
3915
4024
  continue;
3916
4025
  }
3917
- const treatAsBlock = shouldTreatAsBlock(node, i, nodes);
4026
+ const treatAsBlock = shouldTreatAsBlock(node, i, nodes, context.customCodeTags);
3918
4027
  if (lastNodeEnd >= 0 && node.startIndex > lastNodeEnd) {
3919
4028
  const prevNode = nodes[i - 1];
3920
- const prevTreatAsBlock = shouldTreatAsBlock(prevNode, i - 1, nodes);
4029
+ const prevTreatAsBlock = shouldTreatAsBlock(prevNode, i - 1, nodes, context.customCodeTags);
3921
4030
  if (!prevTreatAsBlock && !treatAsBlock) {
3922
4031
  const gap = context.document.getText().slice(lastNodeEnd, node.startIndex);
3923
4032
  if (/\s/.test(gap)) {
@@ -4145,19 +4254,17 @@ function createIndentUnit(options) {
4145
4254
 
4146
4255
  // lsp/server/src/formatting/index.ts
4147
4256
  function formatDocument2(tree, document, options, params = {}) {
4148
- const { customCodeTags: customCodeTags2, printWidth = 80, embeddedFormatted, mustacheSpaces, customCodeTagConfigs, configFile } = params;
4257
+ const { customCodeTags, printWidth = 80, embeddedFormatted, mustacheSpaces, customCodeTagConfigs, configFile } = params;
4149
4258
  const mergedOptions = mergeOptions(options, document.uri, configFile);
4150
4259
  const indentUnit = createIndentUnit(mergedOptions);
4151
- if (customCodeTags2) {
4152
- setCustomCodeTags(customCodeTags2);
4153
- }
4154
4260
  if (tree.rootNode.hasError) {
4155
4261
  return [];
4156
4262
  }
4157
4263
  const configMap = buildConfigMap(customCodeTagConfigs);
4264
+ const customCodeTagSet = customCodeTags ? new Set(customCodeTags.map((t) => t.toLowerCase())) : void 0;
4158
4265
  const context = {
4159
4266
  document,
4160
- customCodeTags: customCodeTags2 ? new Set(customCodeTags2.map((t) => t.toLowerCase())) : void 0,
4267
+ customCodeTags: customCodeTagSet,
4161
4268
  customCodeTagConfigs: configMap,
4162
4269
  embeddedFormatted,
4163
4270
  mustacheSpaces
@@ -4256,7 +4363,7 @@ function resolveSettings(flags, filePath) {
4256
4363
  let insertSpaces = true;
4257
4364
  let printWidth = 80;
4258
4365
  let mustacheSpaces = false;
4259
- let customCodeTags2;
4366
+ let customCodeTags;
4260
4367
  let customCodeTagConfigs;
4261
4368
  const configFile = filePath ? loadConfigFileForPath(filePath) : null;
4262
4369
  if (configFile) {
@@ -4265,7 +4372,7 @@ function resolveSettings(flags, filePath) {
4265
4372
  if (configFile.mustacheSpaces !== void 0) mustacheSpaces = configFile.mustacheSpaces;
4266
4373
  if (configFile.customCodeTags && configFile.customCodeTags.length > 0) {
4267
4374
  const parsed = parseCustomCodeTagSettings(configFile.customCodeTags);
4268
- customCodeTags2 = parsed.tagNames;
4375
+ customCodeTags = parsed.tagNames;
4269
4376
  customCodeTagConfigs = parsed.configs;
4270
4377
  }
4271
4378
  }
@@ -4282,7 +4389,7 @@ function resolveSettings(flags, filePath) {
4282
4389
  options: { tabSize, insertSpaces },
4283
4390
  printWidth,
4284
4391
  mustacheSpaces,
4285
- customCodeTags: customCodeTags2,
4392
+ customCodeTags,
4286
4393
  customCodeTagConfigs,
4287
4394
  configFile
4288
4395
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reteps/tree-sitter-htmlmustache",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "description": "HTML with Mustache/Handlebars template syntax grammar for tree-sitter",
5
5
  "repository": {
6
6
  "type": "git",
package/src/scanner.c CHANGED
@@ -83,7 +83,7 @@ static unsigned serialize(Scanner *scanner, char *buffer) {
83
83
  }
84
84
 
85
85
  memcpy(&buffer[0], &serialized_tag_count, sizeof(serialized_tag_count));
86
- // printf("[S] serialized_tag_count: %d\n", serialized_tag_count);
86
+
87
87
  // Mustache tags
88
88
  uint16_t m_tag_count =
89
89
  scanner->mustache_tags.size > UINT16_MAX ? UINT16_MAX : scanner->mustache_tags.size;
@@ -93,7 +93,6 @@ static unsigned serialize(Scanner *scanner, char *buffer) {
93
93
  size += sizeof(m_serialized_tag_count);
94
94
  memcpy(&buffer[size], &m_tag_count, sizeof(m_tag_count));
95
95
  size += sizeof(m_tag_count);
96
- // printf("[S] m_tag_count: %d\n", m_tag_count);
97
96
 
98
97
  for (; m_serialized_tag_count < m_tag_count; m_serialized_tag_count++) {
99
98
  MustacheTag tag = scanner->mustache_tags.contents[m_serialized_tag_count];
@@ -113,12 +112,10 @@ static unsigned serialize(Scanner *scanner, char *buffer) {
113
112
  }
114
113
 
115
114
  memcpy(&buffer[mustache_start_offset], &m_serialized_tag_count, sizeof(m_serialized_tag_count));
116
- // printf("[S] m_serialized_tag_count: %d\n", m_serialized_tag_count);
117
115
  return size;
118
116
  }
119
117
 
120
118
  static void deserialize(Scanner *scanner, const char *buffer, unsigned length) {
121
- // printf("deserialize\n");
122
119
  for (unsigned i = 0; i < scanner->tags.size; i++) {
123
120
  tag_free(&scanner->tags.contents[i]);
124
121
  }
@@ -195,22 +192,12 @@ static void deserialize(Scanner *scanner, const char *buffer, unsigned length) {
195
192
  }
196
193
  }
197
194
 
198
- static void print_tag_name(String *tag_name) {
199
- // printf("tag_size: %d\n", tag->tag_name.size);
200
- for (uint32_t i = 0; i < tag_name->size; i++) {
201
- printf("%c", tag_name->contents[i]);
202
- }
203
- }
204
-
205
195
  static String scan_html_tag_name(TSLexer *lexer) {
206
196
  String tag_name = array_new();
207
197
  while (iswalnum(lexer->lookahead) || lexer->lookahead == '-' || lexer->lookahead == ':') {
208
198
  array_push(&tag_name, towupper(lexer->lookahead));
209
199
  advance(lexer);
210
200
  }
211
- // printf("tag_name: ");
212
- // print_tag_name(&tag_name);
213
- // printf("\n");
214
201
  return tag_name;
215
202
  }
216
203
 
@@ -431,8 +418,6 @@ static String scan_mustache_tag_name(Scanner *scanner, TSLexer *lexer) {
431
418
  array_push(&tag_name, lexer->lookahead);
432
419
  advance(lexer);
433
420
  }
434
- // print_tag_name(&tag_name);
435
- // printf("\n");
436
421
  return tag_name;
437
422
  }
438
423
 
@@ -445,17 +430,7 @@ static bool scan_mustache_start_tag_name(Scanner *scanner, TSLexer *lexer) {
445
430
  MustacheTag tag = mustache_tag_new();
446
431
  tag.tag_name = tag_name;
447
432
  tag.html_tag_stack_size = scanner->tags.size;
448
- // printf("pushing tag: ");
449
- // print_tag_name(&tag.tag_name);
450
- // printf("\n");
451
433
  array_push(&scanner->mustache_tags, tag);
452
- // printf("--------------------------------\n");
453
- // for (unsigned i = 0; i < scanner->mustache_tags.size; i++) {
454
- // printf("\tSTACK (START), tag_name: ");
455
- // print_tag_name(&scanner->mustache_tags.contents[i]);
456
- // printf("\n");
457
- // }
458
- // printf("--------------------------------\n");
459
434
  lexer->result_symbol = MUSTACHE_START_TAG_NAME;
460
435
  return true;
461
436
  }
@@ -469,23 +444,11 @@ static bool scan_mustache_end_tag_name(Scanner *scanner, TSLexer *lexer) {
469
444
  }
470
445
 
471
446
 
472
- // Print whole stack
473
- // printf("--------------------------------\n");
474
- // printf("num tags: %d\n", scanner->mustache_tags.size);
475
- // for (unsigned i = 0; i < scanner->mustache_tags.size; i++) {
476
- // printf("\tSTACK (END), tag_name: ");
477
- // print_tag_name(&scanner->mustache_tags.contents[i].tag_name);
478
- // printf("\n");
479
- // }
480
- // printf("--------------------------------\n");
481
447
  MustacheTag tag = mustache_tag_new();
482
448
  tag.tag_name = tag_name;
483
449
  if (scanner->mustache_tags.size > 0 && mustache_tag_eq(array_back(&scanner->mustache_tags), &tag)) {
484
450
  MustacheTag popped_tag = array_pop(&scanner->mustache_tags);
485
451
  mustache_tag_free(&popped_tag);
486
- // printf("popped tag (correct): ");
487
- // print_tag_name(&popped_tag.tag_name);
488
- // printf("\n");
489
452
  lexer->result_symbol = MUSTACHE_END_TAG_NAME;
490
453
  } else {
491
454
  if (scanner->mustache_tags.size > 0) {
@@ -501,7 +464,6 @@ static bool scan_mustache_end_tag_name(Scanner *scanner, TSLexer *lexer) {
501
464
 
502
465
  static bool scan_mustache_end_tag_html_implicit_end_tag(Scanner *scanner, TSLexer *lexer) {
503
466
  lexer->mark_end(lexer);
504
- // printf("next char: %c\n", lexer->lookahead);
505
467
  if (lexer->lookahead != '{') {
506
468
  return false;
507
469
  }
@@ -547,7 +509,6 @@ static bool scan(Scanner *scanner, TSLexer *lexer, const bool *valid_symbols) {
547
509
 
548
510
 
549
511
  if (valid_symbols[MUSTACHE_START_TAG_NAME]) {
550
- // printf("MUSTACHE_START_TAG_NAME\n");
551
512
  return scan_mustache_start_tag_name(scanner, lexer);
552
513
  }
553
514
 
Binary file