aria-ease 6.7.0 → 6.9.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 +77 -10
- package/bin/AccordionComponentStrategy-4ZEIQ2V6.js +42 -0
- package/bin/ComboboxComponentStrategy-OGRVZXAF.js +64 -0
- package/bin/MenuComponentStrategy-JAMTCSNF.js +81 -0
- package/bin/TabsComponentStrategy-3SQURPMX.js +29 -0
- package/bin/buildContracts-GBOY7UXG.js +437 -0
- package/bin/{chunk-VPBHLMAS.js → chunk-LMSKLN5O.js} +21 -0
- package/bin/chunk-PK5L2SAF.js +17 -0
- package/bin/{chunk-2TOYEY5L.js → chunk-XERMSYEH.js} +12 -3
- package/bin/cli.cjs +991 -128
- package/bin/cli.js +33 -2
- package/bin/{configLoader-XRF6VM4J.js → configLoader-Q6A4JLKW.js} +1 -1
- package/{dist/contractTestRunnerPlaywright-UAOFNS7Z.js → bin/contractTestRunnerPlaywright-ZZNWDUYP.js} +270 -219
- package/bin/{test-WRIJHN6H.js → test-OND56UUL.js} +97 -10
- package/dist/AccordionComponentStrategy-4ZEIQ2V6.js +42 -0
- package/dist/ComboboxComponentStrategy-OGRVZXAF.js +64 -0
- package/dist/MenuComponentStrategy-JAMTCSNF.js +81 -0
- package/dist/TabsComponentStrategy-3SQURPMX.js +29 -0
- package/dist/chunk-PK5L2SAF.js +17 -0
- package/dist/{chunk-2TOYEY5L.js → chunk-XERMSYEH.js} +12 -3
- package/dist/{configLoader-IT4PWCJB.js → configLoader-WTGJAP4Z.js} +21 -0
- package/{bin/contractTestRunnerPlaywright-UAOFNS7Z.js → dist/contractTestRunnerPlaywright-XBWJZMR3.js} +270 -219
- package/dist/index.cjs +800 -96
- package/dist/index.d.cts +136 -1
- package/dist/index.d.ts +136 -1
- package/dist/index.js +421 -16
- package/dist/src/utils/test/AccordionComponentStrategy-WRHZOEN6.js +38 -0
- package/dist/src/utils/test/ComboboxComponentStrategy-5AECQSRN.js +60 -0
- package/dist/src/utils/test/MenuComponentStrategy-VKZQYLBE.js +77 -0
- package/dist/src/utils/test/TabsComponentStrategy-BKG53SEV.js +26 -0
- package/dist/src/utils/test/aria-contracts/accordion/accordion.contract.json +5 -11
- package/dist/src/utils/test/aria-contracts/combobox/combobox.listbox.contract.json +1 -1
- package/dist/src/utils/test/aria-contracts/menu/menu.contract.json +1 -1
- package/dist/src/utils/test/{chunk-2TOYEY5L.js → chunk-XERMSYEH.js} +12 -3
- package/dist/src/utils/test/{configLoader-LD4RV2WQ.js → configLoader-YE2CYGDG.js} +21 -0
- package/dist/src/utils/test/{contractTestRunnerPlaywright-IRJOAEMT.js → contractTestRunnerPlaywright-LC5OAVXB.js} +262 -200
- package/dist/src/utils/test/index.cjs +472 -88
- package/dist/src/utils/test/index.js +97 -12
- package/package.json +7 -2
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
import "./chunk-I2KLQ2HA.js";
|
|
2
|
+
|
|
3
|
+
// src/utils/cli/buildContracts.ts
|
|
4
|
+
import path from "path";
|
|
5
|
+
import fs from "fs-extra";
|
|
6
|
+
import { glob } from "fs/promises";
|
|
7
|
+
import chalk from "chalk";
|
|
8
|
+
|
|
9
|
+
// src/utils/cli/contractValidator.ts
|
|
10
|
+
function validateContractSchema(contract) {
|
|
11
|
+
const errors = [];
|
|
12
|
+
if (!contract || typeof contract !== "object") {
|
|
13
|
+
return {
|
|
14
|
+
valid: false,
|
|
15
|
+
errors: [{ path: "$", message: "Contract must be an object" }]
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
const c = contract;
|
|
19
|
+
if (!c.selectors) {
|
|
20
|
+
errors.push({ path: "$.selectors", message: "selectors is required" });
|
|
21
|
+
} else if (typeof c.selectors !== "object" || c.selectors === null || Array.isArray(c.selectors)) {
|
|
22
|
+
errors.push({ path: "$.selectors", message: "selectors must be an object" });
|
|
23
|
+
} else {
|
|
24
|
+
const selectors = c.selectors;
|
|
25
|
+
Object.entries(selectors).forEach(([key, value]) => {
|
|
26
|
+
if (typeof value !== "string") {
|
|
27
|
+
errors.push({ path: `$.selectors['${key}']`, message: "All selectors must be strings" });
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
if (!Array.isArray(c.static)) {
|
|
32
|
+
errors.push({ path: "$.static", message: "static must be an array" });
|
|
33
|
+
} else {
|
|
34
|
+
c.static.forEach((item, idx) => {
|
|
35
|
+
if (typeof item !== "object" || item === null) {
|
|
36
|
+
errors.push({ path: `$.static[${idx}]`, message: "static item must be an object" });
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const staticItem = item;
|
|
40
|
+
if (!Array.isArray(staticItem.assertions)) {
|
|
41
|
+
errors.push({
|
|
42
|
+
path: `$.static[${idx}].assertions`,
|
|
43
|
+
message: "assertions must be an array"
|
|
44
|
+
});
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
staticItem.assertions.forEach((assertion, assertIdx) => {
|
|
48
|
+
if (typeof assertion !== "object" || assertion === null) {
|
|
49
|
+
errors.push({
|
|
50
|
+
path: `$.static[${idx}].assertions[${assertIdx}]`,
|
|
51
|
+
message: "assertion must be an object"
|
|
52
|
+
});
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const a = assertion;
|
|
56
|
+
if (typeof a.target !== "string") {
|
|
57
|
+
errors.push({
|
|
58
|
+
path: `$.static[${idx}].assertions[${assertIdx}].target`,
|
|
59
|
+
message: "target is required and must be a string"
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
if (typeof a.attribute !== "string") {
|
|
63
|
+
errors.push({
|
|
64
|
+
path: `$.static[${idx}].assertions[${assertIdx}].attribute`,
|
|
65
|
+
message: "attribute is required and must be a string"
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
if (typeof a.failureMessage !== "string") {
|
|
69
|
+
errors.push({
|
|
70
|
+
path: `$.static[${idx}].assertions[${assertIdx}].failureMessage`,
|
|
71
|
+
message: "failureMessage is required and must be a string"
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
if (a.level !== void 0 && !["required", "recommended", "optional"].includes(a.level)) {
|
|
75
|
+
errors.push({
|
|
76
|
+
path: `$.static[${idx}].assertions[${assertIdx}].level`,
|
|
77
|
+
message: "level must be one of: required, recommended, optional"
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
if (!Array.isArray(c.dynamic)) {
|
|
84
|
+
errors.push({ path: "$.dynamic", message: "dynamic must be an array" });
|
|
85
|
+
} else {
|
|
86
|
+
c.dynamic.forEach((item, idx) => {
|
|
87
|
+
if (typeof item !== "object" || item === null) {
|
|
88
|
+
errors.push({ path: `$.dynamic[${idx}]`, message: "dynamic item must be an object" });
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const dynamicItem = item;
|
|
92
|
+
if (typeof dynamicItem.description !== "string") {
|
|
93
|
+
errors.push({
|
|
94
|
+
path: `$.dynamic[${idx}].description`,
|
|
95
|
+
message: "description is required and must be a string"
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
if (!Array.isArray(dynamicItem.action)) {
|
|
99
|
+
errors.push({
|
|
100
|
+
path: `$.dynamic[${idx}].action`,
|
|
101
|
+
message: "action is required and must be an array"
|
|
102
|
+
});
|
|
103
|
+
} else {
|
|
104
|
+
dynamicItem.action.forEach((action, actIdx) => {
|
|
105
|
+
if (typeof action !== "object" || action === null) {
|
|
106
|
+
errors.push({
|
|
107
|
+
path: `$.dynamic[${idx}].action[${actIdx}]`,
|
|
108
|
+
message: "action item must be an object"
|
|
109
|
+
});
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const a = action;
|
|
113
|
+
if (typeof a.type !== "string") {
|
|
114
|
+
errors.push({
|
|
115
|
+
path: `$.dynamic[${idx}].action[${actIdx}].type`,
|
|
116
|
+
message: "type is required and must be a string"
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
if (typeof a.target !== "string") {
|
|
120
|
+
errors.push({
|
|
121
|
+
path: `$.dynamic[${idx}].action[${actIdx}].target`,
|
|
122
|
+
message: "target is required and must be a string"
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
if (!Array.isArray(dynamicItem.assertions)) {
|
|
128
|
+
errors.push({
|
|
129
|
+
path: `$.dynamic[${idx}].assertions`,
|
|
130
|
+
message: "assertions is required and must be an array"
|
|
131
|
+
});
|
|
132
|
+
} else {
|
|
133
|
+
dynamicItem.assertions.forEach((assertion, assertIdx) => {
|
|
134
|
+
if (typeof assertion !== "object" || assertion === null) {
|
|
135
|
+
errors.push({
|
|
136
|
+
path: `$.dynamic[${idx}].assertions[${assertIdx}]`,
|
|
137
|
+
message: "assertion must be an object"
|
|
138
|
+
});
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const a = assertion;
|
|
142
|
+
if (typeof a.target !== "string") {
|
|
143
|
+
errors.push({
|
|
144
|
+
path: `$.dynamic[${idx}].assertions[${assertIdx}].target`,
|
|
145
|
+
message: "target is required and must be a string"
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
if (typeof a.assertion !== "string") {
|
|
149
|
+
errors.push({
|
|
150
|
+
path: `$.dynamic[${idx}].assertions[${assertIdx}].assertion`,
|
|
151
|
+
message: "assertion is required and must be a string"
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
if (a.level !== void 0 && !["required", "recommended", "optional"].includes(a.level)) {
|
|
155
|
+
errors.push({
|
|
156
|
+
path: `$.dynamic[${idx}].assertions[${assertIdx}].level`,
|
|
157
|
+
message: "level must be one of: required, recommended, optional"
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
if (c.relationships !== void 0) {
|
|
165
|
+
if (!Array.isArray(c.relationships)) {
|
|
166
|
+
errors.push({ path: "$.relationships", message: "relationships must be an array" });
|
|
167
|
+
} else {
|
|
168
|
+
c.relationships.forEach((rel, idx) => {
|
|
169
|
+
if (typeof rel !== "object" || rel === null) {
|
|
170
|
+
errors.push({ path: `$.relationships[${idx}]`, message: "relationship must be an object" });
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const r = rel;
|
|
174
|
+
const type = r.type;
|
|
175
|
+
if (!["aria-reference", "contains"].includes(type)) {
|
|
176
|
+
errors.push({
|
|
177
|
+
path: `$.relationships[${idx}].type`,
|
|
178
|
+
message: "type must be one of: aria-reference, contains"
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
if (type === "aria-reference") {
|
|
182
|
+
if (typeof r.from !== "string") {
|
|
183
|
+
errors.push({
|
|
184
|
+
path: `$.relationships[${idx}].from`,
|
|
185
|
+
message: "from is required for aria-reference and must be a string"
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
if (typeof r.attribute !== "string") {
|
|
189
|
+
errors.push({
|
|
190
|
+
path: `$.relationships[${idx}].attribute`,
|
|
191
|
+
message: "attribute is required for aria-reference and must be a string"
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
if (typeof r.to !== "string") {
|
|
195
|
+
errors.push({
|
|
196
|
+
path: `$.relationships[${idx}].to`,
|
|
197
|
+
message: "to is required for aria-reference and must be a string"
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
} else if (type === "contains") {
|
|
201
|
+
if (typeof r.parent !== "string") {
|
|
202
|
+
errors.push({
|
|
203
|
+
path: `$.relationships[${idx}].parent`,
|
|
204
|
+
message: "parent is required for contains and must be a string"
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
if (typeof r.child !== "string") {
|
|
208
|
+
errors.push({
|
|
209
|
+
path: `$.relationships[${idx}].child`,
|
|
210
|
+
message: "child is required for contains and must be a string"
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
valid: errors.length === 0,
|
|
219
|
+
errors
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
function validateRelationshipReferences(contract, selectorKeys) {
|
|
223
|
+
const errors = [];
|
|
224
|
+
if (!contract || typeof contract !== "object") {
|
|
225
|
+
return errors;
|
|
226
|
+
}
|
|
227
|
+
const c = contract;
|
|
228
|
+
const relationships = c.relationships;
|
|
229
|
+
if (!Array.isArray(relationships)) {
|
|
230
|
+
return errors;
|
|
231
|
+
}
|
|
232
|
+
relationships.forEach((rel, idx) => {
|
|
233
|
+
const type = rel.type;
|
|
234
|
+
if (type === "aria-reference") {
|
|
235
|
+
const from = rel.from;
|
|
236
|
+
const to = rel.to;
|
|
237
|
+
if (from && !selectorKeys.has(from)) {
|
|
238
|
+
errors.push({
|
|
239
|
+
path: `$.relationships[${idx}].from`,
|
|
240
|
+
message: `Selector '${from}' not found in selectors`
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
if (to && !selectorKeys.has(to)) {
|
|
244
|
+
errors.push({
|
|
245
|
+
path: `$.relationships[${idx}].to`,
|
|
246
|
+
message: `Selector '${to}' not found in selectors`
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
} else if (type === "contains") {
|
|
250
|
+
const parent = rel.parent;
|
|
251
|
+
const child = rel.child;
|
|
252
|
+
if (parent && !selectorKeys.has(parent)) {
|
|
253
|
+
errors.push({
|
|
254
|
+
path: `$.relationships[${idx}].parent`,
|
|
255
|
+
message: `Selector '${parent}' not found in selectors`
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
if (child && !selectorKeys.has(child)) {
|
|
259
|
+
errors.push({
|
|
260
|
+
path: `$.relationships[${idx}].child`,
|
|
261
|
+
message: `Selector '${child}' not found in selectors`
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
return errors;
|
|
267
|
+
}
|
|
268
|
+
function validateTargetReferences(contract, selectorKeys) {
|
|
269
|
+
const errors = [];
|
|
270
|
+
if (!contract || typeof contract !== "object") {
|
|
271
|
+
return errors;
|
|
272
|
+
}
|
|
273
|
+
const c = contract;
|
|
274
|
+
const staticItems = c.static;
|
|
275
|
+
if (Array.isArray(staticItems)) {
|
|
276
|
+
staticItems.forEach((item, itemIdx) => {
|
|
277
|
+
const assertions = item.assertions;
|
|
278
|
+
if (Array.isArray(assertions)) {
|
|
279
|
+
assertions.forEach((assertion, assertIdx) => {
|
|
280
|
+
const target = assertion.target;
|
|
281
|
+
if (target && !selectorKeys.has(target)) {
|
|
282
|
+
errors.push({
|
|
283
|
+
path: `$.static[${itemIdx}].assertions[${assertIdx}].target`,
|
|
284
|
+
message: `Selector '${target}' not found in selectors`
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
const dynamicItems = c.dynamic;
|
|
292
|
+
if (Array.isArray(dynamicItems)) {
|
|
293
|
+
dynamicItems.forEach((item, itemIdx) => {
|
|
294
|
+
const actions = item.action;
|
|
295
|
+
if (Array.isArray(actions)) {
|
|
296
|
+
actions.forEach((action, actIdx) => {
|
|
297
|
+
const target = action.target;
|
|
298
|
+
if (target && target !== "document" && !selectorKeys.has(target)) {
|
|
299
|
+
errors.push({
|
|
300
|
+
path: `$.dynamic[${itemIdx}].action[${actIdx}].target`,
|
|
301
|
+
message: `Selector '${target}' not found in selectors (or use 'document')`
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
const assertions = item.assertions;
|
|
307
|
+
if (Array.isArray(assertions)) {
|
|
308
|
+
assertions.forEach((assertion, assertIdx) => {
|
|
309
|
+
const target = assertion.target;
|
|
310
|
+
if (target && target !== "relative" && !selectorKeys.has(target)) {
|
|
311
|
+
errors.push({
|
|
312
|
+
path: `$.dynamic[${itemIdx}].assertions[${assertIdx}].target`,
|
|
313
|
+
message: `Selector '${target}' not found in selectors (or use 'relative')`
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
return errors;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// src/utils/cli/buildContracts.ts
|
|
324
|
+
async function buildContracts(cwd, config) {
|
|
325
|
+
const errors = [];
|
|
326
|
+
const built = [];
|
|
327
|
+
if (!config.contracts || config.contracts.length === 0) {
|
|
328
|
+
console.log(chalk.yellow('\u2139\uFE0F No contracts configured. Add "contracts" array to ariaease.config.js'));
|
|
329
|
+
return { success: true, built, errors };
|
|
330
|
+
}
|
|
331
|
+
try {
|
|
332
|
+
console.log(chalk.cyanBright("\n\u{1F3D7}\uFE0F Building contracts...\n"));
|
|
333
|
+
for (const contractSource of config.contracts) {
|
|
334
|
+
const srcPattern = path.resolve(cwd, contractSource.src);
|
|
335
|
+
const outDir = contractSource.out ? path.resolve(cwd, contractSource.out) : void 0;
|
|
336
|
+
console.log(chalk.gray(` Pattern: ${contractSource.src}`));
|
|
337
|
+
if (outDir) {
|
|
338
|
+
console.log(chalk.gray(` Output: ${contractSource.out}
|
|
339
|
+
`));
|
|
340
|
+
} else {
|
|
341
|
+
console.log(chalk.gray(` Output: Same directory as source
|
|
342
|
+
`));
|
|
343
|
+
}
|
|
344
|
+
const contractFiles = [];
|
|
345
|
+
for await (const file of glob(srcPattern, { cwd })) {
|
|
346
|
+
contractFiles.push(file);
|
|
347
|
+
}
|
|
348
|
+
if (contractFiles.length === 0) {
|
|
349
|
+
console.log(chalk.yellow(`\u26A0\uFE0F No contract files found matching pattern: ${contractSource.src}`));
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
if (outDir) {
|
|
353
|
+
await fs.ensureDir(outDir);
|
|
354
|
+
}
|
|
355
|
+
for (const contractFile of contractFiles) {
|
|
356
|
+
try {
|
|
357
|
+
const absolutePath = contractFile.startsWith("/") ? contractFile : path.resolve(cwd, contractFile);
|
|
358
|
+
const module = await import(`file://${absolutePath}`);
|
|
359
|
+
let contract = module.default;
|
|
360
|
+
if (!contract) {
|
|
361
|
+
const namedExports = Object.entries(module).find(
|
|
362
|
+
([, value]) => value && typeof value === "object" && "toJSON" in value
|
|
363
|
+
);
|
|
364
|
+
if (namedExports) {
|
|
365
|
+
contract = namedExports[1];
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
if (!contract || typeof contract.toJSON !== "function") {
|
|
369
|
+
errors.push(`${path.basename(contractFile)}: No contract with toJSON() method found`);
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
const json = contract.toJSON();
|
|
373
|
+
const schemaValidation = validateContractSchema(json);
|
|
374
|
+
if (!schemaValidation.valid) {
|
|
375
|
+
const errorLines = schemaValidation.errors.map((err) => ` ${chalk.red("\u2717")} ${err.path}: ${err.message}`).join("\n");
|
|
376
|
+
const errorMsg = `Schema validation failed:
|
|
377
|
+
${errorLines}`;
|
|
378
|
+
errors.push(`${path.basename(contractFile)}: ${errorMsg}`);
|
|
379
|
+
console.log(chalk.red(`\u274C ${path.basename(contractFile)}`));
|
|
380
|
+
console.log(chalk.red(` ${errorMsg}`));
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
const selectorKeys = /* @__PURE__ */ new Set();
|
|
384
|
+
if (json && typeof json === "object" && "selectors" in json) {
|
|
385
|
+
const selectors = json.selectors;
|
|
386
|
+
Object.keys(selectors).forEach((key) => selectorKeys.add(key));
|
|
387
|
+
}
|
|
388
|
+
const refErrors = [
|
|
389
|
+
...validateRelationshipReferences(json, selectorKeys),
|
|
390
|
+
...validateTargetReferences(json, selectorKeys)
|
|
391
|
+
];
|
|
392
|
+
if (refErrors.length > 0) {
|
|
393
|
+
const errorLines = refErrors.map((err) => ` ${chalk.red("\u2717")} ${err.path}: ${err.message}`).join("\n");
|
|
394
|
+
const errorMsg = `Reference validation failed:
|
|
395
|
+
${errorLines}`;
|
|
396
|
+
errors.push(`${path.basename(contractFile)}: ${errorMsg}`);
|
|
397
|
+
console.log(chalk.red(`\u274C ${path.basename(contractFile)}`));
|
|
398
|
+
console.log(chalk.red(` ${errorMsg}`));
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
const contractName = path.basename(contractFile, path.extname(contractFile));
|
|
402
|
+
const outputFile = outDir ? path.join(outDir, `${contractName}.json`) : path.join(path.dirname(absolutePath), `${contractName}.json`);
|
|
403
|
+
await fs.writeFile(outputFile, JSON.stringify(json, null, 2) + "\n", "utf-8");
|
|
404
|
+
const relativePath = path.relative(cwd, outputFile);
|
|
405
|
+
built.push(relativePath);
|
|
406
|
+
console.log(chalk.green(`\u2705 ${path.basename(contractFile)} \u2192 ${path.basename(outputFile)}`));
|
|
407
|
+
} catch (error) {
|
|
408
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
409
|
+
const filename = path.basename(contractFile);
|
|
410
|
+
errors.push(`${filename}: ${errorMsg}`);
|
|
411
|
+
console.log(chalk.red(`\u274C ${filename}`));
|
|
412
|
+
console.log(chalk.red(` Error: ${errorMsg}`));
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
console.log("");
|
|
417
|
+
if (errors.length === 0) {
|
|
418
|
+
console.log(chalk.green(`\u2705 Built ${built.length} contract${built.length !== 1 ? "s" : ""} successfully
|
|
419
|
+
`));
|
|
420
|
+
return { success: true, built, errors };
|
|
421
|
+
} else {
|
|
422
|
+
console.log(chalk.yellow(`\u26A0\uFE0F Built ${built.length} contracts with ${errors.length} error${errors.length !== 1 ? "s" : ""}
|
|
423
|
+
`));
|
|
424
|
+
return { success: false, built, errors };
|
|
425
|
+
}
|
|
426
|
+
} catch (error) {
|
|
427
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
428
|
+
const msg = `Failed to build contracts: ${errorMsg}`;
|
|
429
|
+
errors.push(msg);
|
|
430
|
+
console.log(chalk.red(`\u274C ${msg}
|
|
431
|
+
`));
|
|
432
|
+
return { success: false, built, errors };
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
export {
|
|
436
|
+
buildContracts
|
|
437
|
+
};
|
|
@@ -54,6 +54,9 @@ function validateConfig(config) {
|
|
|
54
54
|
if (comp.path !== void 0 && typeof comp.path !== "string") {
|
|
55
55
|
errors.push(`test.components[${idx}].path must be a string when provided`);
|
|
56
56
|
}
|
|
57
|
+
if (comp.strategyPath !== void 0 && typeof comp.strategyPath !== "string") {
|
|
58
|
+
errors.push(`test.components[${idx}].strategyPath must be a string when provided`);
|
|
59
|
+
}
|
|
57
60
|
if (comp.strictness !== void 0 && !["minimal", "balanced", "strict", "paranoid"].includes(comp.strictness)) {
|
|
58
61
|
errors.push(`test.components[${idx}].strictness must be one of: minimal, balanced, strict, paranoid`);
|
|
59
62
|
}
|
|
@@ -68,6 +71,24 @@ function validateConfig(config) {
|
|
|
68
71
|
}
|
|
69
72
|
}
|
|
70
73
|
}
|
|
74
|
+
if (cfg.contracts !== void 0) {
|
|
75
|
+
if (!Array.isArray(cfg.contracts)) {
|
|
76
|
+
errors.push("contracts must be an array");
|
|
77
|
+
} else {
|
|
78
|
+
cfg.contracts.forEach((contract, idx) => {
|
|
79
|
+
if (typeof contract !== "object" || contract === null) {
|
|
80
|
+
errors.push(`contracts[${idx}] must be an object`);
|
|
81
|
+
} else {
|
|
82
|
+
if (typeof contract.src !== "string") {
|
|
83
|
+
errors.push(`contracts[${idx}].src is required and must be a string`);
|
|
84
|
+
}
|
|
85
|
+
if (contract.out !== void 0 && typeof contract.out !== "string") {
|
|
86
|
+
errors.push(`contracts[${idx}].out must be a string`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
71
92
|
return { valid: errors.length === 0, errors };
|
|
72
93
|
}
|
|
73
94
|
async function loadConfigFile(filePath) {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__export,
|
|
3
|
+
__reExport
|
|
4
|
+
} from "./chunk-I2KLQ2HA.js";
|
|
5
|
+
|
|
6
|
+
// node_modules/@playwright/test/index.mjs
|
|
7
|
+
var test_exports = {};
|
|
8
|
+
__export(test_exports, {
|
|
9
|
+
default: () => default2
|
|
10
|
+
});
|
|
11
|
+
__reExport(test_exports, test_star);
|
|
12
|
+
import * as test_star from "playwright/test";
|
|
13
|
+
import { default as default2 } from "playwright/test";
|
|
14
|
+
|
|
15
|
+
export {
|
|
16
|
+
test_exports
|
|
17
|
+
};
|
|
@@ -30,11 +30,13 @@ var ContractReporter = class {
|
|
|
30
30
|
skipped = 0;
|
|
31
31
|
warnings = 0;
|
|
32
32
|
isPlaywright = false;
|
|
33
|
+
isCustomContract = false;
|
|
33
34
|
apgUrl = "https://www.w3.org/WAI/ARIA/apg/";
|
|
34
35
|
hasPrintedStaticSection = false;
|
|
35
36
|
hasPrintedDynamicSection = false;
|
|
36
|
-
constructor(isPlaywright = false) {
|
|
37
|
+
constructor(isPlaywright = false, isCustomContract = false) {
|
|
37
38
|
this.isPlaywright = isPlaywright;
|
|
39
|
+
this.isCustomContract = isCustomContract;
|
|
38
40
|
}
|
|
39
41
|
log(message) {
|
|
40
42
|
process.stderr.write(message + "\n");
|
|
@@ -195,6 +197,13 @@ ${"\u2500".repeat(60)}`);
|
|
|
195
197
|
const totalPasses = this.staticPasses + dynamicPasses;
|
|
196
198
|
const totalFailures = this.staticFailures + dynamicFailures;
|
|
197
199
|
const totalRun = totalPasses + totalFailures + this.warnings;
|
|
200
|
+
const getComponentMessage = () => {
|
|
201
|
+
const componentDisplayName = `${this.componentName.charAt(0).toUpperCase()}${this.componentName.slice(1)}`;
|
|
202
|
+
if (this.isCustomContract) {
|
|
203
|
+
return `${componentDisplayName} component validates against your custom accessibility policy \u2713`;
|
|
204
|
+
}
|
|
205
|
+
return `${componentDisplayName} component meets Aria-Ease baseline WAI-ARIA expectations \u2713`;
|
|
206
|
+
};
|
|
198
207
|
if (failures.length > 0) {
|
|
199
208
|
this.reportFailures(failures);
|
|
200
209
|
}
|
|
@@ -206,7 +215,7 @@ ${"\u2550".repeat(60)}`);
|
|
|
206
215
|
`);
|
|
207
216
|
if (totalFailures === 0 && this.skipped === 0 && this.warnings === 0) {
|
|
208
217
|
this.log(`\u2705 All ${totalRun} tests passed!`);
|
|
209
|
-
this.log(` ${
|
|
218
|
+
this.log(` ${getComponentMessage()}`);
|
|
210
219
|
} else if (totalFailures === 0) {
|
|
211
220
|
this.log(`\u2705 ${totalPasses}/${totalRun} tests passed`);
|
|
212
221
|
if (this.skipped > 0) {
|
|
@@ -215,7 +224,7 @@ ${"\u2550".repeat(60)}`);
|
|
|
215
224
|
if (this.warnings > 0) {
|
|
216
225
|
this.log(`\u26A0\uFE0F ${this.warnings} warning${this.warnings > 1 ? "s" : ""}`);
|
|
217
226
|
}
|
|
218
|
-
this.log(` ${
|
|
227
|
+
this.log(` ${getComponentMessage()}`);
|
|
219
228
|
} else {
|
|
220
229
|
this.log(`\u274C ${totalFailures} test${totalFailures > 1 ? "s" : ""} failed`);
|
|
221
230
|
this.log(`\u2705 ${totalPasses} test${totalPasses > 1 ? "s" : ""} passed`);
|