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 +7 -0
- package/dist/index.js +16 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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: [{
|