aria-ease 6.14.0 → 7.0.1

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.
Files changed (94) hide show
  1. package/README.md +1 -1
  2. package/dist/AccordionComponentStrategy-2SWMNUR6.js +1 -0
  3. package/dist/ComboboxComponentStrategy-YSYLR2U5.js +5 -0
  4. package/dist/MenuComponentStrategy-C22BZEBH.js +5 -0
  5. package/dist/RelativeTargetResolver-T4P25J2M.js +1 -0
  6. package/dist/TabsComponentStrategy-ADEEFJXM.js +1 -0
  7. package/dist/audit-WBKVW7H6.js +9 -0
  8. package/dist/badgeHelper-IB5RTMAG.js +11 -0
  9. package/dist/badgeHelper-JSROP5ML.js +1 -0
  10. package/dist/buildContracts-T4XQZBDU.js +13 -0
  11. package/dist/chunk-52I3INNG.js +11 -0
  12. package/dist/chunk-APUMBDOT.js +1 -0
  13. package/dist/chunk-BHNO4ZI3.js +1 -0
  14. package/dist/chunk-CNU4N4AY.js +1 -0
  15. package/dist/chunk-SM6ZKEDR.js +1 -0
  16. package/dist/chunk-ZNQ5BXVJ.js +1 -0
  17. package/dist/cli.cjs +132 -3560
  18. package/dist/cli.js +19 -161
  19. package/dist/configLoader-ZEJVXLX7.js +1 -0
  20. package/dist/configLoader-ZXTSCIP6.js +1 -0
  21. package/dist/contractTestRunnerPlaywright-FOCQTM4L.js +46 -0
  22. package/dist/contractTestRunnerPlaywright-QPU6HZXG.js +46 -0
  23. package/dist/formatters-H3CPDLG5.js +87 -0
  24. package/dist/index.cjs +64 -5103
  25. package/dist/index.d.cts +4 -6
  26. package/dist/index.d.ts +4 -6
  27. package/dist/index.js +17 -2703
  28. package/dist/src/accordion/index.cjs +1 -183
  29. package/dist/src/accordion/index.js +1 -181
  30. package/dist/src/block/index.cjs +1 -124
  31. package/dist/src/block/index.js +1 -122
  32. package/dist/src/checkbox/index.cjs +1 -109
  33. package/dist/src/checkbox/index.js +1 -107
  34. package/dist/src/combobox/index.cjs +1 -265
  35. package/dist/src/combobox/index.js +1 -263
  36. package/dist/src/menu/index.cjs +1 -339
  37. package/dist/src/menu/index.js +1 -337
  38. package/dist/src/radio/index.cjs +1 -117
  39. package/dist/src/radio/index.js +1 -115
  40. package/dist/src/tabs/index.cjs +1 -265
  41. package/dist/src/tabs/index.js +1 -263
  42. package/dist/src/toggle/index.cjs +1 -119
  43. package/dist/src/toggle/index.js +1 -117
  44. package/dist/src/utils/test/AccordionComponentStrategy-X2GSQ5KT.js +1 -0
  45. package/dist/src/utils/test/ComboboxComponentStrategy-SICWLI27.js +5 -0
  46. package/dist/src/utils/test/MenuComponentStrategy-R4VPAHDE.js +5 -0
  47. package/dist/src/utils/test/RelativeTargetResolver-UQQMZHI6.js +1 -0
  48. package/dist/src/utils/test/TabsComponentStrategy-L2PYNEW6.js +1 -0
  49. package/dist/src/utils/test/badgeHelper-ER5ZOHWF.js +11 -0
  50. package/dist/src/utils/test/chunk-APUMBDOT.js +1 -0
  51. package/dist/src/utils/test/chunk-BHNO4ZI3.js +1 -0
  52. package/dist/src/utils/test/configLoader-NCYRL2O6.js +1 -0
  53. package/dist/src/utils/test/contractTestRunnerPlaywright-YZCMF64Q.js +46 -0
  54. package/dist/src/utils/test/dsl/index.cjs +1 -838
  55. package/dist/src/utils/test/dsl/index.d.cts +2 -4
  56. package/dist/src/utils/test/dsl/index.d.ts +2 -4
  57. package/dist/src/utils/test/dsl/index.js +1 -836
  58. package/dist/src/utils/test/index.cjs +64 -2672
  59. package/dist/src/utils/test/index.d.cts +2 -2
  60. package/dist/src/utils/test/index.d.ts +2 -2
  61. package/dist/src/utils/test/index.js +16 -340
  62. package/dist/test-VXSCSKV5.js +19 -0
  63. package/package.json +8 -10
  64. package/dist/AccordionComponentStrategy-4ZEIQ2V6.js +0 -42
  65. package/dist/ComboboxComponentStrategy-DU342VMB.js +0 -64
  66. package/dist/MenuComponentStrategy-VYCC2XOM.js +0 -81
  67. package/dist/RelativeTargetResolver-DJAITO6D.js +0 -7
  68. package/dist/TabsComponentStrategy-3SQURPMX.js +0 -29
  69. package/dist/audit-JYEPKLHR.js +0 -63
  70. package/dist/badgeHelper-JOWO6RQG.js +0 -15
  71. package/dist/badgeHelper-RDOMCC6E.js +0 -108
  72. package/dist/buildContracts-VIV6GM56.js +0 -437
  73. package/dist/chunk-4DU5Z5BR.js +0 -340
  74. package/dist/chunk-GJGUY643.js +0 -182
  75. package/dist/chunk-GLT43UVH.js +0 -43
  76. package/dist/chunk-I2KLQ2HA.js +0 -22
  77. package/dist/chunk-JJEPLK7L.js +0 -107
  78. package/dist/chunk-PK5L2SAF.js +0 -17
  79. package/dist/configLoader-Q7N5XV4P.js +0 -183
  80. package/dist/configLoader-REHK3S3Q.js +0 -7
  81. package/dist/contractTestRunnerPlaywright-B2HLZKKK.js +0 -1394
  82. package/dist/contractTestRunnerPlaywright-RWK52C7S.js +0 -1394
  83. package/dist/formatters-32KQIIYS.js +0 -183
  84. package/dist/src/utils/test/AccordionComponentStrategy-WRHZOEN6.js +0 -38
  85. package/dist/src/utils/test/ComboboxComponentStrategy-XKQ72RFD.js +0 -60
  86. package/dist/src/utils/test/MenuComponentStrategy-6XWU5KLW.js +0 -77
  87. package/dist/src/utils/test/RelativeTargetResolver-G2XDN2VV.js +0 -1
  88. package/dist/src/utils/test/TabsComponentStrategy-BKG53SEV.js +0 -26
  89. package/dist/src/utils/test/badgeHelper-HZKGOPB4.js +0 -102
  90. package/dist/src/utils/test/chunk-4DU5Z5BR.js +0 -332
  91. package/dist/src/utils/test/chunk-GLT43UVH.js +0 -41
  92. package/dist/src/utils/test/configLoader-NA7IBCS3.js +0 -181
  93. package/dist/src/utils/test/contractTestRunnerPlaywright-5FIGA5G4.js +0 -1372
  94. package/dist/test-WDBS5JWO.js +0 -358
