@d-zero/a11y-check-core 0.3.0 → 0.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/dist/import-scenarios.d.ts +6 -0
- package/dist/import-scenarios.js +12 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/scenario-child-process.d.ts +5 -0
- package/dist/scenario-child-process.js +64 -0
- package/dist/{scenario-runner.d.ts → scenario-main-process.d.ts} +2 -1
- package/dist/scenario-main-process.js +51 -0
- package/dist/types.d.ts +6 -4
- package/package.json +8 -8
- package/dist/scenario-runner.js +0 -97
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* @param scenarios
|
|
4
|
+
*/
|
|
5
|
+
export async function importScenarios(scenarios) {
|
|
6
|
+
return await Promise.all(scenarios.map(async (scenario) => {
|
|
7
|
+
const mod = await import(scenario.modulePath);
|
|
8
|
+
const creator = mod.default;
|
|
9
|
+
const optionsValue = JSON.parse(scenario.moduleParams);
|
|
10
|
+
return creator(optionsValue);
|
|
11
|
+
}));
|
|
12
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,5 +2,6 @@ export { colorContrastCheck, ColorContrastError } from './color-contrast.js';
|
|
|
2
2
|
export { colorFnToHex } from './color.js';
|
|
3
3
|
export { createScenario } from './create-scenario.js';
|
|
4
4
|
export { scNumberComparator } from './sc-number-comparator.js';
|
|
5
|
-
export { scenarioRunner } from './scenario-
|
|
5
|
+
export { scenarioRunner } from './scenario-main-process.js';
|
|
6
|
+
export { importScenarios } from './import-scenarios.js';
|
|
6
7
|
export * from './types.js';
|
package/dist/index.js
CHANGED
|
@@ -2,5 +2,6 @@ export { colorContrastCheck, ColorContrastError } from './color-contrast.js';
|
|
|
2
2
|
export { colorFnToHex } from './color.js';
|
|
3
3
|
export { createScenario } from './create-scenario.js';
|
|
4
4
|
export { scNumberComparator } from './sc-number-comparator.js';
|
|
5
|
-
export { scenarioRunner } from './scenario-
|
|
5
|
+
export { scenarioRunner } from './scenario-main-process.js';
|
|
6
|
+
export { importScenarios } from './import-scenarios.js';
|
|
6
7
|
export * from './types.js';
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { createChildProcess } from '@d-zero/puppeteer-dealer';
|
|
2
|
+
import { beforePageScan, defaultSizes, pageScanListener, } from '@d-zero/puppeteer-page-scan';
|
|
3
|
+
import { Cache } from '@d-zero/shared/cache';
|
|
4
|
+
import c from 'ansi-colors';
|
|
5
|
+
import { importScenarios } from '@d-zero/a11y-check-core';
|
|
6
|
+
createChildProcess(async (param) => {
|
|
7
|
+
const { cacheDir } = param;
|
|
8
|
+
const cache = new Cache('a11y-check/run-puppeteer', cacheDir);
|
|
9
|
+
const sizes = {
|
|
10
|
+
desktop: defaultSizes.desktop,
|
|
11
|
+
mobile: defaultSizes.mobile,
|
|
12
|
+
};
|
|
13
|
+
const scenarios = await importScenarios(param.scenarios);
|
|
14
|
+
return {
|
|
15
|
+
// async beforeOpenPage(_, url, logger) {
|
|
16
|
+
// if (options?.cache === false) {
|
|
17
|
+
// logger('Clearing cache');
|
|
18
|
+
// await cache.clear();
|
|
19
|
+
// }
|
|
20
|
+
// logger('Restoring cache');
|
|
21
|
+
// const cached = await cache.load(url, (key, value) => {
|
|
22
|
+
// if (key === 'timestamp') {
|
|
23
|
+
// return new Date(Date.parse(value));
|
|
24
|
+
// }
|
|
25
|
+
// return value;
|
|
26
|
+
// });
|
|
27
|
+
// if (cached) {
|
|
28
|
+
// logger('Hit cache, skipping page scan');
|
|
29
|
+
// await delay(600);
|
|
30
|
+
// needAnalysis.push(...cached.needAnalysis);
|
|
31
|
+
// passed.push(...cached.passed);
|
|
32
|
+
// violations.push(...cached.violations);
|
|
33
|
+
// return false;
|
|
34
|
+
// }
|
|
35
|
+
// return true;
|
|
36
|
+
// },
|
|
37
|
+
async eachPage({ page, url }, logger) {
|
|
38
|
+
const urlNeedAnalysis = [];
|
|
39
|
+
const urlPassed = [];
|
|
40
|
+
const urlViolations = [];
|
|
41
|
+
for (const [name, size] of Object.entries(sizes)) {
|
|
42
|
+
const sizeLabel = c.bgMagenta(` ${name} `);
|
|
43
|
+
for (const scenario of scenarios) {
|
|
44
|
+
await beforePageScan(page, url, {
|
|
45
|
+
name,
|
|
46
|
+
...size,
|
|
47
|
+
listener: pageScanListener(logger),
|
|
48
|
+
});
|
|
49
|
+
const scenarioResult = await scenario.exec(page, name, (log) => logger(`${sizeLabel} ${log}`));
|
|
50
|
+
urlNeedAnalysis.push(...(scenarioResult.needAnalysis ?? []));
|
|
51
|
+
urlPassed.push(...(scenarioResult.passed ?? []));
|
|
52
|
+
urlViolations.push(...(scenarioResult.violations ?? []));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const urlResults = {
|
|
56
|
+
needAnalysis: urlNeedAnalysis,
|
|
57
|
+
passed: urlPassed,
|
|
58
|
+
violations: urlViolations,
|
|
59
|
+
};
|
|
60
|
+
await cache.store(url, urlResults);
|
|
61
|
+
return urlResults;
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CoreOptions, Result, Scenario, ScenarioRunnerOptions } from './types.js';
|
|
2
|
+
import type { DealOptions } from '@d-zero/dealer';
|
|
2
3
|
/**
|
|
3
4
|
*
|
|
4
5
|
* @param urlList
|
|
@@ -8,4 +9,4 @@ import type { CoreOptions, Result, Scenario, ScenarioRunnerOptions } from './typ
|
|
|
8
9
|
export declare function scenarioRunner<O>(urlList: readonly (string | {
|
|
9
10
|
id: string | null;
|
|
10
11
|
url: string;
|
|
11
|
-
})[], scenarios: readonly Scenario[], options?: O & CoreOptions & ScenarioRunnerOptions): Promise<Result>;
|
|
12
|
+
})[], scenarios: readonly Scenario[], options?: O & CoreOptions & ScenarioRunnerOptions & DealOptions): Promise<Result>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { createProcess, deal } from '@d-zero/puppeteer-dealer';
|
|
3
|
+
import c from 'ansi-colors';
|
|
4
|
+
import { cleanResults } from './clean-results.js';
|
|
5
|
+
import { importScenarios } from '@d-zero/a11y-check-core';
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
* @param urlList
|
|
9
|
+
* @param scenarios
|
|
10
|
+
* @param options
|
|
11
|
+
*/
|
|
12
|
+
export async function scenarioRunner(urlList, scenarios, options) {
|
|
13
|
+
const needAnalysis = [];
|
|
14
|
+
const passed = [];
|
|
15
|
+
const violations = [];
|
|
16
|
+
await deal(urlList.map((url) => {
|
|
17
|
+
if (typeof url === 'string') {
|
|
18
|
+
return { id: null, url };
|
|
19
|
+
}
|
|
20
|
+
return url;
|
|
21
|
+
}), (_, done, total) => {
|
|
22
|
+
return `${c.bold.magenta('🧿 A11y checking%dots%')} ${done}/${total}`;
|
|
23
|
+
}, () => {
|
|
24
|
+
return createProcess(path.resolve(import.meta.dirname, 'scenario-child-process.js'), {
|
|
25
|
+
scenarios,
|
|
26
|
+
cacheDir: options?.cacheDir ?? '.a11y-check-core',
|
|
27
|
+
}, options);
|
|
28
|
+
}, {
|
|
29
|
+
...options,
|
|
30
|
+
each(result) {
|
|
31
|
+
needAnalysis.push(...result.needAnalysis);
|
|
32
|
+
passed.push(...result.passed);
|
|
33
|
+
violations.push(...result.violations);
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
const cleanedViolations = cleanResults(violations);
|
|
37
|
+
process.stdout.write(`📊 Found ${cleanedViolations.length} violations\n`);
|
|
38
|
+
const scenarioModules = await importScenarios(scenarios);
|
|
39
|
+
for (const scenario of scenarioModules) {
|
|
40
|
+
const targets = needAnalysis.filter((result) => result.scenarioId === scenario.id);
|
|
41
|
+
if (targets.length === 0) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
await scenario.analyze?.(targets, (log) => process.stdout.write(`${log}\n`));
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
needAnalysis: needAnalysis,
|
|
48
|
+
passed: passed,
|
|
49
|
+
violations: cleanedViolations,
|
|
50
|
+
};
|
|
51
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DealOptions } from '@d-zero/dealer';
|
|
2
|
-
import type { Page } from '@d-zero/puppeteer-page';
|
|
3
2
|
import type { PageHook } from '@d-zero/puppeteer-page-scan';
|
|
3
|
+
import type { Page } from 'puppeteer';
|
|
4
4
|
export type CoreOptions = {
|
|
5
5
|
readonly screenshot?: boolean;
|
|
6
6
|
readonly cache?: boolean;
|
|
@@ -12,9 +12,11 @@ export type ScenarioRunnerOptions = DealOptions & {
|
|
|
12
12
|
};
|
|
13
13
|
export type ScenarioCreator<O> = (options?: O) => Scenario;
|
|
14
14
|
export type Scenario = {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
readonly modulePath: string;
|
|
16
|
+
readonly moduleParams: string;
|
|
17
|
+
readonly id: string;
|
|
18
|
+
readonly exec: ScenarioExecutor;
|
|
19
|
+
readonly analyze?: ScenarioAnalyzer;
|
|
18
20
|
};
|
|
19
21
|
export type ScenarioExecutor = (page: Page, sizeName: string, log: (log: string) => void) => Promise<Partial<Result>>;
|
|
20
22
|
export type ScenarioAnalyzer = (results: NeedAnalysis[], log: (log: string) => void) => Promise<void | Partial<Result>> | void | Partial<Result>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@d-zero/a11y-check-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Accessibility Checker (Core Module)",
|
|
5
5
|
"author": "D-ZERO",
|
|
6
6
|
"license": "MIT",
|
|
@@ -24,15 +24,15 @@
|
|
|
24
24
|
"clean": "tsc --build --clean"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@d-zero/puppeteer-dealer": "0.
|
|
28
|
-
"@d-zero/shared": "0.
|
|
27
|
+
"@d-zero/puppeteer-dealer": "0.5.0",
|
|
28
|
+
"@d-zero/shared": "0.9.0",
|
|
29
29
|
"ansi-colors": "4.1.3",
|
|
30
|
-
"color-contrast-checker": "2.1.0"
|
|
30
|
+
"color-contrast-checker": "2.1.0",
|
|
31
|
+
"puppeteer": "24.10.1"
|
|
31
32
|
},
|
|
32
33
|
"devDependencies": {
|
|
33
|
-
"@d-zero/dealer": "1.3.
|
|
34
|
-
"@d-zero/puppeteer-page": "0.
|
|
35
|
-
"@d-zero/puppeteer-page-scan": "3.0.0"
|
|
34
|
+
"@d-zero/dealer": "1.3.1",
|
|
35
|
+
"@d-zero/puppeteer-page-scan": "4.0.1"
|
|
36
36
|
},
|
|
37
|
-
"gitHead": "
|
|
37
|
+
"gitHead": "04c6969564182c36ee38ef41e78130936dfa4863"
|
|
38
38
|
}
|
package/dist/scenario-runner.js
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import { deal } from '@d-zero/puppeteer-dealer';
|
|
2
|
-
import { beforePageScan, defaultSizes, pageScanListener, } from '@d-zero/puppeteer-page-scan';
|
|
3
|
-
import { Cache } from '@d-zero/shared/cache';
|
|
4
|
-
import { delay } from '@d-zero/shared/delay';
|
|
5
|
-
import c from 'ansi-colors';
|
|
6
|
-
import { cleanResults } from './clean-results.js';
|
|
7
|
-
/**
|
|
8
|
-
*
|
|
9
|
-
* @param urlList
|
|
10
|
-
* @param scenarios
|
|
11
|
-
* @param options
|
|
12
|
-
*/
|
|
13
|
-
export async function scenarioRunner(urlList, scenarios, options) {
|
|
14
|
-
const cache = new Cache('a11y-check/run-puppeteer', options?.cacheDir);
|
|
15
|
-
const hooks = options?.hooks;
|
|
16
|
-
const sizes = {
|
|
17
|
-
desktop: defaultSizes.desktop,
|
|
18
|
-
mobile: defaultSizes.mobile,
|
|
19
|
-
};
|
|
20
|
-
const needAnalysis = [];
|
|
21
|
-
const passed = [];
|
|
22
|
-
const violations = [];
|
|
23
|
-
await deal(urlList.map((url) => {
|
|
24
|
-
if (typeof url === 'string') {
|
|
25
|
-
return { id: null, url };
|
|
26
|
-
}
|
|
27
|
-
return url;
|
|
28
|
-
}), (_, done, total) => {
|
|
29
|
-
return `${c.bold.magenta('🧿 A11y checking%dots%')} ${done}/${total}`;
|
|
30
|
-
}, {
|
|
31
|
-
async beforeOpenPage(_, url, logger) {
|
|
32
|
-
if (options?.cache === false) {
|
|
33
|
-
logger('Clearing cache');
|
|
34
|
-
await cache.clear();
|
|
35
|
-
}
|
|
36
|
-
logger('Restoring cache');
|
|
37
|
-
const cached = await cache.load(url, (key, value) => {
|
|
38
|
-
if (key === 'timestamp') {
|
|
39
|
-
return new Date(Date.parse(value));
|
|
40
|
-
}
|
|
41
|
-
return value;
|
|
42
|
-
});
|
|
43
|
-
if (cached) {
|
|
44
|
-
logger('Hit cache, skipping page scan');
|
|
45
|
-
await delay(600);
|
|
46
|
-
needAnalysis.push(...cached.needAnalysis);
|
|
47
|
-
passed.push(...cached.passed);
|
|
48
|
-
violations.push(...cached.violations);
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
return true;
|
|
52
|
-
},
|
|
53
|
-
async deal(page, _, url, logger) {
|
|
54
|
-
const urlNeedAnalysis = [];
|
|
55
|
-
const urlPassed = [];
|
|
56
|
-
const urlViolations = [];
|
|
57
|
-
for (const [name, size] of Object.entries(sizes)) {
|
|
58
|
-
const sizeLabel = c.bgMagenta(` ${name} `);
|
|
59
|
-
for (const scenario of scenarios) {
|
|
60
|
-
await beforePageScan(page, url, {
|
|
61
|
-
name,
|
|
62
|
-
...size,
|
|
63
|
-
hooks,
|
|
64
|
-
listener: pageScanListener(logger),
|
|
65
|
-
});
|
|
66
|
-
const scenarioResult = await scenario.exec(page, name, (log) => logger(`${sizeLabel} ${log}`));
|
|
67
|
-
urlNeedAnalysis.push(...(scenarioResult.needAnalysis ?? []));
|
|
68
|
-
urlPassed.push(...(scenarioResult.passed ?? []));
|
|
69
|
-
urlViolations.push(...(scenarioResult.violations ?? []));
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
const urlResults = {
|
|
73
|
-
needAnalysis: urlNeedAnalysis,
|
|
74
|
-
passed: urlPassed,
|
|
75
|
-
violations: urlViolations,
|
|
76
|
-
};
|
|
77
|
-
await cache.store(url, urlResults);
|
|
78
|
-
needAnalysis.push(...urlNeedAnalysis);
|
|
79
|
-
passed.push(...urlPassed);
|
|
80
|
-
violations.push(...urlViolations);
|
|
81
|
-
},
|
|
82
|
-
}, options);
|
|
83
|
-
const cleanedViolations = cleanResults(violations);
|
|
84
|
-
process.stdout.write(`📊 Found ${cleanedViolations.length} violations\n`);
|
|
85
|
-
for (const scenario of scenarios) {
|
|
86
|
-
const targets = needAnalysis.filter((result) => result.scenarioId === scenario.id);
|
|
87
|
-
if (targets.length === 0) {
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
await scenario.analyze?.(targets, (log) => process.stdout.write(`${log}\n`));
|
|
91
|
-
}
|
|
92
|
-
return {
|
|
93
|
-
needAnalysis: needAnalysis,
|
|
94
|
-
passed: passed,
|
|
95
|
-
violations: cleanedViolations,
|
|
96
|
-
};
|
|
97
|
-
}
|