@d-zero/a11y-check-core 0.2.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/LICENSE +21 -0
- package/README.md +1 -0
- package/dist/clean-results.d.ts +2 -0
- package/dist/clean-results.js +29 -0
- package/dist/color-contrast.d.ts +8 -0
- package/dist/color-contrast.js +40 -0
- package/dist/color-contrast.spec.d.ts +1 -0
- package/dist/color-contrast.spec.js +41 -0
- package/dist/color.d.ts +2 -0
- package/dist/color.js +32 -0
- package/dist/create-scenario.d.ts +2 -0
- package/dist/create-scenario.js +3 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/sc-number-comparator.d.ts +1 -0
- package/dist/sc-number-comparator.js +20 -0
- package/dist/sc-number-comparator.spec.d.ts +1 -0
- package/dist/sc-number-comparator.spec.js +21 -0
- package/dist/scenario-runner.d.ts +5 -0
- package/dist/scenario-runner.js +91 -0
- package/dist/types.d.ts +77 -0
- package/dist/types.js +1 -0
- package/package.json +38 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 D-ZERO Co., Ltd.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# `@d-zero/a11y-check-core`
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { hash } from '@d-zero/shared/hash';
|
|
2
|
+
import { pathComparator } from '@d-zero/shared/sort/path';
|
|
3
|
+
import { scNumberComparator } from './sc-number-comparator.js';
|
|
4
|
+
export function cleanResults(results) {
|
|
5
|
+
const hashMap = new Map();
|
|
6
|
+
for (const result of results) {
|
|
7
|
+
const content = [
|
|
8
|
+
result.url,
|
|
9
|
+
result.component ?? '',
|
|
10
|
+
result.targetNode.value,
|
|
11
|
+
result.targetNode.note ?? '',
|
|
12
|
+
].join('');
|
|
13
|
+
const name = hash(content);
|
|
14
|
+
if (hashMap.has(name)) {
|
|
15
|
+
const existing = hashMap.get(name);
|
|
16
|
+
if (!existing.environment.includes(result.environment)) {
|
|
17
|
+
hashMap.set(name, {
|
|
18
|
+
...existing,
|
|
19
|
+
environment: existing.environment + '\n' + result.environment,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
hashMap.set(name, result);
|
|
25
|
+
}
|
|
26
|
+
return [...hashMap.values()]
|
|
27
|
+
.toSorted((a, b) => scNumberComparator(a.scNumber, b.scNumber))
|
|
28
|
+
.toSorted((a, b) => pathComparator(a.url, b.url));
|
|
29
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ColorContrast, Style } from './types.js';
|
|
2
|
+
export declare enum ColorContrastError {
|
|
3
|
+
DOES_NOT_DETERMINE_FOREGROUND = 0,
|
|
4
|
+
DOES_NOT_DETERMINE_BACKGROUND = 1,
|
|
5
|
+
FOREGROUND_COLOR_HAS_ALPHA = 2,
|
|
6
|
+
BACKGROUND_COLOR_HAS_ALPHA = 3
|
|
7
|
+
}
|
|
8
|
+
export declare function colorContrastCheck(style: Style): ColorContrastError | ColorContrast;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// @ts-ignore
|
|
2
|
+
import ColorContrastChecker from 'color-contrast-checker';
|
|
3
|
+
import { colorFnToHex } from './color.js';
|
|
4
|
+
const ccc = new ColorContrastChecker();
|
|
5
|
+
export var ColorContrastError;
|
|
6
|
+
(function (ColorContrastError) {
|
|
7
|
+
ColorContrastError[ColorContrastError["DOES_NOT_DETERMINE_FOREGROUND"] = 0] = "DOES_NOT_DETERMINE_FOREGROUND";
|
|
8
|
+
ColorContrastError[ColorContrastError["DOES_NOT_DETERMINE_BACKGROUND"] = 1] = "DOES_NOT_DETERMINE_BACKGROUND";
|
|
9
|
+
ColorContrastError[ColorContrastError["FOREGROUND_COLOR_HAS_ALPHA"] = 2] = "FOREGROUND_COLOR_HAS_ALPHA";
|
|
10
|
+
ColorContrastError[ColorContrastError["BACKGROUND_COLOR_HAS_ALPHA"] = 3] = "BACKGROUND_COLOR_HAS_ALPHA";
|
|
11
|
+
})(ColorContrastError || (ColorContrastError = {}));
|
|
12
|
+
export function colorContrastCheck(style) {
|
|
13
|
+
const foreground = colorFnToHex(style.color);
|
|
14
|
+
if (!foreground) {
|
|
15
|
+
return ColorContrastError.DOES_NOT_DETERMINE_FOREGROUND;
|
|
16
|
+
}
|
|
17
|
+
if (foreground.a < 1) {
|
|
18
|
+
return ColorContrastError.FOREGROUND_COLOR_HAS_ALPHA;
|
|
19
|
+
}
|
|
20
|
+
const background = colorFnToHex(style.backgroundColor) ?? colorFnToHex(style.closestBackgroundColor);
|
|
21
|
+
if (!background) {
|
|
22
|
+
return ColorContrastError.DOES_NOT_DETERMINE_BACKGROUND;
|
|
23
|
+
}
|
|
24
|
+
if (background.a < 1) {
|
|
25
|
+
return ColorContrastError.BACKGROUND_COLOR_HAS_ALPHA;
|
|
26
|
+
}
|
|
27
|
+
const fL = ccc.hexToLuminance(foreground.hex);
|
|
28
|
+
const bL = ccc.hexToLuminance(background.hex);
|
|
29
|
+
const ratio = ccc.getContrastRatio(fL, bL);
|
|
30
|
+
const ratioText = `${ratio.toFixed(2).replace(/\.0+$/, '')}:1`;
|
|
31
|
+
const wcag = ccc.verifyContrastRatio(ratio);
|
|
32
|
+
return {
|
|
33
|
+
foreground,
|
|
34
|
+
background,
|
|
35
|
+
ratio,
|
|
36
|
+
ratioText,
|
|
37
|
+
AA: wcag.WCAG_AA,
|
|
38
|
+
AAA: wcag.WCAG_AAA,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { test, expect } from 'vitest';
|
|
2
|
+
import { colorContrastCheck, ColorContrastError } from './color-contrast.js';
|
|
3
|
+
test('#000 vs #FFF', () => {
|
|
4
|
+
expect(colorContrastCheck({
|
|
5
|
+
color: 'rgb(0, 0, 0)',
|
|
6
|
+
backgroundColor: 'rgb(255, 255, 255)',
|
|
7
|
+
backgroundImage: '',
|
|
8
|
+
closestBackgroundColor: null,
|
|
9
|
+
closestBackgroundImage: null,
|
|
10
|
+
})).toStrictEqual({
|
|
11
|
+
foreground: {
|
|
12
|
+
a: 1,
|
|
13
|
+
b: 0,
|
|
14
|
+
g: 0,
|
|
15
|
+
hex: '#000000',
|
|
16
|
+
hexA: '#000000FF',
|
|
17
|
+
r: 0,
|
|
18
|
+
},
|
|
19
|
+
background: {
|
|
20
|
+
a: 1,
|
|
21
|
+
b: 255,
|
|
22
|
+
g: 255,
|
|
23
|
+
hex: '#FFFFFF',
|
|
24
|
+
hexA: '#FFFFFFFF',
|
|
25
|
+
r: 255,
|
|
26
|
+
},
|
|
27
|
+
ratio: 21,
|
|
28
|
+
ratioText: '21:1',
|
|
29
|
+
AA: true,
|
|
30
|
+
AAA: true,
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
test('has alpha channel', () => {
|
|
34
|
+
expect(colorContrastCheck({
|
|
35
|
+
color: 'rgba(0, 0, 0, 0.5)',
|
|
36
|
+
backgroundColor: 'rgb(255, 255, 255)',
|
|
37
|
+
backgroundImage: '',
|
|
38
|
+
closestBackgroundColor: null,
|
|
39
|
+
closestBackgroundImage: null,
|
|
40
|
+
})).toBe(ColorContrastError.FOREGROUND_COLOR_HAS_ALPHA);
|
|
41
|
+
});
|
package/dist/color.d.ts
ADDED
package/dist/color.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export function colorFnToHex(colorFn) {
|
|
2
|
+
if (!colorFn) {
|
|
3
|
+
return null;
|
|
4
|
+
}
|
|
5
|
+
const match = colorFn.match(/rgba?\s*\(\s*(?<r>\d+)\s*,\s*(?<g>\d+)\s*,\s*(?<b>\d+)(?:\s*,\s*(?<a>\d*(?:\.\d+)?))?\)/);
|
|
6
|
+
if (!match) {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
const r = Number.parseInt(match.groups?.r ?? '0');
|
|
10
|
+
const g = Number.parseInt(match.groups?.g ?? '0');
|
|
11
|
+
const b = Number.parseInt(match.groups?.b ?? '0');
|
|
12
|
+
const a = Number.parseFloat(match.groups?.a ?? '1');
|
|
13
|
+
if (a === 0) {
|
|
14
|
+
// Fully transparent
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
const R = r.toString(16).padStart(2, '0').toUpperCase();
|
|
18
|
+
const G = g.toString(16).padStart(2, '0').toUpperCase();
|
|
19
|
+
const B = b.toString(16).padStart(2, '0').toUpperCase();
|
|
20
|
+
const A = Math.round(a * 255)
|
|
21
|
+
.toString(16)
|
|
22
|
+
.padStart(2, '0')
|
|
23
|
+
.toUpperCase();
|
|
24
|
+
return {
|
|
25
|
+
r,
|
|
26
|
+
g,
|
|
27
|
+
b,
|
|
28
|
+
a,
|
|
29
|
+
hex: `#${R}${G}${B}`,
|
|
30
|
+
hexA: `#${R}${G}${B}${A}`,
|
|
31
|
+
};
|
|
32
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { colorContrastCheck, ColorContrastError } from './color-contrast.js';
|
|
2
|
+
export { colorFnToHex } from './color.js';
|
|
3
|
+
export { createScenario } from './create-scenario.js';
|
|
4
|
+
export { scNumberComparator } from './sc-number-comparator.js';
|
|
5
|
+
export { scenarioRunner } from './scenario-runner.js';
|
|
6
|
+
export * from './types.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { colorContrastCheck, ColorContrastError } from './color-contrast.js';
|
|
2
|
+
export { colorFnToHex } from './color.js';
|
|
3
|
+
export { createScenario } from './create-scenario.js';
|
|
4
|
+
export { scNumberComparator } from './sc-number-comparator.js';
|
|
5
|
+
export { scenarioRunner } from './scenario-runner.js';
|
|
6
|
+
export * from './types.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function scNumberComparator(a: string | null, b: string | null): number;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function scNumberComparator(a, b) {
|
|
2
|
+
if (a === b) {
|
|
3
|
+
return 0;
|
|
4
|
+
}
|
|
5
|
+
if (a === null) {
|
|
6
|
+
return 1;
|
|
7
|
+
}
|
|
8
|
+
if (b === null) {
|
|
9
|
+
return -1;
|
|
10
|
+
}
|
|
11
|
+
const _a = a.split('.').map((n) => Number.parseInt(n));
|
|
12
|
+
const _b = b.split('.').map((n) => Number.parseInt(n));
|
|
13
|
+
if (_a[0] !== _b[0]) {
|
|
14
|
+
return (_a[0] ?? 0) - (_b[0] ?? 0);
|
|
15
|
+
}
|
|
16
|
+
if (_a[1] !== _b[1]) {
|
|
17
|
+
return (_a[1] ?? 0) - (_b[1] ?? 0);
|
|
18
|
+
}
|
|
19
|
+
return (_a[2] ?? 0) - (_b[2] ?? 0);
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { test, expect } from 'vitest';
|
|
2
|
+
import { scNumberComparator } from './sc-number-comparator.js';
|
|
3
|
+
test('scNumberComparator', () => {
|
|
4
|
+
expect([
|
|
5
|
+
//
|
|
6
|
+
'1.2.3',
|
|
7
|
+
'1.1.1',
|
|
8
|
+
'1.2.1',
|
|
9
|
+
'1.1.2',
|
|
10
|
+
null,
|
|
11
|
+
'1.1.3',
|
|
12
|
+
].toSorted(scNumberComparator)).toStrictEqual([
|
|
13
|
+
//
|
|
14
|
+
'1.1.1',
|
|
15
|
+
'1.1.2',
|
|
16
|
+
'1.1.3',
|
|
17
|
+
'1.2.1',
|
|
18
|
+
'1.2.3',
|
|
19
|
+
null,
|
|
20
|
+
]);
|
|
21
|
+
});
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { CoreOptions, Result, Scenario, ScenarioRunnerOptions } from './types.js';
|
|
2
|
+
export declare function scenarioRunner<O>(urlList: readonly (string | {
|
|
3
|
+
id: string | null;
|
|
4
|
+
url: string;
|
|
5
|
+
})[], scenarios: readonly Scenario[], options?: O & CoreOptions & ScenarioRunnerOptions): Promise<Result>;
|
|
@@ -0,0 +1,91 @@
|
|
|
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
|
+
export async function scenarioRunner(urlList, scenarios, options) {
|
|
8
|
+
const cache = new Cache('a11y-check/run-puppeteer', options?.cacheDir);
|
|
9
|
+
const hooks = options?.hooks;
|
|
10
|
+
const sizes = {
|
|
11
|
+
desktop: defaultSizes.desktop,
|
|
12
|
+
mobile: defaultSizes.mobile,
|
|
13
|
+
};
|
|
14
|
+
const needAnalysis = [];
|
|
15
|
+
const passed = [];
|
|
16
|
+
const violations = [];
|
|
17
|
+
await deal(urlList.map((url) => {
|
|
18
|
+
if (typeof url === 'string') {
|
|
19
|
+
return { id: null, url };
|
|
20
|
+
}
|
|
21
|
+
return url;
|
|
22
|
+
}), (_, done, total) => {
|
|
23
|
+
return `${c.bold.magenta('🧿 A11y checking%dots%')} ${done}/${total}`;
|
|
24
|
+
}, {
|
|
25
|
+
async beforeOpenPage(_, url, logger) {
|
|
26
|
+
if (options?.cache === false) {
|
|
27
|
+
logger('Clearing cache');
|
|
28
|
+
await cache.clear();
|
|
29
|
+
}
|
|
30
|
+
logger('Restoring cache');
|
|
31
|
+
const cached = await cache.load(url, (key, value) => {
|
|
32
|
+
if (key === 'timestamp') {
|
|
33
|
+
return new Date(Date.parse(value));
|
|
34
|
+
}
|
|
35
|
+
return value;
|
|
36
|
+
});
|
|
37
|
+
if (cached) {
|
|
38
|
+
logger('Hit cache, skipping page scan');
|
|
39
|
+
await delay(600);
|
|
40
|
+
needAnalysis.push(...cached.needAnalysis);
|
|
41
|
+
passed.push(...cached.passed);
|
|
42
|
+
violations.push(...cached.violations);
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
return true;
|
|
46
|
+
},
|
|
47
|
+
async deal(page, _, url, logger) {
|
|
48
|
+
const urlNeedAnalysis = [];
|
|
49
|
+
const urlPassed = [];
|
|
50
|
+
const urlViolations = [];
|
|
51
|
+
for (const [name, size] of Object.entries(sizes)) {
|
|
52
|
+
const sizeLabel = c.bgMagenta(` ${name} `);
|
|
53
|
+
for (const scenario of scenarios) {
|
|
54
|
+
await beforePageScan(page, url, {
|
|
55
|
+
name,
|
|
56
|
+
...size,
|
|
57
|
+
hooks,
|
|
58
|
+
listener: pageScanListener(logger),
|
|
59
|
+
});
|
|
60
|
+
const scenarioResult = await scenario.exec(page, name, (log) => logger(`${sizeLabel} ${log}`));
|
|
61
|
+
urlNeedAnalysis.push(...(scenarioResult.needAnalysis ?? []));
|
|
62
|
+
urlPassed.push(...(scenarioResult.passed ?? []));
|
|
63
|
+
urlViolations.push(...(scenarioResult.violations ?? []));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const urlResults = {
|
|
67
|
+
needAnalysis: urlNeedAnalysis,
|
|
68
|
+
passed: urlPassed,
|
|
69
|
+
violations: urlViolations,
|
|
70
|
+
};
|
|
71
|
+
await cache.store(url, urlResults);
|
|
72
|
+
needAnalysis.push(...urlNeedAnalysis);
|
|
73
|
+
passed.push(...urlPassed);
|
|
74
|
+
violations.push(...urlViolations);
|
|
75
|
+
},
|
|
76
|
+
}, options);
|
|
77
|
+
const cleanedViolations = cleanResults(violations);
|
|
78
|
+
process.stdout.write(`📊 Found ${cleanedViolations.length} violations\n`);
|
|
79
|
+
for (const scenario of scenarios) {
|
|
80
|
+
const targets = needAnalysis.filter((result) => result.scenarioId === scenario.id);
|
|
81
|
+
if (targets.length === 0) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
await scenario.analyze?.(targets, (log) => process.stdout.write(`${log}\n`));
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
needAnalysis: needAnalysis,
|
|
88
|
+
passed: passed,
|
|
89
|
+
violations: cleanedViolations,
|
|
90
|
+
};
|
|
91
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { DealOptions } from '@d-zero/dealer';
|
|
2
|
+
import type { Page } from '@d-zero/puppeteer-page';
|
|
3
|
+
import type { PageHook } from '@d-zero/puppeteer-page-scan';
|
|
4
|
+
export type CoreOptions = {
|
|
5
|
+
readonly screenshot?: boolean;
|
|
6
|
+
readonly cache?: boolean;
|
|
7
|
+
readonly cacheDir?: string;
|
|
8
|
+
};
|
|
9
|
+
export type ScenarioRunnerOptions = DealOptions & {
|
|
10
|
+
readonly locale?: string;
|
|
11
|
+
readonly hooks?: readonly PageHook[];
|
|
12
|
+
};
|
|
13
|
+
export type ScenarioCreator<O> = (options?: O) => Scenario;
|
|
14
|
+
export type Scenario = {
|
|
15
|
+
id: string;
|
|
16
|
+
config?: {};
|
|
17
|
+
exec: ScenarioExecutor;
|
|
18
|
+
analyze?: ScenarioAnalyzer;
|
|
19
|
+
};
|
|
20
|
+
export type ScenarioExecutor = (page: Page, sizeName: string, log: (log: string) => void) => Promise<Partial<Result>>;
|
|
21
|
+
export type ScenarioAnalyzer = (results: NeedAnalysis[], log: (log: string) => void) => Promise<void | Partial<Result>> | void | Partial<Result>;
|
|
22
|
+
export type Result = {
|
|
23
|
+
readonly needAnalysis: readonly NeedAnalysis[];
|
|
24
|
+
readonly passed: readonly Passed[];
|
|
25
|
+
readonly violations: readonly Violation[];
|
|
26
|
+
};
|
|
27
|
+
export type ResultData = {
|
|
28
|
+
readonly id: string;
|
|
29
|
+
readonly url: string;
|
|
30
|
+
readonly tool: string | null;
|
|
31
|
+
readonly timestamp: Date;
|
|
32
|
+
readonly component: string | null;
|
|
33
|
+
readonly environment: string;
|
|
34
|
+
};
|
|
35
|
+
export type Passed = ResultData & {};
|
|
36
|
+
export type NeedAnalysis = ResultData & {
|
|
37
|
+
readonly scenarioId: string;
|
|
38
|
+
readonly subKey?: string;
|
|
39
|
+
readonly data: string;
|
|
40
|
+
};
|
|
41
|
+
export type Violation = ResultData & {
|
|
42
|
+
readonly targetNode: Details;
|
|
43
|
+
readonly asIs: Details;
|
|
44
|
+
readonly toBe: Details;
|
|
45
|
+
readonly explanation: Details;
|
|
46
|
+
readonly wcagVersion: string | null;
|
|
47
|
+
readonly scNumber: string | null;
|
|
48
|
+
readonly level: 'A' | 'AA' | 'AAA' | null;
|
|
49
|
+
readonly screenshot: string | null;
|
|
50
|
+
};
|
|
51
|
+
export type Details = {
|
|
52
|
+
readonly value: string;
|
|
53
|
+
readonly note?: string;
|
|
54
|
+
};
|
|
55
|
+
export type Style = {
|
|
56
|
+
readonly color: string;
|
|
57
|
+
readonly backgroundColor: string;
|
|
58
|
+
readonly backgroundImage: string;
|
|
59
|
+
readonly closestBackgroundColor: string | null;
|
|
60
|
+
readonly closestBackgroundImage: string | null;
|
|
61
|
+
};
|
|
62
|
+
export type Color = {
|
|
63
|
+
readonly r: number;
|
|
64
|
+
readonly g: number;
|
|
65
|
+
readonly b: number;
|
|
66
|
+
readonly a: number;
|
|
67
|
+
readonly hex: string;
|
|
68
|
+
readonly hexA: string;
|
|
69
|
+
};
|
|
70
|
+
export type ColorContrast = {
|
|
71
|
+
readonly foreground: Color;
|
|
72
|
+
readonly background: Color;
|
|
73
|
+
readonly ratio: number;
|
|
74
|
+
readonly ratioText: `${number}:1`;
|
|
75
|
+
readonly AA: boolean;
|
|
76
|
+
readonly AAA: boolean;
|
|
77
|
+
};
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@d-zero/a11y-check-core",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Accessibility Checker (Core Module)",
|
|
5
|
+
"author": "D-ZERO",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"private": false,
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsc",
|
|
23
|
+
"watch": "tsc --watch",
|
|
24
|
+
"clean": "tsc --build --clean"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@d-zero/puppeteer-dealer": "0.2.0",
|
|
28
|
+
"@d-zero/shared": "0.6.0",
|
|
29
|
+
"ansi-colors": "4.1.3",
|
|
30
|
+
"color-contrast-checker": "2.1.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@d-zero/dealer": "1.2.0",
|
|
34
|
+
"@d-zero/puppeteer-page": "0.2.0",
|
|
35
|
+
"@d-zero/puppeteer-page-scan": "2.0.0"
|
|
36
|
+
},
|
|
37
|
+
"gitHead": "1eb1c03400580040119121e11ffb33acd876fe1b"
|
|
38
|
+
}
|