@@ -1,7 +0,0 @@
1
- import {
2
- RelativeTargetResolver
3
- } from "./chunk-GLT43UVH.js";
4
- import "./chunk-I2KLQ2HA.js";
5
- export {
6
- RelativeTargetResolver
7
- };
@@ -1,29 +0,0 @@
1
- import "./chunk-I2KLQ2HA.js";
2
-
3
- // src/utils/test/src/component-strategies/TabsComponentStrategy.ts
4
- var TabsComponentStrategy = class {
5
- constructor(mainSelector, selectors) {
6
- this.mainSelector = mainSelector;
7
- this.selectors = selectors;
8
- }
9
- async resetState() {
10
- }
11
- async shouldSkipTest(test, page) {
12
- if (test.isVertical !== void 0 && this.selectors.tablist) {
13
- const tablistSelector = this.selectors.tablist;
14
- const tablist = page.locator(tablistSelector).first();
15
- const orientation = await tablist.getAttribute("aria-orientation");
16
- const isVertical = orientation === "vertical";
17
- if (test.isVertical !== isVertical) {
18
- return true;
19
- }
20
- }
21
- return false;
22
- }
23
- getMainSelector() {
24
- return this.mainSelector;
25
- }
26
- };
27
- export {
28
- TabsComponentStrategy
29
- };
@@ -1,63 +0,0 @@
1
- import "./chunk-I2KLQ2HA.js";
2
-
3
- // src/utils/audit/src/audit/audit.ts
4
- import AxeBuilder from "@axe-core/playwright";
5
- import { chromium } from "playwright";
6
- async function createAuditBrowser() {
7
- return await chromium.launch({ headless: true });
8
- }
9
- async function runAudit(url, options) {
10
- let browser = options.browser;
11
- let browserCreated = false;
12
- const timeout = 6e4;
13
- const waitUntil = "domcontentloaded";
14
- try {
15
- if (!browser) {
16
- browser = await chromium.launch({ headless: true });
17
- browserCreated = true;
18
- }
19
- const context = await browser.newContext();
20
- const page = await context.newPage();
21
- await page.goto(url, { waitUntil, timeout });
22
- try {
23
- await page.waitForSelector("main", { state: "visible", timeout });
24
- } catch (waitError) {
25
- console.warn(`\u26A0\uFE0F Warning: <main> landmark not found or not visible on ${url} after ${timeout}ms. Audit will continue, but results may be inaccurate. Consider adding a <main> element to improve audit accuracy. ${waitError instanceof Error ? waitError.message : String(waitError)}`);
26
- }
27
- const axe = new AxeBuilder({ page });
28
- const axeResults = await axe.analyze();
29
- await page.close();
30
- await context.close();
31
- return axeResults;
32
- } catch (error) {
33
- if (error instanceof Error) {
34
- if (error.message.includes("Executable doesn't exist")) {
35
- console.error("\n\u274C Playwright browsers not found!\n");
36
- console.log("\u{1F4E6} First-time setup required:");
37
- console.log(" Run: npx playwright install chromium\n");
38
- console.log("\u{1F4A1} This downloads the browser needed for auditing (~200MB)");
39
- console.log(" You only need to do this once.\n");
40
- } else if (error.message.includes("page.goto: net::ERR_CONNECTION_REFUSED")) {
41
- console.error("\n\u274C Server Not Running!\n");
42
- console.log(" Make sure your server is running before auditing URL");
43
- console.log(" Run: npm run dev # or your start command");
44
- } else if (error.message.includes("page.goto: Protocol error (Page.navigate): Cannot navigate to invalid URL")) {
45
- console.error("\n\u274C Cannot audit invalid URL\n");
46
- } else {
47
- console.error("\u274C Audit error:", error.message);
48
- console.log(" Make sure you provide a valid URL");
49
- }
50
- } else {
51
- console.error("\u274C Audit error (non-Error):", String(error));
52
- }
53
- throw error;
54
- } finally {
55
- if (browser && browserCreated) {
56
- await browser.close();
57
- }
58
- }
59
- }
60
- export {
61
- createAuditBrowser,
62
- runAudit
63
- };
@@ -1,15 +0,0 @@
1
- import {
2
- BADGE_CONFIGS,
3
- displayAllBadges,
4
- displayBadgeInfo,
5
- getBadgeMarkdown,
6
- promptAddBadge
7
- } from "./chunk-JJEPLK7L.js";
8
- import "./chunk-I2KLQ2HA.js";
9
- export {
10
- BADGE_CONFIGS,
11
- displayAllBadges,
12
- displayBadgeInfo,
13
- getBadgeMarkdown,
14
- promptAddBadge
15
- };
@@ -1,108 +0,0 @@
1
- import "./chunk-I2KLQ2HA.js";
2
-
3
- // src/utils/cli/badgeHelper.ts
4
- import fs from "fs-extra";
5
- import path from "path";
6
- import chalk from "chalk";
7
- import readline from "readline";
8
- var BADGE_CONFIGS = {
9
- audit: {
10
- type: "audit",
11
- fileName: "audited-by-aria-ease.svg",
12
- label: "Audited by aria-ease",
13
- markdownUrl: "https://cdn.jsdelivr.net/gh/aria-ease/aria-ease@main/badges/audited-by-aria-ease.svg"
14
- },
15
- component: {
16
- type: "component",
17
- fileName: "components-tested-aria-ease.svg",
18
- label: "Components tested: aria-ease",
19
- markdownUrl: "https://cdn.jsdelivr.net/gh/aria-ease/aria-ease@main/badges/components-tested-aria-ease.svg"
20
- },
21
- verified: {
22
- type: "verified",
23
- fileName: "verified-by-aria-ease.svg",
24
- label: "Verified by aria-ease",
25
- markdownUrl: "https://cdn.jsdelivr.net/gh/aria-ease/aria-ease@main/badges/verified-by-aria-ease.svg"
26
- }
27
- };
28
- function getBadgeMarkdown(badgeType) {
29
- const config = BADGE_CONFIGS[badgeType];
30
- return `[![${config.label}](${config.markdownUrl})](https://github.com/aria-ease/aria-ease)`;
31
- }
32
- function displayBadgeInfo(badgeType) {
33
- const markdown = getBadgeMarkdown(badgeType);
34
- console.log(chalk.cyan("\n\u{1F3C5} Show your accessibility commitment!"));
35
- console.log(chalk.white(" Add this badge to your README.md:\n"));
36
- console.log(chalk.green(" " + markdown));
37
- console.log(chalk.dim("\n This helps others discover accessibility tools and shows you care!\n"));
38
- }
39
- async function promptAddBadge(badgeType, cwd = process.cwd()) {
40
- const readmePath = path.join(cwd, "README.md");
41
- const readmeExists = await fs.pathExists(readmePath);
42
- if (!readmeExists) {
43
- console.log(chalk.yellow(" \u2139\uFE0F No README.md found in current directory"));
44
- return;
45
- }
46
- const readmeContent = await fs.readFile(readmePath, "utf-8");
47
- const markdown = getBadgeMarkdown(badgeType);
48
- if (readmeContent.includes(markdown) || readmeContent.includes(BADGE_CONFIGS[badgeType].fileName)) {
49
- console.log(chalk.gray(" \u2713 Badge already in README.md"));
50
- return;
51
- }
52
- const rl = readline.createInterface({
53
- input: process.stdin,
54
- output: process.stdout
55
- });
56
- const answer = await new Promise((resolve) => {
57
- rl.question(chalk.cyan(" Add badge to README.md now? (y/n): "), (ans) => {
58
- rl.close();
59
- resolve(ans.toLowerCase().trim());
60
- });
61
- });
62
- if (answer === "y" || answer === "yes") {
63
- await addBadgeToReadme(readmePath, readmeContent, markdown);
64
- console.log(chalk.green(" \u2713 Badge added to README.md!"));
65
- } else {
66
- console.log(chalk.gray(" Skipped. You can add it manually anytime."));
67
- }
68
- }
69
- async function addBadgeToReadme(readmePath, content, badge) {
70
- const lines = content.split("\n");
71
- let insertIndex = 0;
72
- for (let i = 0; i < lines.length; i++) {
73
- const line = lines[i].trim();
74
- if (line.startsWith("[![") || line.startsWith("[!")) {
75
- insertIndex = i + 1;
76
- continue;
77
- }
78
- if (insertIndex > 0 && !line.startsWith("[![") && !line.startsWith("[!") && line.length > 0) {
79
- break;
80
- }
81
- if (insertIndex === 0 && line.startsWith("#")) {
82
- insertIndex = i + 2;
83
- break;
84
- }
85
- }
86
- if (insertIndex === 0) {
87
- insertIndex = 1;
88
- }
89
- lines.splice(insertIndex, 0, badge);
90
- await fs.writeFile(readmePath, lines.join("\n"), "utf-8");
91
- }
92
- function displayAllBadges() {
93
- console.log(chalk.cyan("\n\u{1F4CD} Available badges:"));
94
- console.log(chalk.white("\n For audits:"));
95
- console.log(chalk.green(" " + getBadgeMarkdown("audit")));
96
- console.log(chalk.white("\n For component testing:"));
97
- console.log(chalk.green(" " + getBadgeMarkdown("component")));
98
- console.log(chalk.white("\n For both (verified):"));
99
- console.log(chalk.green(" " + getBadgeMarkdown("verified")));
100
- console.log("");
101
- }
102
- export {
103
- BADGE_CONFIGS,
104
- displayAllBadges,
105
- displayBadgeInfo,
106
- getBadgeMarkdown,
107
- promptAddBadge
108
- };
@@ -1,437 +0,0 @@
1
- import "./chunk-I2KLQ2HA.js";
2
-
3
- // src/utils/test/dsl/src/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/test/dsl/src/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/test/dsl/src/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
- };