@emulsify/core 4.3.2 → 4.5.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/.storybook/main-static-assets.js +5 -8
- package/.storybook/main-vite.js +11 -3
- package/README.md +14 -6
- package/config/a11y-wcag22.js +11 -0
- package/config/vite/entries.js +7 -2
- package/config/vite/environment.js +4 -0
- package/config/vite/plugins/assets/asset-url-rebase.js +241 -0
- package/config/vite/plugins/assets/copy-src-assets.js +82 -12
- package/config/vite/plugins/assets/copy-twig-files.js +85 -16
- package/config/vite/plugins/assets/css-asset-rebase.js +306 -0
- package/config/vite/plugins/assets/css-asset-relativizer.js +301 -21
- package/config/vite/plugins/assets/development-source-maps.js +273 -0
- package/config/vite/plugins/assets/mirror-components.js +98 -82
- package/config/vite/plugins/assets/output-freshness.js +235 -0
- package/config/vite/plugins/assets/source-file-index.js +13 -13
- package/config/vite/plugins/assets/stable-watch-output.js +165 -0
- package/config/vite/plugins/assets/storybook-output.js +27 -0
- package/config/vite/plugins/index.js +95 -9
- package/config/vite/plugins/reporter/asset-resolver.js +34 -6
- package/config/vite/plugins/reporter/build-errors.js +7 -3
- package/config/vite/plugins/reporter/diagnostics.js +140 -10
- package/config/vite/plugins/reporter/index.js +380 -75
- package/config/vite/plugins/reporter/render.js +297 -44
- package/config/vite/plugins/reporter/sass-logger.js +30 -0
- package/config/vite/plugins/reporter/source-roots.js +101 -21
- package/config/vite/plugins/reporter/strict-mode.js +99 -0
- package/config/vite/plugins/reporter/vite-logger.js +220 -8
- package/config/vite/plugins/reporter/watch-mode.js +6 -2
- package/config/vite/plugins/twig/twig-module.js +35 -258
- package/config/vite/plugins/twig/virtual-twig-asset-sources.js +48 -49
- package/config/vite/project-config.js +121 -21
- package/config/vite/project-structure.js +6 -0
- package/config/vite/utils/asset-roots.js +205 -0
- package/config/vite/utils/css-urls.js +350 -0
- package/config/vite/utils/fs-safe.js +38 -1
- package/config/vite/utils/source-directory-skips.js +13 -0
- package/config/vite/utils/source-maps.js +88 -0
- package/config/vite/utils/twig-component-resolver.js +316 -0
- package/config/vite/vite.config.js +106 -42
- package/package.json +54 -40
- package/scripts/a11y.js +88 -9
- package/scripts/audit/checks/css-asset-references.js +256 -24
- package/scripts/audit/checks/twig-references.js +16 -5
- package/scripts/audit/fix.js +836 -0
- package/scripts/audit/index.js +10 -2
- package/scripts/audit/lib/css.js +41 -35
- package/scripts/audit/lib/story-ast.js +392 -0
- package/scripts/audit/lib/story-render-paths.js +600 -0
- package/scripts/audit/lib/story-selection.js +190 -0
- package/scripts/audit/lib/twig.js +372 -80
- package/scripts/audit/report.js +83 -5
- package/scripts/audit-twig-stories.js +73 -3
- package/scripts/audit.js +87 -2
- package/src/storybook/twig/source-function.js +14 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@emulsify/core",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.5.0",
|
|
4
4
|
"description": "Bundled tooling for Storybook development + Vite Build",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"component library",
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"assets/**/*",
|
|
53
53
|
"config/.prettierrc.json",
|
|
54
54
|
"config/.stylelintrc.json",
|
|
55
|
+
"config/a11y-wcag22.js",
|
|
55
56
|
"config/a11y.config.js",
|
|
56
57
|
"config/babel.config.js",
|
|
57
58
|
"config/eslint.config.js",
|
|
@@ -59,11 +60,18 @@
|
|
|
59
60
|
"config/vite/entries.js",
|
|
60
61
|
"config/vite/environment.js",
|
|
61
62
|
"config/vite/platforms.js",
|
|
63
|
+
"config/vite/plugins.js",
|
|
64
|
+
"config/vite/plugins/assets/asset-url-rebase.js",
|
|
62
65
|
"config/vite/plugins/assets/copy-src-assets.js",
|
|
63
66
|
"config/vite/plugins/assets/copy-twig-files.js",
|
|
67
|
+
"config/vite/plugins/assets/css-asset-rebase.js",
|
|
64
68
|
"config/vite/plugins/assets/css-asset-relativizer.js",
|
|
69
|
+
"config/vite/plugins/assets/development-source-maps.js",
|
|
65
70
|
"config/vite/plugins/assets/mirror-components.js",
|
|
71
|
+
"config/vite/plugins/assets/output-freshness.js",
|
|
66
72
|
"config/vite/plugins/assets/source-file-index.js",
|
|
73
|
+
"config/vite/plugins/assets/stable-watch-output.js",
|
|
74
|
+
"config/vite/plugins/assets/storybook-output.js",
|
|
67
75
|
"config/vite/plugins/assets/svg-sprite.js",
|
|
68
76
|
"config/vite/plugins/index.js",
|
|
69
77
|
"config/vite/plugins/reporter/asset-resolver.js",
|
|
@@ -74,6 +82,7 @@
|
|
|
74
82
|
"config/vite/plugins/reporter/render.js",
|
|
75
83
|
"config/vite/plugins/reporter/sass-logger.js",
|
|
76
84
|
"config/vite/plugins/reporter/source-roots.js",
|
|
85
|
+
"config/vite/plugins/reporter/strict-mode.js",
|
|
77
86
|
"config/vite/plugins/reporter/verbosity.js",
|
|
78
87
|
"config/vite/plugins/reporter/vite-logger.js",
|
|
79
88
|
"config/vite/plugins/reporter/watch-mode.js",
|
|
@@ -85,23 +94,24 @@
|
|
|
85
94
|
"config/vite/plugins/twig/virtual-twig-globs.js",
|
|
86
95
|
"config/vite/plugins/twig/vituum-patch.js",
|
|
87
96
|
"config/vite/plugins/yaml-module.js",
|
|
88
|
-
"config/vite/plugins.js",
|
|
89
97
|
"config/vite/project-config.js",
|
|
90
98
|
"config/vite/project-extensions.js",
|
|
91
99
|
"config/vite/project-structure.js",
|
|
100
|
+
"config/vite/utils/asset-roots.js",
|
|
101
|
+
"config/vite/utils/css-urls.js",
|
|
92
102
|
"config/vite/utils/fs-safe.js",
|
|
93
103
|
"config/vite/utils/lru.js",
|
|
94
104
|
"config/vite/utils/package-version.js",
|
|
95
105
|
"config/vite/utils/paths.js",
|
|
96
106
|
"config/vite/utils/react-singleton.js",
|
|
107
|
+
"config/vite/utils/source-directory-skips.js",
|
|
108
|
+
"config/vite/utils/source-maps.js",
|
|
109
|
+
"config/vite/utils/twig-component-resolver.js",
|
|
97
110
|
"config/vite/vite.config.js",
|
|
98
111
|
"scripts/a11y.js",
|
|
112
|
+
"scripts/audit-twig-stories.js",
|
|
99
113
|
"scripts/audit.js",
|
|
100
114
|
"scripts/audit/**/*.js",
|
|
101
|
-
"!scripts/audit/**/*.test.js",
|
|
102
|
-
"!scripts/audit/**/__snapshots__/**",
|
|
103
|
-
"!scripts/audit/test-utils.js",
|
|
104
|
-
"scripts/audit-twig-stories.js",
|
|
105
115
|
"scripts/check-node-version.js",
|
|
106
116
|
"scripts/inspect-components.js",
|
|
107
117
|
"scripts/lib/cli.js",
|
|
@@ -139,7 +149,10 @@
|
|
|
139
149
|
"src/storybook/twig/resolver.js",
|
|
140
150
|
"src/storybook/twig/setup.js",
|
|
141
151
|
"src/storybook/twig/source-function.js",
|
|
142
|
-
"src/storybook/twig/source.js"
|
|
152
|
+
"src/storybook/twig/source.js",
|
|
153
|
+
"!scripts/audit/**/*.test.js",
|
|
154
|
+
"!scripts/audit/**/__snapshots__/**",
|
|
155
|
+
"!scripts/audit/test-utils.js"
|
|
143
156
|
],
|
|
144
157
|
"exports": {
|
|
145
158
|
".": "./src/extensions/index.js",
|
|
@@ -151,13 +164,15 @@
|
|
|
151
164
|
"./storybook/twig/include-function": "./src/storybook/twig/include-function.js",
|
|
152
165
|
"./storybook/twig/source-function": "./src/storybook/twig/source-function.js",
|
|
153
166
|
"./storybook/twig/source": "./src/storybook/twig/source.js",
|
|
167
|
+
"./a11y/wcag22": "./config/a11y-wcag22.js",
|
|
154
168
|
"./vite": "./config/vite/vite.config.js",
|
|
155
169
|
"./vite/plugins": "./config/vite/plugins.js",
|
|
156
170
|
"./vite/platforms": "./config/vite/platforms.js",
|
|
157
171
|
"./package.json": "./package.json"
|
|
158
172
|
},
|
|
159
173
|
"publishConfig": {
|
|
160
|
-
"access": "public"
|
|
174
|
+
"access": "public",
|
|
175
|
+
"provenance": true
|
|
161
176
|
},
|
|
162
177
|
"config": {
|
|
163
178
|
"scripts-prepend-node-path": "auto"
|
|
@@ -184,7 +199,7 @@
|
|
|
184
199
|
"prettier": "npm run check-node-version && prettier --check --config config/.prettierrc.json --ignore-unknown \"**/*.{js,mjs,cjs,jsx,json,yml,yaml,scss,md,twig}\"",
|
|
185
200
|
"prettier-fix": "npm run check-node-version && prettier --config config/.prettierrc.json --write --ignore-unknown \"**/*.{js,mjs,cjs,jsx,json,yml,yaml,scss,md,twig}\"",
|
|
186
201
|
"release:analyze": "npm run check-node-version && node scripts/verify-release-analysis.js",
|
|
187
|
-
"release:verify": "
|
|
202
|
+
"release:verify": "node scripts/release-evidence.js verify",
|
|
188
203
|
"semantic-release": "npm run check-node-version && semantic-release --config ./release.config.cjs",
|
|
189
204
|
"smoke:pack": "npm run check-node-version && node scripts/smoke-pack.js",
|
|
190
205
|
"version:develop": "npm run check-node-version && node scripts/bump-version-from-commits.js",
|
|
@@ -197,61 +212,60 @@
|
|
|
197
212
|
"dependencies": {
|
|
198
213
|
"@babel/core": "^7.29.7",
|
|
199
214
|
"@babel/eslint-parser": "^7.29.7",
|
|
215
|
+
"@babel/parser": "^7.29.8",
|
|
200
216
|
"@babel/preset-env": "^7.29.7",
|
|
201
|
-
"@emulsify/cli": "^2.
|
|
217
|
+
"@emulsify/cli": "^2.4.1",
|
|
202
218
|
"@eslint/js": "^9.39.5",
|
|
203
219
|
"@mlnop/vite-plugin-sass-glob-import": "^6.2.0",
|
|
204
|
-
"@storybook/addon-a11y": "^10.
|
|
205
|
-
"@storybook/addon-links": "^10.
|
|
206
|
-
"@storybook/addon-themes": "^10.
|
|
207
|
-
"@storybook/react": "^10.
|
|
208
|
-
"@storybook/react-vite": "^10.
|
|
220
|
+
"@storybook/addon-a11y": "^10.6.0",
|
|
221
|
+
"@storybook/addon-links": "^10.6.0",
|
|
222
|
+
"@storybook/addon-themes": "^10.6.0",
|
|
223
|
+
"@storybook/react": "^10.6.0",
|
|
224
|
+
"@storybook/react-vite": "^10.6.0",
|
|
209
225
|
"@vituum/vite-plugin-twig": "^2.0.1",
|
|
210
|
-
"autoprefixer": "^10.5.
|
|
211
|
-
"axe-core": "^4.
|
|
226
|
+
"autoprefixer": "^10.5.6",
|
|
227
|
+
"axe-core": "^4.13.0",
|
|
212
228
|
"babel-preset-minify": "^0.5.2",
|
|
213
|
-
"concurrently": "^10.0.
|
|
229
|
+
"concurrently": "^10.0.5",
|
|
214
230
|
"eslint": "^9.39.5",
|
|
215
231
|
"eslint-config-prettier": "^10.1.8",
|
|
216
232
|
"eslint-plugin-import": "^2.32.0",
|
|
217
|
-
"eslint-plugin-jest": "^29.16.
|
|
233
|
+
"eslint-plugin-jest": "^29.16.6",
|
|
218
234
|
"eslint-plugin-prettier": "^5.5.6",
|
|
219
235
|
"eslint-plugin-security": "^4.0.1",
|
|
220
|
-
"eslint-plugin-storybook": "^10.
|
|
236
|
+
"eslint-plugin-storybook": "^10.6.0",
|
|
221
237
|
"glob": "^13.0.6",
|
|
222
|
-
"jest": "^30.
|
|
223
|
-
"jest-environment-jsdom": "^30.
|
|
224
|
-
"js-yaml": "^5.
|
|
238
|
+
"jest": "^30.5.1",
|
|
239
|
+
"jest-environment-jsdom": "^30.5.1",
|
|
240
|
+
"js-yaml": "^5.4.1",
|
|
225
241
|
"normalize.css": "^8.0.1",
|
|
226
242
|
"open-cli": "^9.0.0",
|
|
227
243
|
"pa11y": "^9.1.1",
|
|
228
|
-
"postcss": "^8.5.
|
|
244
|
+
"postcss": "^8.5.28",
|
|
229
245
|
"postcss-scss": "^4.0.9",
|
|
230
|
-
"sass": "^1.
|
|
231
|
-
"storybook": "^10.
|
|
232
|
-
"stylelint": "^17.
|
|
246
|
+
"sass": "^1.104.0",
|
|
247
|
+
"storybook": "^10.6.0",
|
|
248
|
+
"stylelint": "^17.15.0",
|
|
233
249
|
"stylelint-config-standard-scss": "^17.0.0",
|
|
234
250
|
"stylelint-prettier": "^5.0.3",
|
|
235
251
|
"stylelint-selector-bem-pattern": "^5.0.0",
|
|
236
252
|
"twig": "^3.0.0",
|
|
237
253
|
"twig-drupal-filters": "^3.2.0",
|
|
238
|
-
"vite": "^8.
|
|
254
|
+
"vite": "^8.3.0"
|
|
239
255
|
},
|
|
240
256
|
"devDependencies": {
|
|
241
|
-
"@commitlint/cli": "^21.2.
|
|
242
|
-
"@commitlint/config-conventional": "^21.2.
|
|
243
|
-
"@semantic-release/changelog": "^7.0.0",
|
|
257
|
+
"@commitlint/cli": "^21.2.2",
|
|
258
|
+
"@commitlint/config-conventional": "^21.2.2",
|
|
244
259
|
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
245
|
-
"@semantic-release/git": "^11.0.1",
|
|
246
260
|
"@semantic-release/github": "^12.0.9",
|
|
247
261
|
"@semantic-release/npm": "^13.1.5",
|
|
248
262
|
"@semantic-release/release-notes-generator": "^14.1.1",
|
|
249
263
|
"husky": "^9.1.7",
|
|
250
|
-
"lint-staged": "^17.
|
|
251
|
-
"puppeteer": "^25.
|
|
252
|
-
"react": "^19.
|
|
253
|
-
"react-dom": "^19.
|
|
254
|
-
"semantic-release": "^25.0.
|
|
264
|
+
"lint-staged": "^17.5.1",
|
|
265
|
+
"puppeteer": "^25.10.0",
|
|
266
|
+
"react": "^19.3.0",
|
|
267
|
+
"react-dom": "^19.3.0",
|
|
268
|
+
"semantic-release": "^25.0.9"
|
|
255
269
|
},
|
|
256
270
|
"peerDependencies": {
|
|
257
271
|
"react": "^18.0.0 || ^19.0.0",
|
|
@@ -263,11 +277,11 @@
|
|
|
263
277
|
"minimatch@3.0.x": "^3.1.5"
|
|
264
278
|
},
|
|
265
279
|
"allowScripts": {
|
|
280
|
+
"fsevents@2.3.3": true,
|
|
281
|
+
"unrs-resolver@1.12.2": true,
|
|
266
282
|
"@parcel/watcher@2.6.0": true,
|
|
267
283
|
"esbuild@0.28.1": true,
|
|
268
|
-
"fsevents@2.3.3": true,
|
|
269
284
|
"puppeteer@24.43.1": true,
|
|
270
|
-
"
|
|
271
|
-
"puppeteer@25.4.0": true
|
|
285
|
+
"puppeteer@25.10.0": true
|
|
272
286
|
}
|
|
273
287
|
}
|
package/scripts/a11y.js
CHANGED
|
@@ -15,6 +15,7 @@ import a11yConfig from '../config/a11y.config.js';
|
|
|
15
15
|
|
|
16
16
|
// Project-specific configuration.
|
|
17
17
|
let {
|
|
18
|
+
concurrency = 2,
|
|
18
19
|
ignore = {},
|
|
19
20
|
components = [],
|
|
20
21
|
discoverStories = true,
|
|
@@ -49,10 +50,16 @@ const loadProjectA11yConfig = async (projectDir = process.cwd()) => {
|
|
|
49
50
|
/**
|
|
50
51
|
* Apply project-specific a11y config values over shared defaults.
|
|
51
52
|
*
|
|
52
|
-
* @param {{ignore?: object, components?: string[], discoverStories?: boolean, storybookBuildDir?: string, pa11y?: object}} config - Project config.
|
|
53
|
+
* @param {{concurrency?: number, ignore?: object, components?: string[], discoverStories?: boolean, storybookBuildDir?: string, pa11y?: object}} config - Project config.
|
|
53
54
|
* @returns {void}
|
|
54
55
|
*/
|
|
55
56
|
const applyProjectA11yConfig = (config = {}) => {
|
|
57
|
+
if (config.concurrency !== undefined) {
|
|
58
|
+
if (!Number.isSafeInteger(config.concurrency) || config.concurrency < 1) {
|
|
59
|
+
throw new Error('Accessibility concurrency must be a positive integer.');
|
|
60
|
+
}
|
|
61
|
+
concurrency = config.concurrency;
|
|
62
|
+
}
|
|
56
63
|
ignore = config.ignore || ignore;
|
|
57
64
|
components = Array.isArray(config.components)
|
|
58
65
|
? config.components
|
|
@@ -353,14 +360,23 @@ const logReport = ({ issues, pageUrl }) => {
|
|
|
353
360
|
return hasIssues;
|
|
354
361
|
};
|
|
355
362
|
|
|
363
|
+
/**
|
|
364
|
+
* Build the requested URL consistently for scans and execution-failure reports.
|
|
365
|
+
* @param {string} name - Story ID.
|
|
366
|
+
* @param {{baseUrl?: string}} [options={}] - Storybook origin options.
|
|
367
|
+
* @returns {string} Requested story URL.
|
|
368
|
+
*/
|
|
369
|
+
const storyUrl = (name, { baseUrl } = {}) =>
|
|
370
|
+
`${baseUrl || resolveStorybookIframe()}?id=${name}`;
|
|
371
|
+
|
|
356
372
|
/**
|
|
357
373
|
* Run pa11y on a single Storybook story by its ID.
|
|
358
374
|
* @param {string} name - Story ID (e.g., "components-button--primary").
|
|
359
375
|
* @param {{baseUrl?: string}} [options={}] - Storybook origin options.
|
|
360
376
|
* @returns {Promise<{ issues: Pa11yIssue[], pageUrl: string }>} Pa11y result.
|
|
361
377
|
*/
|
|
362
|
-
const lintComponent = async (name,
|
|
363
|
-
pa11y(
|
|
378
|
+
const lintComponent = async (name, options = {}) =>
|
|
379
|
+
pa11y(storyUrl(name, options), {
|
|
364
380
|
includeNotices: true,
|
|
365
381
|
includeWarnings: true,
|
|
366
382
|
runners: ['axe'],
|
|
@@ -368,19 +384,82 @@ const lintComponent = async (name, { baseUrl } = {}) =>
|
|
|
368
384
|
});
|
|
369
385
|
|
|
370
386
|
/**
|
|
371
|
-
*
|
|
387
|
+
* @typedef {Object} StoryOutcome
|
|
388
|
+
* @property {string} storyId - Selected Storybook story ID.
|
|
389
|
+
* @property {string} url - Requested story URL, even when navigation fails.
|
|
390
|
+
* @property {'completed'|'failed'} status - Scan execution outcome.
|
|
391
|
+
* @property {object} [report] - Completed Pa11y report.
|
|
392
|
+
* @property {Error} [error] - Contextual execution error with the original cause.
|
|
393
|
+
*/
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Lint every selected story and report all outcomes before rejecting failures.
|
|
397
|
+
*
|
|
398
|
+
* Reportable findings set a nonzero exit status. Execution failures also reject
|
|
399
|
+
* with an AggregateError whose errors preserve story context and original causes.
|
|
372
400
|
* @param {string[]} names - List of Storybook story IDs.
|
|
373
401
|
* @param {{baseUrl?: string}} [options={}] - Storybook origin options.
|
|
374
402
|
* @returns {Promise<void>}
|
|
375
403
|
*/
|
|
376
404
|
const lintReportAndExit = async (names, options = {}) => {
|
|
377
|
-
|
|
378
|
-
|
|
405
|
+
/** @type {StoryOutcome[]} */
|
|
406
|
+
const outcomes = new Array(names.length);
|
|
407
|
+
let nextIndex = 0;
|
|
408
|
+
const worker = async () => {
|
|
409
|
+
while (nextIndex < names.length) {
|
|
410
|
+
const index = nextIndex;
|
|
411
|
+
nextIndex += 1;
|
|
412
|
+
const storyId = names[index];
|
|
413
|
+
const url = storyUrl(storyId, options);
|
|
414
|
+
try {
|
|
415
|
+
const report = await lintComponent(storyId, options);
|
|
416
|
+
outcomes[index] = { storyId, url, status: 'completed', report };
|
|
417
|
+
} catch (cause) {
|
|
418
|
+
const error = new Error(
|
|
419
|
+
`Accessibility check failed for story "${storyId}" (${url}): ${cause?.message || cause}`,
|
|
420
|
+
{ cause },
|
|
421
|
+
);
|
|
422
|
+
Object.assign(error, { storyId, url });
|
|
423
|
+
outcomes[index] = { storyId, url, status: 'failed', error };
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
// Pa11y releases its browsers before settling. Drain every worker before
|
|
428
|
+
// reporting or rejecting so the caller can safely close the Storybook server.
|
|
429
|
+
await Promise.all(
|
|
430
|
+
Array.from({ length: Math.min(concurrency, names.length) }, worker),
|
|
379
431
|
);
|
|
380
|
-
const hasIssues = results.map(logReport).some(Boolean);
|
|
381
432
|
|
|
382
|
-
|
|
383
|
-
|
|
433
|
+
const failures = [];
|
|
434
|
+
let clean = 0;
|
|
435
|
+
let withFindings = 0;
|
|
436
|
+
for (const outcome of outcomes) {
|
|
437
|
+
if (outcome.status === 'failed') {
|
|
438
|
+
failures.push(outcome.error);
|
|
439
|
+
// Use the same output stream as completed reports to retain input order.
|
|
440
|
+
// Logging the original error object keeps its stack and nested causes.
|
|
441
|
+
console.log(
|
|
442
|
+
`Execution failed for story: ${outcome.storyId}\nURL: ${outcome.url}`,
|
|
443
|
+
outcome.error.cause,
|
|
444
|
+
);
|
|
445
|
+
} else if (logReport(outcome.report)) {
|
|
446
|
+
withFindings += 1;
|
|
447
|
+
} else {
|
|
448
|
+
clean += 1;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
console.log(
|
|
452
|
+
`Accessibility summary: ${outcomes.length} attempted, ${clean} clean, ${withFindings} with findings, ${failures.length} failed to execute.`,
|
|
453
|
+
);
|
|
454
|
+
|
|
455
|
+
if ((withFindings || failures.length) && !process.exitCode) {
|
|
456
|
+
process.exitCode = 1;
|
|
457
|
+
}
|
|
458
|
+
if (failures.length) {
|
|
459
|
+
throw new AggregateError(
|
|
460
|
+
failures,
|
|
461
|
+
`Accessibility execution failed for ${failures.length} ${failures.length === 1 ? 'story' : 'stories'}.`,
|
|
462
|
+
);
|
|
384
463
|
}
|
|
385
464
|
};
|
|
386
465
|
|