shadscan-vue 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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.1](https://github.com/vinayakkulkarni/shadscan-vue/compare/v0.2.0...v0.2.1) (2026-07-26)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **rules:** treat slot-projected content as an accessible name ([4dc2cc0](https://github.com/vinayakkulkarni/shadscan-vue/commit/4dc2cc0413b28f76783c85035f4ca83b46feaa39))
9
+
3
10
  ## [0.2.0](https://github.com/vinayakkulkarni/shadscan-vue/compare/v0.1.2...v0.2.0) (2026-07-26)
4
11
 
5
12
 
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import path from "node:path";
4
4
  import { cac } from "cac";
5
5
  import { glob } from "tinyglobby";
6
6
  import { parse } from "@vue/compiler-sfc";
7
- import { NodeTypes } from "@vue/compiler-dom";
7
+ import { ElementTypes, NodeTypes } from "@vue/compiler-dom";
8
8
  import ts from "typescript";
9
9
  import { parse as parse$1 } from "jsonc-parser";
10
10
  import pc from "picocolors";
@@ -736,6 +736,19 @@ const collectText = (children) => {
736
736
  };
737
737
  const visibleText = (element) => collectText(element.children).trim();
738
738
  /**
739
+ * True when the element projects caller-supplied content through a `<slot>`.
740
+ * The name then lives at the call site, so the component itself cannot be
741
+ * judged nameless — `<a><slot /></a>` is a wrapper, not an anonymous link.
742
+ */
743
+ const projectsSlotContent = (element) => {
744
+ for (const child of element.children) {
745
+ if (child.type !== NodeTypes.ELEMENT) continue;
746
+ if (child.tagType === ElementTypes.SLOT) return true;
747
+ if (projectsSlotContent(child)) return true;
748
+ }
749
+ return false;
750
+ };
751
+ /**
739
752
  * True when the element carries an explicit accessible name via ARIA,
740
753
  * a title, or visually-hidden text.
741
754
  */
@@ -1234,7 +1247,7 @@ const iconButtonsHaveLabels = {
1234
1247
  const children = elementChildren(element);
1235
1248
  if (!(children.length > 0 && children.every((child) => isIconTag$1(child.tag)) || findAttribute(element, "size")?.static === "icon")) return;
1236
1249
  if (visibleText(element).length > 0) return;
1237
- if (hasAriaName(element) || hasScreenReaderText(element)) return;
1250
+ if (hasAriaName(element) || hasScreenReaderText(element) || projectsSlotContent(element)) return;
1238
1251
  findings.push({
1239
1252
  message: `Icon-only <${element.tag}> has no accessible name.`,
1240
1253
  evidence: [{
@@ -1439,7 +1452,7 @@ const linksHaveAccessibleNames = {
1439
1452
  if (!LINK_TAGS$2.has(element.tag)) return;
1440
1453
  if (visibleText(element).length > 0) return;
1441
1454
  if (hasAriaName(element) || hasScreenReaderText(element)) return;
1442
- if (hasLabelledImage(element)) return;
1455
+ if (hasLabelledImage(element) || projectsSlotContent(element)) return;
1443
1456
  findings.push({
1444
1457
  message: `<${element.tag}> has no accessible name.`,
1445
1458
  evidence: [{