@reteps/tree-sitter-htmlmustache 0.6.0 → 0.7.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.
- package/cli/out/main.js +335 -16
- package/package.json +1 -1
package/cli/out/main.js
CHANGED
|
@@ -748,6 +748,22 @@ function validateConfig(raw) {
|
|
|
748
748
|
}
|
|
749
749
|
if (hasRules) config.rules = rules;
|
|
750
750
|
}
|
|
751
|
+
if (Array.isArray(obj.customRules)) {
|
|
752
|
+
const rules = [];
|
|
753
|
+
for (const entry of obj.customRules) {
|
|
754
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
|
|
755
|
+
const e = entry;
|
|
756
|
+
if (typeof e.id !== "string" || e.id.length === 0) continue;
|
|
757
|
+
if (typeof e.selector !== "string" || e.selector.length === 0) continue;
|
|
758
|
+
if (typeof e.message !== "string" || e.message.length === 0) continue;
|
|
759
|
+
const rule = { id: e.id, selector: e.selector, message: e.message };
|
|
760
|
+
if (typeof e.severity === "string" && VALID_RULE_SEVERITIES.has(e.severity)) {
|
|
761
|
+
rule.severity = e.severity;
|
|
762
|
+
}
|
|
763
|
+
rules.push(rule);
|
|
764
|
+
}
|
|
765
|
+
if (rules.length > 0) config.customRules = rules;
|
|
766
|
+
}
|
|
751
767
|
return config;
|
|
752
768
|
}
|
|
753
769
|
function loadConfigFileForPath(filePath) {
|
|
@@ -921,18 +937,29 @@ function mergeAdjacentForks(items) {
|
|
|
921
937
|
}
|
|
922
938
|
return result;
|
|
923
939
|
}
|
|
924
|
-
function
|
|
940
|
+
function isBranchBalanced(items) {
|
|
941
|
+
const stack = [];
|
|
925
942
|
for (const item of items) {
|
|
926
|
-
if (item.type
|
|
927
|
-
|
|
943
|
+
if (item.type === "fork") {
|
|
944
|
+
if (!isBranchBalanced(item.truthy) || !isBranchBalanced(item.falsy)) {
|
|
945
|
+
return false;
|
|
946
|
+
}
|
|
947
|
+
} else if (item.type === "open") {
|
|
948
|
+
stack.push(item.tagName);
|
|
949
|
+
} else {
|
|
950
|
+
if (stack.length === 0 || stack[stack.length - 1] !== item.tagName) {
|
|
951
|
+
return false;
|
|
952
|
+
}
|
|
953
|
+
stack.pop();
|
|
954
|
+
}
|
|
928
955
|
}
|
|
929
|
-
return
|
|
956
|
+
return stack.length === 0;
|
|
930
957
|
}
|
|
931
958
|
function collectSectionNames(items) {
|
|
932
959
|
const names = /* @__PURE__ */ new Set();
|
|
933
960
|
for (const item of items) {
|
|
934
961
|
if (item.type === "fork") {
|
|
935
|
-
if (
|
|
962
|
+
if (!isBranchBalanced(item.truthy) || !isBranchBalanced(item.falsy)) {
|
|
936
963
|
names.add(item.sectionName);
|
|
937
964
|
}
|
|
938
965
|
for (const name of collectSectionNames(item.truthy)) names.add(name);
|
|
@@ -1573,6 +1600,281 @@ function checkDuplicateAttributes(rootNode) {
|
|
|
1573
1600
|
return errors;
|
|
1574
1601
|
}
|
|
1575
1602
|
|
|
1603
|
+
// lsp/server/src/selectorMatcher.ts
|
|
1604
|
+
function isNameChar(ch) {
|
|
1605
|
+
return /[a-zA-Z0-9\-_]/.test(ch);
|
|
1606
|
+
}
|
|
1607
|
+
function parseAttributes(raw, pos) {
|
|
1608
|
+
const attrs = [];
|
|
1609
|
+
while (pos.i < raw.length) {
|
|
1610
|
+
if (raw[pos.i] === ":") {
|
|
1611
|
+
if (raw.slice(pos.i, pos.i + 6).toLowerCase() !== ":not([") return attrs;
|
|
1612
|
+
pos.i += 6;
|
|
1613
|
+
const attr = parseOneAttribute(raw, pos, true);
|
|
1614
|
+
if (!attr) return attrs;
|
|
1615
|
+
if (raw[pos.i] !== "]" || raw[pos.i + 1] !== ")") return attrs;
|
|
1616
|
+
pos.i += 2;
|
|
1617
|
+
attrs.push(attr);
|
|
1618
|
+
} else if (raw[pos.i] === "[") {
|
|
1619
|
+
pos.i++;
|
|
1620
|
+
const attr = parseOneAttribute(raw, pos, false);
|
|
1621
|
+
if (!attr) return attrs;
|
|
1622
|
+
if (raw[pos.i] !== "]") return attrs;
|
|
1623
|
+
pos.i++;
|
|
1624
|
+
attrs.push(attr);
|
|
1625
|
+
} else {
|
|
1626
|
+
break;
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
return attrs;
|
|
1630
|
+
}
|
|
1631
|
+
function parseOneAttribute(raw, pos, negated) {
|
|
1632
|
+
let name = "";
|
|
1633
|
+
while (pos.i < raw.length && isNameChar(raw[pos.i])) {
|
|
1634
|
+
name += raw[pos.i];
|
|
1635
|
+
pos.i++;
|
|
1636
|
+
}
|
|
1637
|
+
if (name.length === 0) return null;
|
|
1638
|
+
let value;
|
|
1639
|
+
if (raw[pos.i] === "=") {
|
|
1640
|
+
pos.i++;
|
|
1641
|
+
value = "";
|
|
1642
|
+
if (raw[pos.i] === '"' || raw[pos.i] === "'") {
|
|
1643
|
+
const quote = raw[pos.i];
|
|
1644
|
+
pos.i++;
|
|
1645
|
+
while (pos.i < raw.length && raw[pos.i] !== quote) {
|
|
1646
|
+
value += raw[pos.i];
|
|
1647
|
+
pos.i++;
|
|
1648
|
+
}
|
|
1649
|
+
if (pos.i < raw.length) pos.i++;
|
|
1650
|
+
} else {
|
|
1651
|
+
while (pos.i < raw.length && raw[pos.i] !== "]") {
|
|
1652
|
+
value += raw[pos.i];
|
|
1653
|
+
pos.i++;
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
return { name: name.toLowerCase(), value, negated };
|
|
1658
|
+
}
|
|
1659
|
+
function parseSelector(raw) {
|
|
1660
|
+
const trimmed = raw.trim();
|
|
1661
|
+
if (trimmed.length === 0) return null;
|
|
1662
|
+
const parts = trimmed.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
1663
|
+
if (parts.length === 0) return null;
|
|
1664
|
+
const alternatives = [];
|
|
1665
|
+
for (const part of parts) {
|
|
1666
|
+
const alt = parseSingleSelector(part);
|
|
1667
|
+
if (!alt) return null;
|
|
1668
|
+
alternatives.push(alt);
|
|
1669
|
+
}
|
|
1670
|
+
return { alternatives };
|
|
1671
|
+
}
|
|
1672
|
+
function parseSingleSelector(raw) {
|
|
1673
|
+
const segments = [];
|
|
1674
|
+
let i = 0;
|
|
1675
|
+
let nextCombinator = "descendant";
|
|
1676
|
+
while (i < raw.length) {
|
|
1677
|
+
while (i < raw.length && raw[i] === " ") i++;
|
|
1678
|
+
if (i >= raw.length) break;
|
|
1679
|
+
if (raw[i] === ">") {
|
|
1680
|
+
if (segments.length === 0) return null;
|
|
1681
|
+
nextCombinator = "child";
|
|
1682
|
+
i++;
|
|
1683
|
+
while (i < raw.length && raw[i] === " ") i++;
|
|
1684
|
+
if (i >= raw.length) return null;
|
|
1685
|
+
continue;
|
|
1686
|
+
}
|
|
1687
|
+
const pos = { i };
|
|
1688
|
+
const segment = parseOneSegment(raw, pos);
|
|
1689
|
+
if (!segment) return null;
|
|
1690
|
+
i = pos.i;
|
|
1691
|
+
segment.combinator = nextCombinator;
|
|
1692
|
+
nextCombinator = "descendant";
|
|
1693
|
+
segments.push(segment);
|
|
1694
|
+
}
|
|
1695
|
+
if (segments.length === 0) return null;
|
|
1696
|
+
return { segments };
|
|
1697
|
+
}
|
|
1698
|
+
function parseOneSegment(raw, pos) {
|
|
1699
|
+
let kind;
|
|
1700
|
+
let name;
|
|
1701
|
+
if (raw[pos.i] === "#") {
|
|
1702
|
+
kind = "mustache";
|
|
1703
|
+
pos.i++;
|
|
1704
|
+
name = "";
|
|
1705
|
+
while (pos.i < raw.length && isNameChar(raw[pos.i])) {
|
|
1706
|
+
name += raw[pos.i];
|
|
1707
|
+
pos.i++;
|
|
1708
|
+
}
|
|
1709
|
+
if (name.length === 0) name = null;
|
|
1710
|
+
else name = name.toLowerCase();
|
|
1711
|
+
return { kind, name, attributes: [], combinator: "descendant" };
|
|
1712
|
+
}
|
|
1713
|
+
if (raw[pos.i] === "*") {
|
|
1714
|
+
kind = "html";
|
|
1715
|
+
name = null;
|
|
1716
|
+
pos.i++;
|
|
1717
|
+
const attrs2 = parseAttributes(raw, pos);
|
|
1718
|
+
return { kind, name, attributes: attrs2, combinator: "descendant" };
|
|
1719
|
+
}
|
|
1720
|
+
if (raw[pos.i] === "[" || raw[pos.i] === ":") {
|
|
1721
|
+
kind = "html";
|
|
1722
|
+
name = null;
|
|
1723
|
+
const attrs2 = parseAttributes(raw, pos);
|
|
1724
|
+
if (attrs2.length === 0) return null;
|
|
1725
|
+
return { kind, name, attributes: attrs2, combinator: "descendant" };
|
|
1726
|
+
}
|
|
1727
|
+
if (!isNameChar(raw[pos.i])) return null;
|
|
1728
|
+
kind = "html";
|
|
1729
|
+
name = "";
|
|
1730
|
+
while (pos.i < raw.length && isNameChar(raw[pos.i])) {
|
|
1731
|
+
name += raw[pos.i];
|
|
1732
|
+
pos.i++;
|
|
1733
|
+
}
|
|
1734
|
+
name = name.toLowerCase();
|
|
1735
|
+
const attrs = parseAttributes(raw, pos);
|
|
1736
|
+
return { kind, name, attributes: attrs, combinator: "descendant" };
|
|
1737
|
+
}
|
|
1738
|
+
function getNodeAttributes(node) {
|
|
1739
|
+
const startTag = node.children.find(
|
|
1740
|
+
(c) => c.type === "html_start_tag" || c.type === "html_self_closing_tag"
|
|
1741
|
+
);
|
|
1742
|
+
if (!startTag) return [];
|
|
1743
|
+
const attrs = [];
|
|
1744
|
+
for (const child of startTag.children) {
|
|
1745
|
+
if (child.type === "html_attribute") {
|
|
1746
|
+
let attrName = "";
|
|
1747
|
+
let attrValue;
|
|
1748
|
+
for (const part of child.children) {
|
|
1749
|
+
if (part.type === "html_attribute_name") {
|
|
1750
|
+
attrName = part.text.toLowerCase();
|
|
1751
|
+
} else if (part.type === "html_quoted_attribute_value") {
|
|
1752
|
+
attrValue = part.text.replace(/^["']|["']$/g, "");
|
|
1753
|
+
} else if (part.type === "html_attribute_value") {
|
|
1754
|
+
attrValue = part.text;
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
if (attrName) attrs.push({ name: attrName, value: attrValue });
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
return attrs;
|
|
1761
|
+
}
|
|
1762
|
+
function checkAttributes(node, constraints) {
|
|
1763
|
+
if (constraints.length === 0) return true;
|
|
1764
|
+
const nodeAttrs = getNodeAttributes(node);
|
|
1765
|
+
for (const constraint of constraints) {
|
|
1766
|
+
const found = nodeAttrs.find((a) => a.name === constraint.name);
|
|
1767
|
+
if (constraint.negated) {
|
|
1768
|
+
if (found) return false;
|
|
1769
|
+
} else if (constraint.value !== void 0) {
|
|
1770
|
+
if (!found || found.value !== constraint.value) return false;
|
|
1771
|
+
} else {
|
|
1772
|
+
if (!found) return false;
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
return true;
|
|
1776
|
+
}
|
|
1777
|
+
function nodeMatchesSegment(node, segment) {
|
|
1778
|
+
if (segment.kind === "html") {
|
|
1779
|
+
if (!HTML_ELEMENT_TYPES.has(node.type)) return false;
|
|
1780
|
+
if (segment.name !== null) {
|
|
1781
|
+
const tagName = getTagName(node)?.toLowerCase();
|
|
1782
|
+
if (tagName !== segment.name) return false;
|
|
1783
|
+
}
|
|
1784
|
+
return checkAttributes(node, segment.attributes);
|
|
1785
|
+
}
|
|
1786
|
+
if (!MUSTACHE_SECTION_TYPES.has(node.type)) return false;
|
|
1787
|
+
if (segment.name !== null) {
|
|
1788
|
+
const sectionName = getSectionName(node)?.toLowerCase();
|
|
1789
|
+
if (sectionName !== segment.name) return false;
|
|
1790
|
+
}
|
|
1791
|
+
return true;
|
|
1792
|
+
}
|
|
1793
|
+
function checkAncestors(ancestors, segments, segIdx, childCombinator) {
|
|
1794
|
+
if (segIdx < 0) return true;
|
|
1795
|
+
const segment = segments[segIdx];
|
|
1796
|
+
if (childCombinator === "child") {
|
|
1797
|
+
for (let a = ancestors.length - 1; a >= 0; a--) {
|
|
1798
|
+
const entry = ancestors[a];
|
|
1799
|
+
if (entry.kind !== segment.kind) continue;
|
|
1800
|
+
if (segment.name !== null && entry.name !== segment.name) return false;
|
|
1801
|
+
if (segment.kind === "html" && segment.attributes.length > 0) {
|
|
1802
|
+
if (!checkAttributes(entry.node, segment.attributes)) return false;
|
|
1803
|
+
}
|
|
1804
|
+
return checkAncestors(ancestors.slice(0, a), segments, segIdx - 1, segment.combinator);
|
|
1805
|
+
}
|
|
1806
|
+
return false;
|
|
1807
|
+
}
|
|
1808
|
+
for (let a = ancestors.length - 1; a >= 0; a--) {
|
|
1809
|
+
const entry = ancestors[a];
|
|
1810
|
+
if (entry.kind !== segment.kind) continue;
|
|
1811
|
+
if (segment.name !== null && entry.name !== segment.name) continue;
|
|
1812
|
+
if (segment.kind === "html" && segment.attributes.length > 0) {
|
|
1813
|
+
if (!checkAttributes(entry.node, segment.attributes)) continue;
|
|
1814
|
+
}
|
|
1815
|
+
if (checkAncestors(ancestors.slice(0, a), segments, segIdx - 1, segment.combinator)) {
|
|
1816
|
+
return true;
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
return false;
|
|
1820
|
+
}
|
|
1821
|
+
function getReportNode(node) {
|
|
1822
|
+
if (HTML_ELEMENT_TYPES.has(node.type)) {
|
|
1823
|
+
const startTag = node.children.find(
|
|
1824
|
+
(c) => c.type === "html_start_tag" || c.type === "html_self_closing_tag"
|
|
1825
|
+
);
|
|
1826
|
+
return startTag ?? node;
|
|
1827
|
+
}
|
|
1828
|
+
if (MUSTACHE_SECTION_TYPES.has(node.type)) {
|
|
1829
|
+
const begin = node.children.find(
|
|
1830
|
+
(c) => c.type === "mustache_section_begin" || c.type === "mustache_inverted_section_begin"
|
|
1831
|
+
);
|
|
1832
|
+
return begin ?? node;
|
|
1833
|
+
}
|
|
1834
|
+
return node;
|
|
1835
|
+
}
|
|
1836
|
+
function matchAlternative(rootNode, alt) {
|
|
1837
|
+
const results = [];
|
|
1838
|
+
const lastSegment = alt.segments[alt.segments.length - 1];
|
|
1839
|
+
function walk(node, ancestors) {
|
|
1840
|
+
if (nodeMatchesSegment(node, lastSegment)) {
|
|
1841
|
+
if (alt.segments.length === 1 || checkAncestors(ancestors, alt.segments, alt.segments.length - 2, lastSegment.combinator)) {
|
|
1842
|
+
results.push(getReportNode(node));
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
let newAncestors = ancestors;
|
|
1846
|
+
if (HTML_ELEMENT_TYPES.has(node.type)) {
|
|
1847
|
+
const tagName = getTagName(node)?.toLowerCase();
|
|
1848
|
+
if (tagName) {
|
|
1849
|
+
newAncestors = [...ancestors, { kind: "html", name: tagName, node }];
|
|
1850
|
+
}
|
|
1851
|
+
} else if (MUSTACHE_SECTION_TYPES.has(node.type)) {
|
|
1852
|
+
const sectionName = getSectionName(node)?.toLowerCase();
|
|
1853
|
+
if (sectionName) {
|
|
1854
|
+
newAncestors = [...ancestors, { kind: "mustache", name: sectionName, node }];
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
for (const child of node.children) {
|
|
1858
|
+
walk(child, newAncestors);
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
walk(rootNode, []);
|
|
1862
|
+
return results;
|
|
1863
|
+
}
|
|
1864
|
+
function matchSelector(rootNode, selector) {
|
|
1865
|
+
const allResults = [];
|
|
1866
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1867
|
+
for (const alt of selector.alternatives) {
|
|
1868
|
+
for (const node of matchAlternative(rootNode, alt)) {
|
|
1869
|
+
if (!seen.has(node)) {
|
|
1870
|
+
seen.add(node);
|
|
1871
|
+
allResults.push(node);
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
return allResults;
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1576
1878
|
// lsp/server/src/collectErrors.ts
|
|
1577
1879
|
var ERROR_NODE_TYPES = /* @__PURE__ */ new Set([
|
|
1578
1880
|
"ERROR",
|
|
@@ -1592,7 +1894,7 @@ function errorMessageForNode(nodeType, node) {
|
|
|
1592
1894
|
function resolveRuleSeverity(rules, ruleName) {
|
|
1593
1895
|
return rules?.[ruleName] ?? RULE_DEFAULTS[ruleName] ?? "off";
|
|
1594
1896
|
}
|
|
1595
|
-
function parseDisableDirective(node) {
|
|
1897
|
+
function parseDisableDirective(node, customRuleIds) {
|
|
1596
1898
|
if (node.type !== "html_comment" && node.type !== "mustache_comment") return null;
|
|
1597
1899
|
let inner = null;
|
|
1598
1900
|
if (node.type === "html_comment") {
|
|
@@ -1606,12 +1908,14 @@ function parseDisableDirective(node) {
|
|
|
1606
1908
|
const prefix = "htmlmustache-disable ";
|
|
1607
1909
|
if (!inner.startsWith(prefix)) return null;
|
|
1608
1910
|
const ruleName = inner.slice(prefix.length).trim();
|
|
1609
|
-
|
|
1911
|
+
if (KNOWN_RULE_NAMES.has(ruleName)) return ruleName;
|
|
1912
|
+
if (customRuleIds?.has(ruleName)) return ruleName;
|
|
1913
|
+
return null;
|
|
1610
1914
|
}
|
|
1611
|
-
function collectDisabledRules(rootNode) {
|
|
1915
|
+
function collectDisabledRules(rootNode, customRuleIds) {
|
|
1612
1916
|
const disabled = /* @__PURE__ */ new Set();
|
|
1613
1917
|
function walk(node) {
|
|
1614
|
-
const rule = parseDisableDirective(node);
|
|
1918
|
+
const rule = parseDisableDirective(node, customRuleIds);
|
|
1615
1919
|
if (rule) {
|
|
1616
1920
|
disabled.add(rule);
|
|
1617
1921
|
return;
|
|
@@ -1621,7 +1925,7 @@ function collectDisabledRules(rootNode) {
|
|
|
1621
1925
|
walk(rootNode);
|
|
1622
1926
|
return disabled;
|
|
1623
1927
|
}
|
|
1624
|
-
function collectErrors(tree, rules, customTagNames) {
|
|
1928
|
+
function collectErrors(tree, rules, customTagNames, customRules) {
|
|
1625
1929
|
const errors = [];
|
|
1626
1930
|
const cursor = tree.walk();
|
|
1627
1931
|
function visit() {
|
|
@@ -1650,7 +1954,8 @@ function collectErrors(tree, rules, customTagNames) {
|
|
|
1650
1954
|
for (const error of unclosedErrors) {
|
|
1651
1955
|
errors.push({ node: error.node, message: error.message });
|
|
1652
1956
|
}
|
|
1653
|
-
const
|
|
1957
|
+
const customRuleIds = customRules ? new Set(customRules.map((r) => r.id)) : void 0;
|
|
1958
|
+
const disabledRules = collectDisabledRules(tree.rootNode, customRuleIds);
|
|
1654
1959
|
const effectiveRules = { ...rules };
|
|
1655
1960
|
for (const rule of disabledRules) {
|
|
1656
1961
|
effectiveRules[rule] = "off";
|
|
@@ -1679,14 +1984,27 @@ function collectErrors(tree, rules, customTagNames) {
|
|
|
1679
1984
|
});
|
|
1680
1985
|
}
|
|
1681
1986
|
}
|
|
1987
|
+
if (customRules) {
|
|
1988
|
+
for (const rule of customRules) {
|
|
1989
|
+
if (disabledRules.has(rule.id)) continue;
|
|
1990
|
+
const severity = rule.severity ?? "error";
|
|
1991
|
+
if (severity === "off") continue;
|
|
1992
|
+
const parsed = parseSelector(rule.selector);
|
|
1993
|
+
if (!parsed) continue;
|
|
1994
|
+
const matches = matchSelector(tree.rootNode, parsed);
|
|
1995
|
+
for (const node of matches) {
|
|
1996
|
+
errors.push({ node, message: rule.message, severity });
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
1682
2000
|
return errors.filter(
|
|
1683
|
-
(e) => !(e.message.includes("HTML comment found") && parseDisableDirective(e.node) !== null)
|
|
2001
|
+
(e) => !(e.message.includes("HTML comment found") && parseDisableDirective(e.node, customRuleIds) !== null)
|
|
1684
2002
|
);
|
|
1685
2003
|
}
|
|
1686
2004
|
|
|
1687
2005
|
// cli/src/check.ts
|
|
1688
|
-
function collectErrors2(tree, file, rules, customTagNames) {
|
|
1689
|
-
const errors = collectErrors(tree, rules, customTagNames);
|
|
2006
|
+
function collectErrors2(tree, file, rules, customTagNames, customRules) {
|
|
2007
|
+
const errors = collectErrors(tree, rules, customTagNames, customRules);
|
|
1690
2008
|
return errors.map((error) => ({
|
|
1691
2009
|
file,
|
|
1692
2010
|
line: error.node.startPosition.row + 1,
|
|
@@ -1871,12 +2189,13 @@ async function run(args) {
|
|
|
1871
2189
|
const errorOutput = [];
|
|
1872
2190
|
const rules = config?.rules;
|
|
1873
2191
|
const customTagNames = config?.customTags?.map((t) => t.name);
|
|
2192
|
+
const customRules = config?.customRules;
|
|
1874
2193
|
for (const file of files) {
|
|
1875
2194
|
const displayPath = import_node_path.default.relative(cwd, file) || file;
|
|
1876
2195
|
let source = import_node_fs.default.readFileSync(file, "utf-8");
|
|
1877
2196
|
if (fixMode) {
|
|
1878
2197
|
const tree2 = parseDocument(source);
|
|
1879
|
-
const errors2 = collectErrors2(tree2, displayPath, rules, customTagNames);
|
|
2198
|
+
const errors2 = collectErrors2(tree2, displayPath, rules, customTagNames, customRules);
|
|
1880
2199
|
const fixed = applyFixes(source, errors2);
|
|
1881
2200
|
if (fixed !== source) {
|
|
1882
2201
|
import_node_fs.default.writeFileSync(file, fixed, "utf-8");
|
|
@@ -1884,7 +2203,7 @@ async function run(args) {
|
|
|
1884
2203
|
}
|
|
1885
2204
|
}
|
|
1886
2205
|
const tree = parseDocument(source);
|
|
1887
|
-
const errors = collectErrors2(tree, displayPath, rules, customTagNames);
|
|
2206
|
+
const errors = collectErrors2(tree, displayPath, rules, customTagNames, customRules);
|
|
1888
2207
|
const fileErrors = errors.filter((e) => e.severity !== "warning");
|
|
1889
2208
|
const fileWarnings = errors.filter((e) => e.severity === "warning");
|
|
1890
2209
|
if (errors.length > 0) {
|