@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/cli/out/main.js CHANGED
@@ -525,11 +525,16 @@ var import_node_path = __toESM(require("node:path"));
525
525
  // cli/src/wasm.ts
526
526
  var path = __toESM(require("node:path"));
527
527
  var import_web_tree_sitter = require("web-tree-sitter");
528
+
529
+ // src/core/grammar.ts
530
+ var GRAMMAR_WASM_FILENAME = "tree-sitter-htmlmustache.wasm";
531
+
532
+ // cli/src/wasm.ts
528
533
  var parser;
529
534
  async function initializeParser() {
530
535
  await import_web_tree_sitter.Parser.init();
531
536
  parser = new import_web_tree_sitter.Parser();
532
- const wasmPath = path.resolve(__dirname, "..", "..", "tree-sitter-htmlmustache.wasm");
537
+ const wasmPath = path.resolve(__dirname, "..", "..", GRAMMAR_WASM_FILENAME);
533
538
  const language = await import_web_tree_sitter.Language.load(wasmPath);
534
539
  parser.setLanguage(language);
535
540
  }
@@ -545,7 +550,7 @@ function parseDocument(source) {
545
550
  var fs = __toESM(require("fs"), 1);
546
551
  var path2 = __toESM(require("path"), 1);
547
552
 
548
- // lsp/server/src/ruleMetadata.ts
553
+ // src/core/ruleMetadata.ts
549
554
  var RULES = [
550
555
  {
551
556
  name: "nestedDuplicateSections",
@@ -598,7 +603,7 @@ var RULE_DEFAULTS = Object.fromEntries(
598
603
  RULES.map((r2) => [r2.name, r2.defaultSeverity])
599
604
  );
600
605
 
601
- // lsp/server/src/configFile.ts
606
+ // src/core/configSchema.ts
602
607
  var VALID_CSS_DISPLAY_VALUES = /* @__PURE__ */ new Set([
603
608
  "block",
604
609
  "inline",
@@ -648,7 +653,6 @@ function parseRuleEntry(key, value) {
648
653
  if (!options) return { severity };
649
654
  return { severity, ...options };
650
655
  }
651
- var CONFIG_FILENAME = ".htmlmustache.jsonc";
652
656
  function parseJsonc(text2) {
653
657
  let result = "";
654
658
  let i2 = 0;
@@ -687,21 +691,6 @@ function parseJsonc(text2) {
687
691
  result = result.replace(/,\s*([}\]])/g, "$1");
688
692
  return JSON.parse(result);
689
693
  }
690
- function findConfigFile(startDir) {
691
- let dir = path2.resolve(startDir);
692
- const root = path2.parse(dir).root;
693
- while (true) {
694
- const candidate = path2.join(dir, CONFIG_FILENAME);
695
- try {
696
- fs.accessSync(candidate, fs.constants.R_OK);
697
- return candidate;
698
- } catch {
699
- }
700
- const parent = path2.dirname(dir);
701
- if (parent === dir || dir === root) return null;
702
- dir = parent;
703
- }
704
- }
705
694
  var VALID_INDENT_MODES = /* @__PURE__ */ new Set(["never", "always", "attribute"]);
706
695
  function parseCustomTagArray(arr) {
707
696
  if (!Array.isArray(arr)) return [];
@@ -801,6 +790,24 @@ function validateConfig(raw) {
801
790
  }
802
791
  return config;
803
792
  }
793
+
794
+ // lsp/server/src/configFile.ts
795
+ var CONFIG_FILENAME = ".htmlmustache.jsonc";
796
+ function findConfigFile(startDir) {
797
+ let dir = path2.resolve(startDir);
798
+ const root = path2.parse(dir).root;
799
+ while (true) {
800
+ const candidate = path2.join(dir, CONFIG_FILENAME);
801
+ try {
802
+ fs.accessSync(candidate, fs.constants.R_OK);
803
+ return candidate;
804
+ } catch {
805
+ }
806
+ const parent = path2.dirname(dir);
807
+ if (parent === dir || dir === root) return null;
808
+ dir = parent;
809
+ }
810
+ }
804
811
  function loadConfigFileForPath(filePath) {
805
812
  const dir = path2.dirname(path2.resolve(filePath));
806
813
  const configPath = findConfigFile(dir);
@@ -814,7 +821,7 @@ function loadConfigFileForPath(filePath) {
814
821
  }
815
822
  }
816
823
 
817
- // lsp/server/src/nodeHelpers.ts
824
+ // src/core/nodeHelpers.ts
818
825
  var MUSTACHE_SECTION_TYPES = /* @__PURE__ */ new Set([
819
826
  "mustache_section",
820
827
  "mustache_inverted_section"
@@ -878,7 +885,7 @@ function getPartialName(node) {
878
885
  return child ? child.text.trim() : null;
879
886
  }
880
887
 
881
- // lsp/server/src/htmlBalanceChecker.ts
888
+ // src/core/htmlBalanceChecker.ts
882
889
  function getTagNameLower(element) {
883
890
  return getTagName(element)?.toLowerCase() ?? null;
884
891
  }
@@ -1175,7 +1182,7 @@ function checkHtmlBalance(rootNode) {
1175
1182
  return allErrors;
1176
1183
  }
1177
1184
 
1178
- // lsp/server/src/mustacheChecks.ts
1185
+ // src/core/mustacheChecks.ts
1179
1186
  function checkNestedSameNameSections(rootNode) {
1180
1187
  const errors = [];
1181
1188
  function visit(node, ancestors) {
@@ -1834,7 +1841,7 @@ function m(e2, { recursive: t2 = true, list: s2 = true } = {}) {
1834
1841
  return c2;
1835
1842
  }
1836
1843
 
1837
- // lsp/server/src/selectorMatcher.ts
1844
+ // src/core/selectorMatcher.ts
1838
1845
  var MUSTACHE_KIND_PSEUDO = /* @__PURE__ */ new Set([
1839
1846
  "m-section",
1840
1847
  "m-inverted",
@@ -1963,6 +1970,7 @@ function segmentFromCompound(ast) {
1963
1970
  let kind;
1964
1971
  let name = null;
1965
1972
  let pathRegex;
1973
+ let rootOnly = false;
1966
1974
  const attributes = [];
1967
1975
  const descendantChecks = [];
1968
1976
  const forbidChange = (requested) => {
@@ -2021,6 +2029,11 @@ function segmentFromCompound(ast) {
2021
2029
  if (!applyNegatedSubtree(token.subtree, attributes, descendantChecks)) return null;
2022
2030
  break;
2023
2031
  }
2032
+ if (token.name === "root") {
2033
+ rootOnly = true;
2034
+ if (kind === void 0) kind = "html";
2035
+ break;
2036
+ }
2024
2037
  return null;
2025
2038
  }
2026
2039
  default:
@@ -2030,9 +2043,12 @@ function segmentFromCompound(ast) {
2030
2043
  if (kind === void 0) {
2031
2044
  kind = "html";
2032
2045
  }
2046
+ if (rootOnly) {
2047
+ if (name !== null || attributes.length > 0 || kind !== "html") return null;
2048
+ }
2033
2049
  const isHtml = kind === "html";
2034
2050
  const finalAttrs = isHtml ? attributes : [];
2035
- return { kind, name, pathRegex, attributes: finalAttrs, descendantChecks, combinator: "descendant" };
2051
+ return { kind, rootOnly, name, pathRegex, attributes: finalAttrs, descendantChecks, combinator: "descendant" };
2036
2052
  }
2037
2053
  function mustacheKindFromMarker(name) {
2038
2054
  switch (name) {
@@ -2227,7 +2243,11 @@ function matchesName(actual, segment) {
2227
2243
  if (segment.pathRegex) return segment.pathRegex.test(actual);
2228
2244
  return actual === segment.name;
2229
2245
  }
2230
- function nodeMatchesSegment(node, segment) {
2246
+ function nodeMatchesSegment(node, segment, rootNode) {
2247
+ if (segment.rootOnly) {
2248
+ if (node !== rootNode) return false;
2249
+ return checkDescendants(node, segment.descendantChecks);
2250
+ }
2231
2251
  switch (segment.kind) {
2232
2252
  case "html": {
2233
2253
  if (!HTML_ELEMENT_TYPES.has(node.type)) return false;
@@ -2271,7 +2291,10 @@ function checkAncestors(ancestors, segments, segIdx, childCombinator) {
2271
2291
  if (childCombinator === "child") {
2272
2292
  for (let a2 = ancestors.length - 1; a2 >= 0; a2--) {
2273
2293
  const entry = ancestors[a2];
2274
- if (entry.kind !== ancestorKind) continue;
2294
+ if (entry.kind !== ancestorKind) {
2295
+ if (ancestorKind === "root" && entry.kind === "html") return false;
2296
+ continue;
2297
+ }
2275
2298
  if (!matchesName(entry.name, segment)) return false;
2276
2299
  if (segment.kind === "html" && !checkAttributes(entry.node, segment.attributes)) return false;
2277
2300
  if (!checkDescendants(entry.node, segment.descendantChecks)) return false;
@@ -2292,12 +2315,13 @@ function checkAncestors(ancestors, segments, segIdx, childCombinator) {
2292
2315
  return false;
2293
2316
  }
2294
2317
  function ancestorKindForSegment(segment) {
2318
+ if (segment.rootOnly) return "root";
2295
2319
  if (segment.kind === "html") return "html";
2296
2320
  if (segment.kind === "section") return "section";
2297
2321
  if (segment.kind === "inverted") return "inverted";
2298
2322
  return null;
2299
2323
  }
2300
- function getReportNode(node) {
2324
+ function getReportNode(node, rootNode) {
2301
2325
  if (HTML_ELEMENT_TYPES.has(node.type)) {
2302
2326
  const startTag = node.children.find(
2303
2327
  (c2) => c2.type === "html_start_tag" || c2.type === "html_self_closing_tag"
@@ -2310,15 +2334,26 @@ function getReportNode(node) {
2310
2334
  );
2311
2335
  return begin ?? node;
2312
2336
  }
2337
+ if (rootNode && node === rootNode) {
2338
+ return {
2339
+ type: node.type,
2340
+ text: "",
2341
+ startPosition: node.startPosition,
2342
+ endPosition: { row: node.startPosition.row, column: node.startPosition.column + 1 },
2343
+ startIndex: node.startIndex,
2344
+ endIndex: Math.min(node.startIndex + 1, node.endIndex),
2345
+ children: []
2346
+ };
2347
+ }
2313
2348
  return node;
2314
2349
  }
2315
2350
  function matchAlternative(rootNode, segments) {
2316
2351
  const results = [];
2317
2352
  const lastSegment = segments[segments.length - 1];
2318
2353
  function walk(node, ancestors) {
2319
- if (nodeMatchesSegment(node, lastSegment)) {
2354
+ if (nodeMatchesSegment(node, lastSegment, rootNode)) {
2320
2355
  if (segments.length === 1 || checkAncestors(ancestors, segments, segments.length - 2, lastSegment.combinator)) {
2321
- results.push(getReportNode(node));
2356
+ results.push(getReportNode(node, rootNode));
2322
2357
  }
2323
2358
  }
2324
2359
  let newAncestors = ancestors;
@@ -2331,7 +2366,7 @@ function matchAlternative(rootNode, segments) {
2331
2366
  }
2332
2367
  for (const child of node.children) walk(child, newAncestors);
2333
2368
  }
2334
- walk(rootNode, []);
2369
+ walk(rootNode, [{ kind: "root", name: "", node: rootNode }]);
2335
2370
  return results;
2336
2371
  }
2337
2372
  function matchSelector(rootNode, selector) {
@@ -2348,7 +2383,15 @@ function matchSelector(rootNode, selector) {
2348
2383
  return allResults;
2349
2384
  }
2350
2385
 
2351
- // lsp/server/src/collectErrors.ts
2386
+ // src/core/collectErrors.ts
2387
+ var selectorCache = /* @__PURE__ */ new Map();
2388
+ function parseSelectorCached(raw) {
2389
+ const hit = selectorCache.get(raw);
2390
+ if (hit !== void 0) return hit;
2391
+ const parsed = parseSelector(raw);
2392
+ selectorCache.set(raw, parsed);
2393
+ return parsed;
2394
+ }
2352
2395
  var ERROR_NODE_TYPES = /* @__PURE__ */ new Set([
2353
2396
  "ERROR",
2354
2397
  "mustache_erroneous_section_end",
@@ -2479,7 +2522,7 @@ function collectErrors(tree, rules, customTagNames, customRules) {
2479
2522
  if (disabledRules.has(rule.id)) continue;
2480
2523
  const severity = rule.severity ?? "error";
2481
2524
  if (severity === "off") continue;
2482
- const parsed = parseSelector(rule.selector);
2525
+ const parsed = parseSelectorCached(rule.selector);
2483
2526
  if (!parsed) continue;
2484
2527
  const matches = matchSelector(tree.rootNode, parsed);
2485
2528
  for (const node of matches) {
@@ -2492,20 +2535,32 @@ function collectErrors(tree, rules, customTagNames, customRules) {
2492
2535
  );
2493
2536
  }
2494
2537
 
2538
+ // src/core/diagnostic.ts
2539
+ function toFix(r2) {
2540
+ return { range: [r2.startIndex, r2.endIndex], newText: r2.newText };
2541
+ }
2542
+ function toDiagnostic(err) {
2543
+ const { node } = err;
2544
+ return {
2545
+ line: node.startPosition.row + 1,
2546
+ column: node.startPosition.column + 1,
2547
+ endLine: node.endPosition.row + 1,
2548
+ endColumn: node.endPosition.column + 1,
2549
+ message: err.message,
2550
+ severity: err.severity ?? "error",
2551
+ ruleName: err.ruleName,
2552
+ fix: err.fix && err.fix.length > 0 ? err.fix.map(toFix) : void 0,
2553
+ fixDescription: err.fixDescription
2554
+ };
2555
+ }
2556
+
2495
2557
  // cli/src/check.ts
2496
2558
  function collectErrors2(tree, file, rules, customTagNames, customRules) {
2497
2559
  const errors = collectErrors(tree, rules, customTagNames, customRules);
2498
2560
  return errors.map((error) => ({
2499
2561
  file,
2500
- line: error.node.startPosition.row + 1,
2501
- column: error.node.startPosition.column + 1,
2502
- endLine: error.node.endPosition.row + 1,
2503
- endColumn: error.node.endPosition.column + 1,
2504
- message: error.message,
2505
2562
  nodeText: error.node.text,
2506
- severity: error.severity,
2507
- fix: error.fix,
2508
- fixDescription: error.fixDescription
2563
+ ...toDiagnostic(error)
2509
2564
  }));
2510
2565
  }
2511
2566
  function formatError(error, source) {
@@ -2617,8 +2672,9 @@ function resolveFiles(cliPatterns) {
2617
2672
  function applyFixes(source, errors) {
2618
2673
  const replacements = [];
2619
2674
  for (const error of errors) {
2620
- if (error.fix) {
2621
- replacements.push(...error.fix);
2675
+ if (!error.fix) continue;
2676
+ for (const edit of error.fix) {
2677
+ replacements.push({ startIndex: edit.range[0], endIndex: edit.range[1], newText: edit.newText });
2622
2678
  }
2623
2679
  }
2624
2680
  if (replacements.length === 0) return source;
@@ -2946,7 +3002,7 @@ function getWellformedEdit(textEdit) {
2946
3002
  return textEdit;
2947
3003
  }
2948
3004
 
2949
- // lsp/server/src/formatting/printer.ts
3005
+ // src/core/formatting/printer.ts
2950
3006
  function print(doc, options) {
2951
3007
  const output = [];
2952
3008
  const state = { indentLevel: 0, mode: "break", groupModes: /* @__PURE__ */ new Map() };
@@ -3096,7 +3152,7 @@ function makeIndent(level, options) {
3096
3152
  return options.indentUnit.repeat(level);
3097
3153
  }
3098
3154
 
3099
- // lsp/server/src/formatting/ir.ts
3155
+ // src/core/formatting/ir.ts
3100
3156
  var hardline = { type: "hardline" };
3101
3157
  var softline = { type: "softline" };
3102
3158
  var line = { type: "line" };
@@ -3148,7 +3204,7 @@ function isLine(doc) {
3148
3204
  return typeof doc === "object" && doc.type === "line";
3149
3205
  }
3150
3206
 
3151
- // lsp/server/src/formatting/utils.ts
3207
+ // src/core/formatting/utils.ts
3152
3208
  function normalizeText(text2) {
3153
3209
  return text2.split("\n").map((line2) => line2.replace(/[ \t]+/g, " ").trim()).filter((line2, i2, arr) => line2 || i2 > 0 && i2 < arr.length - 1).join("\n");
3154
3210
  }
@@ -3224,7 +3280,7 @@ function getIgnoreDirective(node) {
3224
3280
  return null;
3225
3281
  }
3226
3282
 
3227
- // lsp/server/src/customCodeTags.ts
3283
+ // src/core/customCodeTags.ts
3228
3284
  function isCodeTag(config) {
3229
3285
  return !!(config.languageAttribute || config.languageDefault);
3230
3286
  }
@@ -3253,7 +3309,7 @@ function getAttributeValue(node, attrName) {
3253
3309
  return null;
3254
3310
  }
3255
3311
 
3256
- // lsp/server/src/formatting/classifier.ts
3312
+ // src/core/formatting/classifier.ts
3257
3313
  var EMPTY_MAP = /* @__PURE__ */ new Map();
3258
3314
  var CSS_DISPLAY_MAP = {
3259
3315
  // Block elements
@@ -3555,7 +3611,7 @@ function shouldTreatAsBlock(node, index, nodes, customTags = EMPTY_MAP) {
3555
3611
  return isHtmlEl && !shouldHtmlElementStayInline(node, index, nodes, customTags) || isMustacheSec && !isInTextFlow(node, index, nodes) || isBlockLevel(node, customTags) && !isInTextFlow(node, index, nodes);
3556
3612
  }
3557
3613
 
3558
- // lsp/server/src/formatting/formatters.ts
3614
+ // src/core/formatting/formatters.ts
3559
3615
  function isAttributeTruthy(value) {
3560
3616
  if (value === null || value === "" || value === "false" || value === "0") {
3561
3617
  return false;
@@ -4447,46 +4503,12 @@ function trimDoc(doc) {
4447
4503
  return doc;
4448
4504
  }
4449
4505
 
4450
- // lsp/server/src/formatting/editorconfig.ts
4451
- var import_editorconfig = require("editorconfig");
4452
- var import_url = require("url");
4453
- function getEditorConfigOptions(uri) {
4454
- try {
4455
- if (!uri.startsWith("file://")) {
4456
- return {};
4457
- }
4458
- const filePath = (0, import_url.fileURLToPath)(uri);
4459
- const config = (0, import_editorconfig.parseSync)(filePath);
4460
- const result = {};
4461
- if (config.indent_style === "space") {
4462
- result.insertSpaces = true;
4463
- } else if (config.indent_style === "tab") {
4464
- result.insertSpaces = false;
4465
- }
4466
- if (typeof config.indent_size === "number") {
4467
- result.tabSize = config.indent_size;
4468
- } else if (config.indent_size === "tab" && typeof config.tab_width === "number") {
4469
- result.tabSize = config.tab_width;
4470
- }
4471
- return result;
4472
- } catch {
4473
- return {};
4474
- }
4475
- }
4476
- function mergeOptions(lspOptions, uri, configFile) {
4477
- let tabSize = lspOptions.tabSize;
4478
- let insertSpaces = lspOptions.insertSpaces;
4479
- if (configFile?.indentSize !== void 0) tabSize = configFile.indentSize;
4480
- const ec = getEditorConfigOptions(uri);
4481
- if (ec.tabSize !== void 0) tabSize = ec.tabSize;
4482
- if (ec.insertSpaces !== void 0) insertSpaces = ec.insertSpaces;
4483
- return { tabSize, insertSpaces };
4484
- }
4506
+ // src/core/formatting/mergeOptions.ts
4485
4507
  function createIndentUnit(options) {
4486
4508
  return options.insertSpaces ? " ".repeat(options.tabSize) : " ";
4487
4509
  }
4488
4510
 
4489
- // lsp/server/src/formatting/index.ts
4511
+ // src/core/formatting/index.ts
4490
4512
  function buildCustomTagMap(customTags) {
4491
4513
  if (!customTags || customTags.length === 0) return void 0;
4492
4514
  const map = /* @__PURE__ */ new Map();
@@ -4496,12 +4518,9 @@ function buildCustomTagMap(customTags) {
4496
4518
  return map;
4497
4519
  }
4498
4520
  function formatDocument2(tree, document, options, params = {}) {
4499
- const { printWidth = 80, embeddedFormatted, mustacheSpaces, noBreakDelimiters, configFile } = params;
4500
- const mergedOptions = mergeOptions(options, document.uri, configFile);
4501
- const indentUnit = createIndentUnit(mergedOptions);
4502
- if (tree.rootNode.hasError) {
4503
- return [];
4504
- }
4521
+ const { printWidth = 80, embeddedFormatted, mustacheSpaces, noBreakDelimiters } = params;
4522
+ const indentUnit = createIndentUnit(options);
4523
+ if (tree.rootNode.hasError) return [];
4505
4524
  const customTagMap = buildCustomTagMap(params.customTags);
4506
4525
  const context = {
4507
4526
  document,
@@ -4519,7 +4538,7 @@ function formatDocument2(tree, document, options, params = {}) {
4519
4538
  return [{ range: fullRange, newText: formatted }];
4520
4539
  }
4521
4540
 
4522
- // lsp/server/src/embeddedRegions.ts
4541
+ // src/core/embeddedRegions.ts
4523
4542
  function getEmbeddedLanguageId(node) {
4524
4543
  if (node.type === "html_style_element") {
4525
4544
  return "css";
@@ -4572,6 +4591,62 @@ function collectEmbeddedRegions(rootNode) {
4572
4591
  return regions;
4573
4592
  }
4574
4593
 
4594
+ // src/core/formatting/embedded.ts
4595
+ var LANGUAGE_TO_PRETTIER_PARSER = {
4596
+ javascript: "babel",
4597
+ typescript: "typescript",
4598
+ css: "css"
4599
+ };
4600
+ async function formatEmbeddedRegions(rootNode, options, prettier) {
4601
+ const result = /* @__PURE__ */ new Map();
4602
+ if (!prettier) return result;
4603
+ const regions = collectEmbeddedRegions(rootNode);
4604
+ if (regions.length === 0) return result;
4605
+ await Promise.all(
4606
+ regions.map(async (region) => {
4607
+ const parser2 = LANGUAGE_TO_PRETTIER_PARSER[region.languageId];
4608
+ if (!parser2) return;
4609
+ try {
4610
+ const formatted = await prettier.format(region.content, {
4611
+ parser: parser2,
4612
+ tabWidth: options.tabSize,
4613
+ useTabs: !options.insertSpaces
4614
+ });
4615
+ result.set(region.startIndex, formatted);
4616
+ } catch {
4617
+ }
4618
+ })
4619
+ );
4620
+ return result;
4621
+ }
4622
+
4623
+ // lsp/server/src/formatting/editorconfig.ts
4624
+ var import_editorconfig = require("editorconfig");
4625
+ var import_url = require("url");
4626
+ function getEditorConfigOptions(uri) {
4627
+ try {
4628
+ if (!uri.startsWith("file://")) {
4629
+ return {};
4630
+ }
4631
+ const filePath = (0, import_url.fileURLToPath)(uri);
4632
+ const config = (0, import_editorconfig.parseSync)(filePath);
4633
+ const result = {};
4634
+ if (config.indent_style === "space") {
4635
+ result.insertSpaces = true;
4636
+ } else if (config.indent_style === "tab") {
4637
+ result.insertSpaces = false;
4638
+ }
4639
+ if (typeof config.indent_size === "number") {
4640
+ result.tabSize = config.indent_size;
4641
+ } else if (config.indent_size === "tab" && typeof config.tab_width === "number") {
4642
+ result.tabSize = config.tab_width;
4643
+ }
4644
+ return result;
4645
+ } catch {
4646
+ return {};
4647
+ }
4648
+ }
4649
+
4575
4650
  // cli/src/format.ts
4576
4651
  var USAGE2 = `Usage: htmlmustache format [options] [patterns...]
4577
4652
 
@@ -4675,15 +4750,9 @@ function resolveSettings(flags, filePath) {
4675
4750
  printWidth,
4676
4751
  mustacheSpaces,
4677
4752
  noBreakDelimiters,
4678
- customTags,
4679
- configFile
4753
+ customTags
4680
4754
  };
4681
4755
  }
4682
- var LANGUAGE_TO_PRETTIER_PARSER = {
4683
- javascript: "babel",
4684
- typescript: "typescript",
4685
- css: "css"
4686
- };
4687
4756
  var prettierModule;
4688
4757
  async function getPrettier() {
4689
4758
  if (prettierModule !== void 0) return prettierModule;
@@ -4695,32 +4764,9 @@ async function getPrettier() {
4695
4764
  return null;
4696
4765
  }
4697
4766
  }
4698
- async function formatEmbeddedRegions(tree, options) {
4699
- const result = /* @__PURE__ */ new Map();
4700
- const prettier = await getPrettier();
4701
- if (!prettier) return result;
4702
- const regions = collectEmbeddedRegions(tree.rootNode);
4703
- if (regions.length === 0) return result;
4704
- await Promise.all(
4705
- regions.map(async (region) => {
4706
- const parser2 = LANGUAGE_TO_PRETTIER_PARSER[region.languageId];
4707
- if (!parser2) return;
4708
- try {
4709
- const formatted = await prettier.format(region.content, {
4710
- parser: parser2,
4711
- tabWidth: options.tabSize,
4712
- useTabs: !options.insertSpaces
4713
- });
4714
- result.set(region.startIndex, formatted);
4715
- } catch {
4716
- }
4717
- })
4718
- );
4719
- return result;
4720
- }
4721
4767
  async function formatSource(source, options, params = {}) {
4722
4768
  const tree = parseDocument(source);
4723
- const embeddedFormatted = await formatEmbeddedRegions(tree, options);
4769
+ const embeddedFormatted = await formatEmbeddedRegions(tree.rootNode, options, await getPrettier());
4724
4770
  const document = TextDocument.create("file:///stdin", "htmlmustache", 1, source);
4725
4771
  const edits = formatDocument2(tree, document, options, {
4726
4772
  ...params,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reteps/tree-sitter-htmlmustache",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "HTML with Mustache/Handlebars template syntax grammar for tree-sitter",
5
5
  "repository": {
6
6
  "type": "git",
@@ -15,6 +15,18 @@
15
15
  "htmlmustache": "cli/out/main.js"
16
16
  },
17
17
  "types": "bindings/node",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./bindings/node/index.d.ts",
21
+ "default": "./bindings/node/index.js"
22
+ },
23
+ "./browser": {
24
+ "types": "./browser/out/browser/index.d.ts",
25
+ "import": "./browser/out/browser/index.mjs"
26
+ },
27
+ "./tree-sitter-htmlmustache.wasm": "./tree-sitter-htmlmustache.wasm",
28
+ "./package.json": "./package.json"
29
+ },
18
30
  "keywords": [
19
31
  "incremental",
20
32
  "parsing",
@@ -32,7 +44,8 @@
32
44
  "queries/*",
33
45
  "src/**",
34
46
  "*.wasm",
35
- "cli/out/*"
47
+ "cli/out/*",
48
+ "browser/out/**"
36
49
  ],
37
50
  "dependencies": {
38
51
  "chalk": "^5.6.2",
@@ -43,6 +56,7 @@
43
56
  "peerDependencies": {
44
57
  "node-addon-api": "^8.2.2",
45
58
  "node-gyp-build": "^4.8.2",
59
+ "prettier": "^3.0.0",
46
60
  "tree-sitter": "^0.25.0"
47
61
  },
48
62
  "peerDependenciesMeta": {
@@ -52,6 +66,9 @@
52
66
  "node-gyp-build": {
53
67
  "optional": true
54
68
  },
69
+ "prettier": {
70
+ "optional": true
71
+ },
55
72
  "tree-sitter": {
56
73
  "optional": true
57
74
  }
@@ -81,8 +98,9 @@
81
98
  "scripts": {
82
99
  "install": "node-gyp-build || exit 0",
83
100
  "build": "tree-sitter build --wasm",
84
- "prepack": "tree-sitter build --wasm && node cli/esbuild.mjs",
101
+ "prepack": "tree-sitter build --wasm && node cli/esbuild.mjs && node browser/esbuild.mjs && tsc -p src/browser/tsconfig.json",
85
102
  "build:cli": "node cli/esbuild.mjs",
103
+ "build:browser": "node browser/esbuild.mjs && tsc -p src/browser/tsconfig.json",
86
104
  "check": "node cli/out/check.js check",
87
105
  "lint": "eslint .",
88
106
  "format": "prettier --write .",