@reteps/tree-sitter-htmlmustache 0.2.0 → 0.2.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.
Files changed (2) hide show
  1. package/cli/out/main.js +91 -1
  2. package/package.json +1 -1
package/cli/out/main.js CHANGED
@@ -2113,6 +2113,95 @@ function checkConsecutiveSameNameSections(rootNode, sourceText) {
2113
2113
  visit(rootNode);
2114
2114
  return errors;
2115
2115
  }
2116
+ function areMutuallyExclusive(a, b) {
2117
+ for (const ac of a) {
2118
+ for (const bc of b) {
2119
+ if (ac.name === bc.name && ac.inverted !== bc.inverted) {
2120
+ return true;
2121
+ }
2122
+ }
2123
+ }
2124
+ return false;
2125
+ }
2126
+ function formatConditionClause(a, b) {
2127
+ const seen = /* @__PURE__ */ new Map();
2128
+ for (const c of [...a, ...b]) {
2129
+ if (!seen.has(c.name)) {
2130
+ seen.set(c.name, c.inverted);
2131
+ }
2132
+ }
2133
+ if (seen.size === 0) return "";
2134
+ const parts = [];
2135
+ for (const [name, inverted] of seen) {
2136
+ parts.push(`${name} is ${inverted ? "falsy" : "truthy"}`);
2137
+ }
2138
+ return ` (when ${parts.join(", ")})`;
2139
+ }
2140
+ function collectAttributes(node, conditions, out) {
2141
+ for (const child of node.children) {
2142
+ if (child.type === "html_attribute") {
2143
+ const nameNode = child.children.find((c) => c.type === "html_attribute_name");
2144
+ if (nameNode) {
2145
+ out.push({ nameNode, conditions: [...conditions] });
2146
+ }
2147
+ } else if (child.type === "mustache_attribute") {
2148
+ const section = child.children.find(
2149
+ (c) => c.type === "mustache_section" || c.type === "mustache_inverted_section"
2150
+ );
2151
+ if (section) {
2152
+ const name = getSectionName(section);
2153
+ if (name) {
2154
+ const inverted = section.type === "mustache_inverted_section";
2155
+ collectAttributes(section, [...conditions, { name, inverted }], out);
2156
+ }
2157
+ }
2158
+ }
2159
+ }
2160
+ }
2161
+ function checkDuplicateAttributes(rootNode) {
2162
+ const errors = [];
2163
+ function visit(node) {
2164
+ if (node.type === "html_start_tag" || node.type === "html_self_closing_tag") {
2165
+ const occurrences = [];
2166
+ collectAttributes(node, [], occurrences);
2167
+ const groups = /* @__PURE__ */ new Map();
2168
+ for (const occ of occurrences) {
2169
+ const key = occ.nameNode.text.toLowerCase();
2170
+ let group2 = groups.get(key);
2171
+ if (!group2) {
2172
+ group2 = [];
2173
+ groups.set(key, group2);
2174
+ }
2175
+ group2.push(occ);
2176
+ }
2177
+ for (const [, group2] of groups) {
2178
+ if (group2.length < 2) continue;
2179
+ for (let i = 1; i < group2.length; i++) {
2180
+ let conflictIdx = -1;
2181
+ for (let j = 0; j < i; j++) {
2182
+ if (!areMutuallyExclusive(group2[i].conditions, group2[j].conditions)) {
2183
+ conflictIdx = j;
2184
+ break;
2185
+ }
2186
+ }
2187
+ if (conflictIdx >= 0) {
2188
+ const clause = formatConditionClause(group2[conflictIdx].conditions, group2[i].conditions);
2189
+ errors.push({
2190
+ node: group2[i].nameNode,
2191
+ message: `Duplicate attribute "${group2[i].nameNode.text}"${clause}`
2192
+ });
2193
+ }
2194
+ }
2195
+ }
2196
+ return;
2197
+ }
2198
+ for (const child of node.children) {
2199
+ visit(child);
2200
+ }
2201
+ }
2202
+ visit(rootNode);
2203
+ return errors;
2204
+ }
2116
2205
 
2117
2206
  // cli/src/check.ts
2118
2207
  function errorMessageForNode(nodeType, node) {
@@ -2185,7 +2274,8 @@ function collectErrors(tree, file) {
2185
2274
  const mustacheChecks = [
2186
2275
  ...checkNestedSameNameSections(rootNode),
2187
2276
  ...checkUnquotedMustacheAttributes(rootNode),
2188
- ...checkConsecutiveSameNameSections(rootNode, sourceText)
2277
+ ...checkConsecutiveSameNameSections(rootNode, sourceText),
2278
+ ...checkDuplicateAttributes(rootNode)
2189
2279
  ];
2190
2280
  for (const error of mustacheChecks) {
2191
2281
  errors.push({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reteps/tree-sitter-htmlmustache",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "HTML with Mustache/Handlebars template syntax grammar for tree-sitter",
5
5
  "repository": {
6
6
  "type": "git",