test-a11y-js 0.6.3 → 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/README.md CHANGED
@@ -12,6 +12,9 @@ npm install --save-dev test-a11y-js
12
12
 
13
13
  - `eslint` (>=8.0.0) - Required for ESLint plugin
14
14
  - `vue-eslint-parser` (>=9.0.0) - Optional, only needed for Vue support
15
+ - `jsdom` (>=23.0.0) - Optional, only needed for HTML string parsing in ESLint rules
16
+
17
+ **Note:** jsdom is only required if you use HTML strings in your code. JSX and Vue templates work without jsdom. See [jsdom Guide](./docs/JSDOM.md) for details.
15
18
 
16
19
  ## Usage
17
20
 
@@ -75,12 +78,24 @@ module.exports = {
75
78
 
76
79
  #### Available Configurations
77
80
 
81
+ - `plugin:test-a11y-js/minimal` - Only critical rules (3 rules) - **Best for large projects**
78
82
  - `plugin:test-a11y-js/recommended` - Balanced approach (default)
79
83
  - `plugin:test-a11y-js/strict` - All rules as errors
80
84
  - `plugin:test-a11y-js/react` - Optimized for React/JSX
81
85
  - `plugin:test-a11y-js/vue` - Optimized for Vue SFC
82
86
 
83
- See [Configuration Guide](./docs/CONFIGURATION.md) for more details.
87
+ ### Quick Start for Large Projects
88
+
89
+ ```javascript
90
+ // .eslintrc.js - Start with minimal rules
91
+ module.exports = {
92
+ plugins: ['test-a11y-js'],
93
+ extends: ['plugin:test-a11y-js/minimal'],
94
+ ignorePatterns: ['**/node_modules/**', '**/dist/**']
95
+ }
96
+ ```
97
+
98
+ See [Configuration Guide](./docs/CONFIGURATION.md) for more details and [Large Project Setup Guide](./docs/LARGE_PROJECTS.md) for incremental adoption strategies.
84
99
 
85
100
  ## API
86
101
 
package/dist/index.js CHANGED
@@ -424,6 +424,15 @@ ${index + 1}. ${violation.id} (${violation.impact})`);
424
424
  }
425
425
  };
426
426
 
427
+ // src/linter/eslint-plugin/configs/minimal.ts
428
+ var minimal = {
429
+ // Only critical/serious violations that block basic accessibility
430
+ "test-a11y-js/button-label": "error",
431
+ "test-a11y-js/form-label": "error",
432
+ "test-a11y-js/image-alt": "error"
433
+ };
434
+ var minimal_default = minimal;
435
+
427
436
  // src/linter/eslint-plugin/configs/recommended.ts
428
437
  var recommended = {
429
438
  // Critical/Serious violations - set to error
@@ -478,7 +487,25 @@ var vue = {
478
487
  var vue_default = vue;
479
488
 
480
489
  // src/linter/eslint-plugin/utils/jsx-ast-utils.ts
481
- var import_jsdom = require("jsdom");
490
+ var JSDOM = null;
491
+ var jsdomWarningShown = false;
492
+ function getJSDOM() {
493
+ if (JSDOM !== null) {
494
+ return JSDOM;
495
+ }
496
+ try {
497
+ JSDOM = require("jsdom").JSDOM;
498
+ return JSDOM;
499
+ } catch (error) {
500
+ if (!jsdomWarningShown) {
501
+ console.warn(
502
+ "[test-a11y-js] jsdom not found. JSX element conversion will be skipped. Install jsdom if you need JSX accessibility checks: npm install --save-dev jsdom"
503
+ );
504
+ jsdomWarningShown = true;
505
+ }
506
+ return null;
507
+ }
508
+ }
482
509
  function getJSXAttributeValue(attr) {
483
510
  if (!attr.value) {
484
511
  return attr.name.name || null;
@@ -531,7 +558,11 @@ function jsxToElement(node, context) {
531
558
  const openingElement = "openingElement" in jsxNode ? jsxNode.openingElement : jsxNode;
532
559
  const tagName = getJSXTagName(openingElement);
533
560
  const attributes = getJSXAttributes(openingElement);
534
- const dom = new import_jsdom.JSDOM("<!DOCTYPE html><html><body></body></html>");
561
+ const JSDOMClass = getJSDOM();
562
+ if (!JSDOMClass) {
563
+ throw new Error("jsdom is required for JSX element conversion");
564
+ }
565
+ const dom = new JSDOMClass("<!DOCTYPE html><html><body></body></html>");
535
566
  const element = dom.window.document.createElement(tagName);
536
567
  for (const [name, value] of attributes.entries()) {
537
568
  element.setAttribute(name, value);
@@ -558,18 +589,38 @@ function hasJSXAttribute(element, name) {
558
589
  return getJSXAttribute(element, name) !== void 0;
559
590
  }
560
591
 
561
- // src/linter/eslint-plugin/utils/html-ast-utils.ts
562
- var import_jsdom2 = require("jsdom");
563
-
564
592
  // src/linter/eslint-plugin/utils/ast-utils.ts
565
593
  function isHTMLLiteral(node) {
566
594
  return node.type === "TemplateLiteral" || node.type === "Literal" || node.type === "TaggedTemplateExpression" && node.tag.name === "html";
567
595
  }
568
596
 
569
597
  // src/linter/eslint-plugin/utils/html-ast-utils.ts
598
+ var JSDOM2 = null;
599
+ var jsdomWarningShown2 = false;
600
+ function getJSDOM2() {
601
+ if (JSDOM2 !== null) {
602
+ return JSDOM2;
603
+ }
604
+ try {
605
+ JSDOM2 = require("jsdom").JSDOM;
606
+ return JSDOM2;
607
+ } catch (error) {
608
+ if (!jsdomWarningShown2) {
609
+ console.warn(
610
+ "[test-a11y-js] jsdom not found. HTML string parsing will be skipped. Install jsdom if you need HTML string accessibility checks: npm install --save-dev jsdom"
611
+ );
612
+ jsdomWarningShown2 = true;
613
+ }
614
+ return null;
615
+ }
616
+ }
570
617
  function parseHTMLString(html) {
618
+ const JSDOMClass = getJSDOM2();
619
+ if (!JSDOMClass) {
620
+ return null;
621
+ }
571
622
  try {
572
- const dom = new import_jsdom2.JSDOM(html, { contentType: "text/html" });
623
+ const dom = new JSDOMClass(html, { contentType: "text/html" });
573
624
  const body = dom.window.document.body;
574
625
  if (body.children.length === 1) {
575
626
  return body.children[0];
@@ -617,7 +668,25 @@ function htmlNodeToElement(node, context) {
617
668
  }
618
669
 
619
670
  // src/linter/eslint-plugin/utils/vue-ast-utils.ts
620
- var import_jsdom3 = require("jsdom");
671
+ var JSDOM3 = null;
672
+ var jsdomWarningShown3 = false;
673
+ function getJSDOM3() {
674
+ if (JSDOM3 !== null) {
675
+ return JSDOM3;
676
+ }
677
+ try {
678
+ JSDOM3 = require("jsdom").JSDOM;
679
+ return JSDOM3;
680
+ } catch (error) {
681
+ if (!jsdomWarningShown3) {
682
+ console.warn(
683
+ "[test-a11y-js] jsdom not found. Vue element conversion will be skipped. Install jsdom if you need Vue accessibility checks: npm install --save-dev jsdom"
684
+ );
685
+ jsdomWarningShown3 = true;
686
+ }
687
+ return null;
688
+ }
689
+ }
621
690
  function getVueAttributeValue(attr) {
622
691
  if (!attr.value) {
623
692
  return attr.key.name || attr.key.argument || null;
@@ -636,7 +705,11 @@ function vueElementToDOM(node, _context) {
636
705
  return null;
637
706
  }
638
707
  const tagName = vueNode.name.toLowerCase();
639
- const dom = new import_jsdom3.JSDOM("<!DOCTYPE html><html><body></body></html>");
708
+ const JSDOMClass = getJSDOM3();
709
+ if (!JSDOMClass) {
710
+ return null;
711
+ }
712
+ const dom = new JSDOMClass("<!DOCTYPE html><html><body></body></html>");
640
713
  const element = dom.window.document.createElement(tagName);
641
714
  if (vueNode.startTag?.attributes) {
642
715
  for (const attr of vueNode.startTag.attributes) {
@@ -2273,7 +2346,7 @@ var dialog_modal_default = rule13;
2273
2346
  var plugin = {
2274
2347
  meta: {
2275
2348
  name: "test-a11y-js",
2276
- version: "0.6.2"
2349
+ version: "0.7.0"
2277
2350
  },
2278
2351
  rules: {
2279
2352
  "image-alt": image_alt_default,
@@ -2291,6 +2364,10 @@ var plugin = {
2291
2364
  "dialog-modal": dialog_modal_default
2292
2365
  },
2293
2366
  configs: {
2367
+ minimal: {
2368
+ plugins: ["test-a11y-js"],
2369
+ rules: minimal_default
2370
+ },
2294
2371
  recommended: {
2295
2372
  plugins: ["test-a11y-js"],
2296
2373
  rules: recommended_default
package/dist/index.mjs CHANGED
@@ -1,3 +1,11 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined")
5
+ return require.apply(this, arguments);
6
+ throw Error('Dynamic require of "' + x + '" is not supported');
7
+ });
8
+
1
9
  // src/core/a11y-checker.ts
2
10
  var A11yChecker = class {
3
11
  static checkImageAlt(element) {
@@ -397,6 +405,15 @@ ${index + 1}. ${violation.id} (${violation.impact})`);
397
405
  }
398
406
  };
399
407
 
408
+ // src/linter/eslint-plugin/configs/minimal.ts
409
+ var minimal = {
410
+ // Only critical/serious violations that block basic accessibility
411
+ "test-a11y-js/button-label": "error",
412
+ "test-a11y-js/form-label": "error",
413
+ "test-a11y-js/image-alt": "error"
414
+ };
415
+ var minimal_default = minimal;
416
+
400
417
  // src/linter/eslint-plugin/configs/recommended.ts
401
418
  var recommended = {
402
419
  // Critical/Serious violations - set to error
@@ -451,7 +468,25 @@ var vue = {
451
468
  var vue_default = vue;
452
469
 
453
470
  // src/linter/eslint-plugin/utils/jsx-ast-utils.ts
454
- import { JSDOM } from "jsdom";
471
+ var JSDOM = null;
472
+ var jsdomWarningShown = false;
473
+ function getJSDOM() {
474
+ if (JSDOM !== null) {
475
+ return JSDOM;
476
+ }
477
+ try {
478
+ JSDOM = __require("jsdom").JSDOM;
479
+ return JSDOM;
480
+ } catch (error) {
481
+ if (!jsdomWarningShown) {
482
+ console.warn(
483
+ "[test-a11y-js] jsdom not found. JSX element conversion will be skipped. Install jsdom if you need JSX accessibility checks: npm install --save-dev jsdom"
484
+ );
485
+ jsdomWarningShown = true;
486
+ }
487
+ return null;
488
+ }
489
+ }
455
490
  function getJSXAttributeValue(attr) {
456
491
  if (!attr.value) {
457
492
  return attr.name.name || null;
@@ -504,7 +539,11 @@ function jsxToElement(node, context) {
504
539
  const openingElement = "openingElement" in jsxNode ? jsxNode.openingElement : jsxNode;
505
540
  const tagName = getJSXTagName(openingElement);
506
541
  const attributes = getJSXAttributes(openingElement);
507
- const dom = new JSDOM("<!DOCTYPE html><html><body></body></html>");
542
+ const JSDOMClass = getJSDOM();
543
+ if (!JSDOMClass) {
544
+ throw new Error("jsdom is required for JSX element conversion");
545
+ }
546
+ const dom = new JSDOMClass("<!DOCTYPE html><html><body></body></html>");
508
547
  const element = dom.window.document.createElement(tagName);
509
548
  for (const [name, value] of attributes.entries()) {
510
549
  element.setAttribute(name, value);
@@ -531,18 +570,38 @@ function hasJSXAttribute(element, name) {
531
570
  return getJSXAttribute(element, name) !== void 0;
532
571
  }
533
572
 
534
- // src/linter/eslint-plugin/utils/html-ast-utils.ts
535
- import { JSDOM as JSDOM2 } from "jsdom";
536
-
537
573
  // src/linter/eslint-plugin/utils/ast-utils.ts
538
574
  function isHTMLLiteral(node) {
539
575
  return node.type === "TemplateLiteral" || node.type === "Literal" || node.type === "TaggedTemplateExpression" && node.tag.name === "html";
540
576
  }
541
577
 
542
578
  // src/linter/eslint-plugin/utils/html-ast-utils.ts
579
+ var JSDOM2 = null;
580
+ var jsdomWarningShown2 = false;
581
+ function getJSDOM2() {
582
+ if (JSDOM2 !== null) {
583
+ return JSDOM2;
584
+ }
585
+ try {
586
+ JSDOM2 = __require("jsdom").JSDOM;
587
+ return JSDOM2;
588
+ } catch (error) {
589
+ if (!jsdomWarningShown2) {
590
+ console.warn(
591
+ "[test-a11y-js] jsdom not found. HTML string parsing will be skipped. Install jsdom if you need HTML string accessibility checks: npm install --save-dev jsdom"
592
+ );
593
+ jsdomWarningShown2 = true;
594
+ }
595
+ return null;
596
+ }
597
+ }
543
598
  function parseHTMLString(html) {
599
+ const JSDOMClass = getJSDOM2();
600
+ if (!JSDOMClass) {
601
+ return null;
602
+ }
544
603
  try {
545
- const dom = new JSDOM2(html, { contentType: "text/html" });
604
+ const dom = new JSDOMClass(html, { contentType: "text/html" });
546
605
  const body = dom.window.document.body;
547
606
  if (body.children.length === 1) {
548
607
  return body.children[0];
@@ -590,7 +649,25 @@ function htmlNodeToElement(node, context) {
590
649
  }
591
650
 
592
651
  // src/linter/eslint-plugin/utils/vue-ast-utils.ts
593
- import { JSDOM as JSDOM3 } from "jsdom";
652
+ var JSDOM3 = null;
653
+ var jsdomWarningShown3 = false;
654
+ function getJSDOM3() {
655
+ if (JSDOM3 !== null) {
656
+ return JSDOM3;
657
+ }
658
+ try {
659
+ JSDOM3 = __require("jsdom").JSDOM;
660
+ return JSDOM3;
661
+ } catch (error) {
662
+ if (!jsdomWarningShown3) {
663
+ console.warn(
664
+ "[test-a11y-js] jsdom not found. Vue element conversion will be skipped. Install jsdom if you need Vue accessibility checks: npm install --save-dev jsdom"
665
+ );
666
+ jsdomWarningShown3 = true;
667
+ }
668
+ return null;
669
+ }
670
+ }
594
671
  function getVueAttributeValue(attr) {
595
672
  if (!attr.value) {
596
673
  return attr.key.name || attr.key.argument || null;
@@ -609,7 +686,11 @@ function vueElementToDOM(node, _context) {
609
686
  return null;
610
687
  }
611
688
  const tagName = vueNode.name.toLowerCase();
612
- const dom = new JSDOM3("<!DOCTYPE html><html><body></body></html>");
689
+ const JSDOMClass = getJSDOM3();
690
+ if (!JSDOMClass) {
691
+ return null;
692
+ }
693
+ const dom = new JSDOMClass("<!DOCTYPE html><html><body></body></html>");
613
694
  const element = dom.window.document.createElement(tagName);
614
695
  if (vueNode.startTag?.attributes) {
615
696
  for (const attr of vueNode.startTag.attributes) {
@@ -2246,7 +2327,7 @@ var dialog_modal_default = rule13;
2246
2327
  var plugin = {
2247
2328
  meta: {
2248
2329
  name: "test-a11y-js",
2249
- version: "0.6.2"
2330
+ version: "0.7.0"
2250
2331
  },
2251
2332
  rules: {
2252
2333
  "image-alt": image_alt_default,
@@ -2264,6 +2345,10 @@ var plugin = {
2264
2345
  "dialog-modal": dialog_modal_default
2265
2346
  },
2266
2347
  configs: {
2348
+ minimal: {
2349
+ plugins: ["test-a11y-js"],
2350
+ rules: minimal_default
2351
+ },
2267
2352
  recommended: {
2268
2353
  plugins: ["test-a11y-js"],
2269
2354
  rules: recommended_default
@@ -24,6 +24,15 @@ __export(eslint_plugin_exports, {
24
24
  });
25
25
  module.exports = __toCommonJS(eslint_plugin_exports);
26
26
 
27
+ // src/linter/eslint-plugin/configs/minimal.ts
28
+ var minimal = {
29
+ // Only critical/serious violations that block basic accessibility
30
+ "test-a11y-js/button-label": "error",
31
+ "test-a11y-js/form-label": "error",
32
+ "test-a11y-js/image-alt": "error"
33
+ };
34
+ var minimal_default = minimal;
35
+
27
36
  // src/linter/eslint-plugin/configs/recommended.ts
28
37
  var recommended = {
29
38
  // Critical/Serious violations - set to error
@@ -477,7 +486,25 @@ ${index + 1}. ${violation.id} (${violation.impact})`);
477
486
  };
478
487
 
479
488
  // src/linter/eslint-plugin/utils/jsx-ast-utils.ts
480
- var import_jsdom = require("jsdom");
489
+ var JSDOM = null;
490
+ var jsdomWarningShown = false;
491
+ function getJSDOM() {
492
+ if (JSDOM !== null) {
493
+ return JSDOM;
494
+ }
495
+ try {
496
+ JSDOM = require("jsdom").JSDOM;
497
+ return JSDOM;
498
+ } catch (error) {
499
+ if (!jsdomWarningShown) {
500
+ console.warn(
501
+ "[test-a11y-js] jsdom not found. JSX element conversion will be skipped. Install jsdom if you need JSX accessibility checks: npm install --save-dev jsdom"
502
+ );
503
+ jsdomWarningShown = true;
504
+ }
505
+ return null;
506
+ }
507
+ }
481
508
  function getJSXAttributeValue(attr) {
482
509
  if (!attr.value) {
483
510
  return attr.name.name || null;
@@ -530,7 +557,11 @@ function jsxToElement(node, context) {
530
557
  const openingElement = "openingElement" in jsxNode ? jsxNode.openingElement : jsxNode;
531
558
  const tagName = getJSXTagName(openingElement);
532
559
  const attributes = getJSXAttributes(openingElement);
533
- const dom = new import_jsdom.JSDOM("<!DOCTYPE html><html><body></body></html>");
560
+ const JSDOMClass = getJSDOM();
561
+ if (!JSDOMClass) {
562
+ throw new Error("jsdom is required for JSX element conversion");
563
+ }
564
+ const dom = new JSDOMClass("<!DOCTYPE html><html><body></body></html>");
534
565
  const element = dom.window.document.createElement(tagName);
535
566
  for (const [name, value] of attributes.entries()) {
536
567
  element.setAttribute(name, value);
@@ -557,18 +588,38 @@ function hasJSXAttribute(element, name) {
557
588
  return getJSXAttribute(element, name) !== void 0;
558
589
  }
559
590
 
560
- // src/linter/eslint-plugin/utils/html-ast-utils.ts
561
- var import_jsdom2 = require("jsdom");
562
-
563
591
  // src/linter/eslint-plugin/utils/ast-utils.ts
564
592
  function isHTMLLiteral(node) {
565
593
  return node.type === "TemplateLiteral" || node.type === "Literal" || node.type === "TaggedTemplateExpression" && node.tag.name === "html";
566
594
  }
567
595
 
568
596
  // src/linter/eslint-plugin/utils/html-ast-utils.ts
597
+ var JSDOM2 = null;
598
+ var jsdomWarningShown2 = false;
599
+ function getJSDOM2() {
600
+ if (JSDOM2 !== null) {
601
+ return JSDOM2;
602
+ }
603
+ try {
604
+ JSDOM2 = require("jsdom").JSDOM;
605
+ return JSDOM2;
606
+ } catch (error) {
607
+ if (!jsdomWarningShown2) {
608
+ console.warn(
609
+ "[test-a11y-js] jsdom not found. HTML string parsing will be skipped. Install jsdom if you need HTML string accessibility checks: npm install --save-dev jsdom"
610
+ );
611
+ jsdomWarningShown2 = true;
612
+ }
613
+ return null;
614
+ }
615
+ }
569
616
  function parseHTMLString(html) {
617
+ const JSDOMClass = getJSDOM2();
618
+ if (!JSDOMClass) {
619
+ return null;
620
+ }
570
621
  try {
571
- const dom = new import_jsdom2.JSDOM(html, { contentType: "text/html" });
622
+ const dom = new JSDOMClass(html, { contentType: "text/html" });
572
623
  const body = dom.window.document.body;
573
624
  if (body.children.length === 1) {
574
625
  return body.children[0];
@@ -616,7 +667,25 @@ function htmlNodeToElement(node, context) {
616
667
  }
617
668
 
618
669
  // src/linter/eslint-plugin/utils/vue-ast-utils.ts
619
- var import_jsdom3 = require("jsdom");
670
+ var JSDOM3 = null;
671
+ var jsdomWarningShown3 = false;
672
+ function getJSDOM3() {
673
+ if (JSDOM3 !== null) {
674
+ return JSDOM3;
675
+ }
676
+ try {
677
+ JSDOM3 = require("jsdom").JSDOM;
678
+ return JSDOM3;
679
+ } catch (error) {
680
+ if (!jsdomWarningShown3) {
681
+ console.warn(
682
+ "[test-a11y-js] jsdom not found. Vue element conversion will be skipped. Install jsdom if you need Vue accessibility checks: npm install --save-dev jsdom"
683
+ );
684
+ jsdomWarningShown3 = true;
685
+ }
686
+ return null;
687
+ }
688
+ }
620
689
  function getVueAttributeValue(attr) {
621
690
  if (!attr.value) {
622
691
  return attr.key.name || attr.key.argument || null;
@@ -635,7 +704,11 @@ function vueElementToDOM(node, _context) {
635
704
  return null;
636
705
  }
637
706
  const tagName = vueNode.name.toLowerCase();
638
- const dom = new import_jsdom3.JSDOM("<!DOCTYPE html><html><body></body></html>");
707
+ const JSDOMClass = getJSDOM3();
708
+ if (!JSDOMClass) {
709
+ return null;
710
+ }
711
+ const dom = new JSDOMClass("<!DOCTYPE html><html><body></body></html>");
639
712
  const element = dom.window.document.createElement(tagName);
640
713
  if (vueNode.startTag?.attributes) {
641
714
  for (const attr of vueNode.startTag.attributes) {
@@ -2272,7 +2345,7 @@ var dialog_modal_default = rule13;
2272
2345
  var plugin = {
2273
2346
  meta: {
2274
2347
  name: "test-a11y-js",
2275
- version: "0.6.2"
2348
+ version: "0.7.0"
2276
2349
  },
2277
2350
  rules: {
2278
2351
  "image-alt": image_alt_default,
@@ -2290,6 +2363,10 @@ var plugin = {
2290
2363
  "dialog-modal": dialog_modal_default
2291
2364
  },
2292
2365
  configs: {
2366
+ minimal: {
2367
+ plugins: ["test-a11y-js"],
2368
+ rules: minimal_default
2369
+ },
2293
2370
  recommended: {
2294
2371
  plugins: ["test-a11y-js"],
2295
2372
  rules: recommended_default
@@ -1,3 +1,20 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined")
5
+ return require.apply(this, arguments);
6
+ throw Error('Dynamic require of "' + x + '" is not supported');
7
+ });
8
+
9
+ // src/linter/eslint-plugin/configs/minimal.ts
10
+ var minimal = {
11
+ // Only critical/serious violations that block basic accessibility
12
+ "test-a11y-js/button-label": "error",
13
+ "test-a11y-js/form-label": "error",
14
+ "test-a11y-js/image-alt": "error"
15
+ };
16
+ var minimal_default = minimal;
17
+
1
18
  // src/linter/eslint-plugin/configs/recommended.ts
2
19
  var recommended = {
3
20
  // Critical/Serious violations - set to error
@@ -451,7 +468,25 @@ ${index + 1}. ${violation.id} (${violation.impact})`);
451
468
  };
452
469
 
453
470
  // src/linter/eslint-plugin/utils/jsx-ast-utils.ts
454
- import { JSDOM } from "jsdom";
471
+ var JSDOM = null;
472
+ var jsdomWarningShown = false;
473
+ function getJSDOM() {
474
+ if (JSDOM !== null) {
475
+ return JSDOM;
476
+ }
477
+ try {
478
+ JSDOM = __require("jsdom").JSDOM;
479
+ return JSDOM;
480
+ } catch (error) {
481
+ if (!jsdomWarningShown) {
482
+ console.warn(
483
+ "[test-a11y-js] jsdom not found. JSX element conversion will be skipped. Install jsdom if you need JSX accessibility checks: npm install --save-dev jsdom"
484
+ );
485
+ jsdomWarningShown = true;
486
+ }
487
+ return null;
488
+ }
489
+ }
455
490
  function getJSXAttributeValue(attr) {
456
491
  if (!attr.value) {
457
492
  return attr.name.name || null;
@@ -504,7 +539,11 @@ function jsxToElement(node, context) {
504
539
  const openingElement = "openingElement" in jsxNode ? jsxNode.openingElement : jsxNode;
505
540
  const tagName = getJSXTagName(openingElement);
506
541
  const attributes = getJSXAttributes(openingElement);
507
- const dom = new JSDOM("<!DOCTYPE html><html><body></body></html>");
542
+ const JSDOMClass = getJSDOM();
543
+ if (!JSDOMClass) {
544
+ throw new Error("jsdom is required for JSX element conversion");
545
+ }
546
+ const dom = new JSDOMClass("<!DOCTYPE html><html><body></body></html>");
508
547
  const element = dom.window.document.createElement(tagName);
509
548
  for (const [name, value] of attributes.entries()) {
510
549
  element.setAttribute(name, value);
@@ -531,18 +570,38 @@ function hasJSXAttribute(element, name) {
531
570
  return getJSXAttribute(element, name) !== void 0;
532
571
  }
533
572
 
534
- // src/linter/eslint-plugin/utils/html-ast-utils.ts
535
- import { JSDOM as JSDOM2 } from "jsdom";
536
-
537
573
  // src/linter/eslint-plugin/utils/ast-utils.ts
538
574
  function isHTMLLiteral(node) {
539
575
  return node.type === "TemplateLiteral" || node.type === "Literal" || node.type === "TaggedTemplateExpression" && node.tag.name === "html";
540
576
  }
541
577
 
542
578
  // src/linter/eslint-plugin/utils/html-ast-utils.ts
579
+ var JSDOM2 = null;
580
+ var jsdomWarningShown2 = false;
581
+ function getJSDOM2() {
582
+ if (JSDOM2 !== null) {
583
+ return JSDOM2;
584
+ }
585
+ try {
586
+ JSDOM2 = __require("jsdom").JSDOM;
587
+ return JSDOM2;
588
+ } catch (error) {
589
+ if (!jsdomWarningShown2) {
590
+ console.warn(
591
+ "[test-a11y-js] jsdom not found. HTML string parsing will be skipped. Install jsdom if you need HTML string accessibility checks: npm install --save-dev jsdom"
592
+ );
593
+ jsdomWarningShown2 = true;
594
+ }
595
+ return null;
596
+ }
597
+ }
543
598
  function parseHTMLString(html) {
599
+ const JSDOMClass = getJSDOM2();
600
+ if (!JSDOMClass) {
601
+ return null;
602
+ }
544
603
  try {
545
- const dom = new JSDOM2(html, { contentType: "text/html" });
604
+ const dom = new JSDOMClass(html, { contentType: "text/html" });
546
605
  const body = dom.window.document.body;
547
606
  if (body.children.length === 1) {
548
607
  return body.children[0];
@@ -590,7 +649,25 @@ function htmlNodeToElement(node, context) {
590
649
  }
591
650
 
592
651
  // src/linter/eslint-plugin/utils/vue-ast-utils.ts
593
- import { JSDOM as JSDOM3 } from "jsdom";
652
+ var JSDOM3 = null;
653
+ var jsdomWarningShown3 = false;
654
+ function getJSDOM3() {
655
+ if (JSDOM3 !== null) {
656
+ return JSDOM3;
657
+ }
658
+ try {
659
+ JSDOM3 = __require("jsdom").JSDOM;
660
+ return JSDOM3;
661
+ } catch (error) {
662
+ if (!jsdomWarningShown3) {
663
+ console.warn(
664
+ "[test-a11y-js] jsdom not found. Vue element conversion will be skipped. Install jsdom if you need Vue accessibility checks: npm install --save-dev jsdom"
665
+ );
666
+ jsdomWarningShown3 = true;
667
+ }
668
+ return null;
669
+ }
670
+ }
594
671
  function getVueAttributeValue(attr) {
595
672
  if (!attr.value) {
596
673
  return attr.key.name || attr.key.argument || null;
@@ -609,7 +686,11 @@ function vueElementToDOM(node, _context) {
609
686
  return null;
610
687
  }
611
688
  const tagName = vueNode.name.toLowerCase();
612
- const dom = new JSDOM3("<!DOCTYPE html><html><body></body></html>");
689
+ const JSDOMClass = getJSDOM3();
690
+ if (!JSDOMClass) {
691
+ return null;
692
+ }
693
+ const dom = new JSDOMClass("<!DOCTYPE html><html><body></body></html>");
613
694
  const element = dom.window.document.createElement(tagName);
614
695
  if (vueNode.startTag?.attributes) {
615
696
  for (const attr of vueNode.startTag.attributes) {
@@ -2246,7 +2327,7 @@ var dialog_modal_default = rule13;
2246
2327
  var plugin = {
2247
2328
  meta: {
2248
2329
  name: "test-a11y-js",
2249
- version: "0.6.2"
2330
+ version: "0.7.0"
2250
2331
  },
2251
2332
  rules: {
2252
2333
  "image-alt": image_alt_default,
@@ -2264,6 +2345,10 @@ var plugin = {
2264
2345
  "dialog-modal": dialog_modal_default
2265
2346
  },
2266
2347
  configs: {
2348
+ minimal: {
2349
+ plugins: ["test-a11y-js"],
2350
+ rules: minimal_default
2351
+ },
2267
2352
  recommended: {
2268
2353
  plugins: ["test-a11y-js"],
2269
2354
  rules: recommended_default
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "test-a11y-js",
3
- "version": "0.6.3",
3
+ "version": "0.7.0",
4
4
  "description": "A JavaScript library for testing component accessibility across multiple testing frameworks",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -64,8 +64,15 @@
64
64
  "peerDependenciesMeta": {
65
65
  "vue-eslint-parser": {
66
66
  "optional": true
67
+ },
68
+ "jsdom": {
69
+ "optional": true,
70
+ "description": "Required only for HTML string parsing in ESLint rules"
67
71
  }
68
72
  },
73
+ "optionalDependencies": {
74
+ "jsdom": "^23.0.0"
75
+ },
69
76
  "devDependencies": {
70
77
  "@testing-library/dom": "^9.0.0",
71
78
  "@types/node": "^18.15.0",