@diegovelasquezweb/a11y-engine 0.4.2 → 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.
Files changed (40) hide show
  1. package/CHANGELOG.md +80 -26
  2. package/README.md +76 -215
  3. package/docs/api-reference.md +107 -0
  4. package/docs/architecture.md +83 -209
  5. package/docs/cli-handbook.md +4 -4
  6. package/docs/engine-manifest.md +58 -0
  7. package/docs/outputs.md +9 -11
  8. package/docs/testing.md +63 -0
  9. package/package.json +3 -6
  10. package/src/core/asset-loader.mjs +22 -14
  11. package/src/index.d.mts +29 -12
  12. package/src/index.mjs +49 -52
  13. package/src/pipeline/dom-scanner.mjs +4 -4
  14. package/src/reports/renderers/findings.mjs +32 -32
  15. package/src/reports/renderers/md.mjs +6 -4
  16. package/assets/source/discovery/crawler-config.json +0 -11
  17. package/assets/source/discovery/stack-detection.json +0 -235
  18. package/assets/source/engine/cdp-checks.json +0 -30
  19. package/assets/source/engine/pa11y-config.json +0 -53
  20. package/assets/source/remediation/axe-check-maps.json +0 -31
  21. package/assets/source/remediation/code-patterns.json +0 -109
  22. package/assets/source/remediation/guardrails.json +0 -24
  23. package/assets/source/remediation/intelligence.json +0 -4166
  24. package/assets/source/remediation/source-boundaries.json +0 -46
  25. package/assets/source/reporting/compliance-config.json +0 -173
  26. package/assets/source/reporting/manual-checks.json +0 -944
  27. package/assets/source/reporting/wcag-reference.json +0 -588
  28. package/src/sync-assets.mjs +0 -66
  29. /package/assets/{generated/discovery → discovery}/crawler-config.mjs +0 -0
  30. /package/assets/{generated/discovery → discovery}/stack-detection.mjs +0 -0
  31. /package/assets/{generated/remediation → remediation}/axe-check-maps.mjs +0 -0
  32. /package/assets/{generated/remediation → remediation}/code-patterns.mjs +0 -0
  33. /package/assets/{generated/remediation → remediation}/guardrails.mjs +0 -0
  34. /package/assets/{generated/remediation → remediation}/intelligence.mjs +0 -0
  35. /package/assets/{generated/remediation → remediation}/source-boundaries.mjs +0 -0
  36. /package/assets/{generated/reporting → reporting}/compliance-config.mjs +0 -0
  37. /package/assets/{generated/reporting → reporting}/manual-checks.mjs +0 -0
  38. /package/assets/{generated/reporting → reporting}/wcag-reference.mjs +0 -0
  39. /package/assets/{generated/engine → scanning}/cdp-checks.mjs +0 -0
  40. /package/assets/{generated/engine → scanning}/pa11y-config.mjs +0 -0
package/src/index.d.mts CHANGED
@@ -53,26 +53,44 @@ export interface Finding {
53
53
  affected_urls?: string[] | null;
54
54
  }
55
55
 
56
- export interface EnrichedFinding extends Finding {
56
+ export interface EnrichedFinding {
57
+ id: string;
57
58
  ruleId: string;
59
+ source: string;
58
60
  sourceRuleId: string | null;
59
- fixDescription: string | null;
60
- fixCode: string | null;
61
- fixCodeLang: string | null;
62
- falsePositiveRisk: string | null;
63
- fixDifficultyNotes: string | string[] | null;
64
- screenshotPath: string | null;
61
+ title: string;
62
+ severity: string;
63
+ wcag: string;
65
64
  wcagCriterionId: string | null;
66
65
  wcagClassification: string | null;
67
- impactedUsers: string | null;
66
+ category: string | null;
67
+ area: string;
68
+ url: string;
69
+ selector: string;
68
70
  primarySelector: string;
71
+ impactedUsers: string | null;
72
+ actual: string;
73
+ expected: string;
69
74
  primaryFailureMode: string | null;
70
75
  relationshipHint: string | null;
71
76
  failureChecks: unknown[];
72
77
  relatedContext: unknown[];
78
+ mdn: string | null;
79
+ fixDescription: string | null;
80
+ fixCode: string | null;
81
+ fixCodeLang: string | null;
73
82
  recommendedFix: string;
83
+ evidence: unknown[];
74
84
  totalInstances: number | null;
85
+ effort: string;
75
86
  relatedRules: string[];
87
+ screenshotPath: string | null;
88
+ falsePositiveRisk: string | null;
89
+ guardrails: Record<string, unknown> | null;
90
+ fixDifficultyNotes: string | string[] | null;
91
+ frameworkNotes: string | null;
92
+ cmsNotes: string | null;
93
+ fileSearchPattern: string | null;
76
94
  ownershipStatus: string;
77
95
  ownershipReason: string | null;
78
96
  primarySourceScope: string[];
@@ -84,7 +102,6 @@ export interface EnrichedFinding extends Finding {
84
102
  checkData: Record<string, unknown> | null;
85
103
  pagesAffected: number | null;
86
104
  affectedUrls: string[] | null;
87
- effort: string;
88
105
  }
89
106
 
90
107
  export interface SeverityTotals {
@@ -232,12 +249,12 @@ export interface EnrichmentOptions {
232
249
 
233
250
  export function runAudit(options: RunAuditOptions): Promise<ScanPayload>;
234
251
 
235
- export function getEnrichedFindings(
236
- input: ScanPayload | Finding[] | Record<string, unknown>[],
252
+ export function getFindings(
253
+ input: ScanPayload,
237
254
  options?: EnrichmentOptions
238
255
  ): EnrichedFinding[];
239
256
 
240
- export function getAuditSummary(
257
+ export function getOverview(
241
258
  findings: EnrichedFinding[],
242
259
  payload?: ScanPayload | null
243
260
  ): AuditSummary;
package/src/index.mjs CHANGED
@@ -23,7 +23,7 @@ function getIntelligence() {
23
23
  function getPa11yConfig() {
24
24
  if (!_pa11yConfig) {
25
25
  try {
26
- _pa11yConfig = loadAssetJson(ASSET_PATHS.engine.pa11yConfig, "pa11y-config.json");
26
+ _pa11yConfig = loadAssetJson(ASSET_PATHS.scanning.pa11yConfig, "pa11y-config.json");
27
27
  } catch {
28
28
  _pa11yConfig = { equivalenceMap: {}, ignoreByPrinciple: [], impactMap: {} };
29
29
  }
@@ -159,31 +159,26 @@ function normalizeSingleFinding(item, index, screenshotUrlBuilder) {
159
159
  /**
160
160
  * Normalizes and enriches raw findings with intelligence data.
161
161
  *
162
- * Accepts either:
163
- * - A full scan payload: { findings: object[], metadata?: object }
164
- * - An array of findings directly: object[]
165
- *
166
162
  * Options:
167
163
  * - screenshotUrlBuilder: (rawPath: string) => string — transforms screenshot
168
164
  * paths into consumer-specific URLs.
169
165
  *
170
- * @param {object[]|{findings: object[]}} input
166
+ * @param {{findings: object[]}} input
171
167
  * @param {{ screenshotUrlBuilder?: (path: string) => string }} [options={}]
172
168
  * @returns {object[]} Enriched, normalized, sorted findings.
173
169
  */
174
- export function getEnrichedFindings(input, options = {}) {
170
+ export function getFindings(input, options = {}) {
175
171
  const { screenshotUrlBuilder = null } = options;
176
172
  const rules = getIntelligence().rules || {};
177
173
 
178
- // Accept payload object or array directly
179
- const rawFindings = Array.isArray(input) ? input : (input?.findings || []);
174
+ const rawFindings = input?.findings || [];
180
175
 
181
176
  // Normalize raw findings
182
177
  const normalized = rawFindings.map((item, index) =>
183
178
  normalizeSingleFinding(item, index, screenshotUrlBuilder)
184
179
  );
185
180
 
186
- // Enrich with intelligence + camelCase aliases
181
+ // Enrich with intelligence and output camelCase-only findings
187
182
  const enriched = normalized.map((finding) => {
188
183
  const canonical = mapPa11yRuleToCanonical(
189
184
  finding.rule_id,
@@ -191,31 +186,45 @@ export function getEnrichedFindings(input, options = {}) {
191
186
  finding.check_data,
192
187
  );
193
188
 
194
- // Effort will be inferred after enrichment
195
-
196
- // Always create camelCase aliases
197
- const withAliases = {
198
- ...finding,
189
+ // Build camelCase-only enriched finding
190
+ const enrichedFinding = {
191
+ id: finding.id,
199
192
  ruleId: canonical,
200
- rule_id: canonical,
193
+ source: finding.source,
201
194
  sourceRuleId: finding.source_rule_id || finding.rule_id || null,
202
- fixDescription: finding.fix_description,
203
- fixCode: finding.fix_code,
204
- fixCodeLang: finding.fix_code_lang,
205
- falsePositiveRisk: finding.false_positive_risk,
206
- fixDifficultyNotes: finding.fix_difficulty_notes,
207
- screenshotPath: finding.screenshot_path,
195
+ title: finding.title,
196
+ severity: finding.severity,
197
+ wcag: finding.wcag,
208
198
  wcagCriterionId: finding.wcag_criterion_id,
209
199
  wcagClassification: finding.wcag_classification,
210
- impactedUsers: finding.impacted_users,
200
+ category: finding.category,
201
+ area: finding.area,
202
+ url: finding.url,
203
+ selector: finding.selector,
211
204
  primarySelector: finding.primary_selector,
205
+ impactedUsers: finding.impacted_users,
206
+ actual: finding.actual,
207
+ expected: finding.expected,
212
208
  primaryFailureMode: finding.primary_failure_mode,
213
209
  relationshipHint: finding.relationship_hint,
214
210
  failureChecks: finding.failure_checks,
215
211
  relatedContext: finding.related_context,
212
+ mdn: finding.mdn,
213
+ fixDescription: finding.fix_description,
214
+ fixCode: finding.fix_code,
215
+ fixCodeLang: finding.fix_code_lang,
216
216
  recommendedFix: finding.recommended_fix,
217
+ evidence: finding.evidence,
217
218
  totalInstances: finding.total_instances,
219
+ effort: finding.effort,
218
220
  relatedRules: finding.related_rules,
221
+ screenshotPath: finding.screenshot_path,
222
+ falsePositiveRisk: finding.false_positive_risk,
223
+ guardrails: finding.guardrails,
224
+ fixDifficultyNotes: finding.fix_difficulty_notes,
225
+ frameworkNotes: finding.framework_notes,
226
+ cmsNotes: finding.cms_notes,
227
+ fileSearchPattern: finding.file_search_pattern,
219
228
  ownershipStatus: finding.ownership_status,
220
229
  ownershipReason: finding.ownership_reason,
221
230
  primarySourceScope: finding.primary_source_scope,
@@ -229,36 +238,24 @@ export function getEnrichedFindings(input, options = {}) {
229
238
  affectedUrls: finding.affected_urls,
230
239
  };
231
240
 
232
- // If fix data already exists, no need to look up intelligence
233
- let result;
234
- if (withAliases.fixDescription || withAliases.fixCode) {
235
- result = withAliases;
236
- } else {
241
+ // Enrich from intelligence if no fix data exists yet
242
+ if (!enrichedFinding.fixDescription && !enrichedFinding.fixCode) {
237
243
  const info = rules[canonical];
238
- if (!info) {
239
- result = withAliases;
240
- } else {
241
- result = {
242
- ...withAliases,
243
- category: withAliases.category ?? info.category ?? null,
244
- fixDescription: info.fix?.description ?? null,
245
- fix_description: info.fix?.description ?? null,
246
- fixCode: info.fix?.code ?? null,
247
- fix_code: info.fix?.code ?? withAliases.fix_code ?? null,
248
- falsePositiveRisk: withAliases.falsePositiveRisk ?? info.false_positive_risk ?? null,
249
- false_positive_risk: withAliases.false_positive_risk ?? info.false_positive_risk ?? null,
250
- fixDifficultyNotes: withAliases.fixDifficultyNotes ?? info.fix_difficulty_notes ?? null,
251
- fix_difficulty_notes: withAliases.fix_difficulty_notes ?? info.fix_difficulty_notes ?? null,
252
- };
244
+ if (info) {
245
+ enrichedFinding.category = enrichedFinding.category ?? info.category ?? null;
246
+ enrichedFinding.fixDescription = info.fix?.description ?? null;
247
+ enrichedFinding.fixCode = info.fix?.code ?? null;
248
+ enrichedFinding.falsePositiveRisk = enrichedFinding.falsePositiveRisk ?? info.false_positive_risk ?? null;
249
+ enrichedFinding.fixDifficultyNotes = enrichedFinding.fixDifficultyNotes ?? info.fix_difficulty_notes ?? null;
253
250
  }
254
251
  }
255
252
 
256
253
  // Infer effort AFTER enrichment so intelligence-provided fixCode is considered
257
- if (!result.effort || result.effort === "null") {
258
- result.effort = (result.fixCode || result.fix_code) ? "low" : "high";
254
+ if (!enrichedFinding.effort || enrichedFinding.effort === "null") {
255
+ enrichedFinding.effort = enrichedFinding.fixCode ? "low" : "high";
259
256
  }
260
257
 
261
- return result;
258
+ return enrichedFinding;
262
259
  });
263
260
 
264
261
  // Sort by severity then by ID
@@ -332,9 +329,9 @@ function getPersonaGroups(findings) {
332
329
  }
333
330
 
334
331
  for (const f of findings) {
335
- const ruleId = (f.ruleId || f.rule_id || "").toLowerCase();
336
- const wcagCriterionId = f.wcagCriterionId || f.wcag_criterion_id || "";
337
- const users = (f.impactedUsers || f.impacted_users || "").toLowerCase();
332
+ const ruleId = (f.ruleId || "").toLowerCase();
333
+ const wcagCriterionId = f.wcagCriterionId || "";
334
+ const users = (f.impactedUsers || "").toLowerCase();
338
335
  const matchedPersonas = new Set();
339
336
 
340
337
  for (const [personaKey, mapping] of Object.entries(personaMapping)) {
@@ -377,7 +374,7 @@ function getPersonaGroups(findings) {
377
374
  * @param {{ findings: object[], metadata?: object }|null} [payload=null] - Original scan payload for metadata extraction.
378
375
  * @returns {object} Full audit summary.
379
376
  */
380
- export function getAuditSummary(findings, payload = null) {
377
+ export function getOverview(findings, payload = null) {
381
378
  const totals = { Critical: 0, Serious: 0, Moderate: 0, Minor: 0 };
382
379
  for (const f of findings) {
383
380
  const severity = f.severity || "";
@@ -390,7 +387,7 @@ export function getAuditSummary(findings, payload = null) {
390
387
  const quickWins = findings
391
388
  .filter((f) =>
392
389
  (f.severity === "Critical" || f.severity === "Serious") &&
393
- (f.fixCode || f.fix_code)
390
+ f.fixCode
394
391
  )
395
392
  .slice(0, 3);
396
393
 
@@ -430,7 +427,7 @@ export function getAuditSummary(findings, payload = null) {
430
427
 
431
428
  /**
432
429
  * Runs a complete accessibility audit: crawl + scan (axe + CDP + pa11y) + analyze.
433
- * Returns the enriched scan payload ready for getEnrichedFindings().
430
+ * Returns the scan payload ready for getFindings().
434
431
  *
435
432
  * @param {{
436
433
  * baseUrl: string,
@@ -26,12 +26,12 @@ const STACK_DETECTION = loadAssetJson(
26
26
  "assets/discovery/stack-detection.json",
27
27
  );
28
28
  const CDP_CHECKS = loadAssetJson(
29
- ASSET_PATHS.engine.cdpChecks,
30
- "assets/engine/cdp-checks.json",
29
+ ASSET_PATHS.scanning.cdpChecks,
30
+ "assets/scanning/cdp-checks.json",
31
31
  );
32
32
  const PA11Y_CONFIG = loadAssetJson(
33
- ASSET_PATHS.engine.pa11yConfig,
34
- "assets/engine/pa11y-config.json",
33
+ ASSET_PATHS.scanning.pa11yConfig,
34
+ "assets/scanning/pa11y-config.json",
35
35
  );
36
36
  const AXE_TAGS = [
37
37
  "wcag2a",
@@ -43,55 +43,55 @@ export function normalizeFindings(payload) {
43
43
  return payload.findings
44
44
  .map((item, index) => ({
45
45
  id: String(item.id ?? `A11Y-${String(index + 1).padStart(3, "0")}`),
46
- ruleId: String(item.rule_id ?? ""),
46
+ ruleId: String(item.ruleId ?? item.rule_id ?? ""),
47
47
  category: item.category ?? null,
48
48
  title: String(item.title ?? "Untitled finding"),
49
49
  severity: String(item.severity ?? "Unknown"),
50
50
  wcag: String(item.wcag ?? ""),
51
- wcagClassification: item.wcag_classification ?? null,
51
+ wcagClassification: item.wcagClassification ?? item.wcag_classification ?? null,
52
52
  area: String(item.area ?? ""),
53
53
  url: String(item.url ?? ""),
54
54
  selector: String(item.selector ?? ""),
55
- primarySelector: String(item.primary_selector ?? item.selector ?? ""),
55
+ primarySelector: String(item.primarySelector ?? item.primary_selector ?? item.selector ?? ""),
56
56
  impactedUsers: String(
57
- item.impacted_users ?? "Users relying on assistive technology",
57
+ item.impactedUsers ?? item.impacted_users ?? "Users relying on assistive technology",
58
58
  ),
59
59
  actual: String(item.actual ?? ""),
60
- primaryFailureMode: item.primary_failure_mode ?? null,
61
- relationshipHint: item.relationship_hint ?? null,
62
- failureChecks: Array.isArray(item.failure_checks) ? item.failure_checks : [],
63
- relatedContext: Array.isArray(item.related_context) ? item.related_context : [],
60
+ primaryFailureMode: item.primaryFailureMode ?? item.primary_failure_mode ?? null,
61
+ relationshipHint: item.relationshipHint ?? item.relationship_hint ?? null,
62
+ failureChecks: Array.isArray(item.failureChecks ?? item.failure_checks) ? (item.failureChecks ?? item.failure_checks) : [],
63
+ relatedContext: Array.isArray(item.relatedContext ?? item.related_context) ? (item.relatedContext ?? item.related_context) : [],
64
64
  expected: String(item.expected ?? ""),
65
65
  mdn: item.mdn ?? null,
66
- fixDescription: item.fix_description ?? null,
67
- fixCode: item.fix_code ?? null,
68
- recommendedFix: String(item.recommended_fix ?? item.recommendedFix ?? ""),
66
+ fixDescription: item.fixDescription ?? item.fix_description ?? null,
67
+ fixCode: item.fixCode ?? item.fix_code ?? null,
68
+ recommendedFix: String(item.recommendedFix ?? item.recommended_fix ?? ""),
69
69
  evidence: Array.isArray(item.evidence) ? item.evidence : [],
70
70
  totalInstances:
71
- typeof item.total_instances === "number" ? item.total_instances : null,
71
+ typeof (item.totalInstances ?? item.total_instances) === "number" ? (item.totalInstances ?? item.total_instances) : null,
72
72
  effort: item.effort ?? null,
73
- relatedRules: Array.isArray(item.related_rules) ? item.related_rules : [],
74
- fixCodeLang: item.fix_code_lang ?? "html",
75
- screenshotPath: item.screenshot_path ?? null,
76
- falsePositiveRisk: item.false_positive_risk ?? null,
73
+ relatedRules: Array.isArray(item.relatedRules ?? item.related_rules) ? (item.relatedRules ?? item.related_rules) : [],
74
+ fixCodeLang: item.fixCodeLang ?? item.fix_code_lang ?? "html",
75
+ screenshotPath: item.screenshotPath ?? item.screenshot_path ?? null,
76
+ falsePositiveRisk: item.falsePositiveRisk ?? item.false_positive_risk ?? null,
77
77
  guardrails: item.guardrails ?? null,
78
- fixDifficultyNotes: item.fix_difficulty_notes ?? null,
79
- frameworkNotes: item.framework_notes ?? null,
80
- cmsNotes: item.cms_notes ?? null,
81
- fileSearchPattern: item.file_search_pattern ?? null,
82
- ownershipStatus: item.ownership_status ?? "unknown",
83
- ownershipReason: item.ownership_reason ?? null,
84
- primarySourceScope: Array.isArray(item.primary_source_scope)
85
- ? item.primary_source_scope
78
+ fixDifficultyNotes: item.fixDifficultyNotes ?? item.fix_difficulty_notes ?? null,
79
+ frameworkNotes: item.frameworkNotes ?? item.framework_notes ?? null,
80
+ cmsNotes: item.cmsNotes ?? item.cms_notes ?? null,
81
+ fileSearchPattern: item.fileSearchPattern ?? item.file_search_pattern ?? null,
82
+ ownershipStatus: item.ownershipStatus ?? item.ownership_status ?? "unknown",
83
+ ownershipReason: item.ownershipReason ?? item.ownership_reason ?? null,
84
+ primarySourceScope: Array.isArray(item.primarySourceScope ?? item.primary_source_scope)
85
+ ? (item.primarySourceScope ?? item.primary_source_scope)
86
86
  : [],
87
- searchStrategy: item.search_strategy ?? "verify_ownership_before_search",
88
- managedByLibrary: item.managed_by_library ?? null,
89
- componentHint: item.component_hint ?? null,
90
- verificationCommand: item.verification_command ?? null,
91
- verificationCommandFallback: item.verification_command_fallback ?? null,
92
- pagesAffected: typeof item.pages_affected === "number" ? item.pages_affected : null,
93
- affectedUrls: Array.isArray(item.affected_urls) ? item.affected_urls : null,
94
- checkData: item.check_data ?? null,
87
+ searchStrategy: item.searchStrategy ?? item.search_strategy ?? "verify_ownership_before_search",
88
+ managedByLibrary: item.managedByLibrary ?? item.managed_by_library ?? null,
89
+ componentHint: item.componentHint ?? item.component_hint ?? null,
90
+ verificationCommand: item.verificationCommand ?? item.verification_command ?? null,
91
+ verificationCommandFallback: item.verificationCommandFallback ?? item.verification_command_fallback ?? null,
92
+ pagesAffected: typeof (item.pagesAffected ?? item.pages_affected) === "number" ? (item.pagesAffected ?? item.pages_affected) : null,
93
+ affectedUrls: Array.isArray(item.affectedUrls ?? item.affected_urls) ? (item.affectedUrls ?? item.affected_urls) : null,
94
+ checkData: item.checkData ?? item.check_data ?? null,
95
95
  }))
96
96
  .sort((a, b) => {
97
97
  const sa = SEVERITY_ORDER[a.severity] ?? 99;
@@ -144,15 +144,17 @@ function buildIncompleteSection(incompleteFindings) {
144
144
  if (!Array.isArray(incompleteFindings) || incompleteFindings.length === 0) return "";
145
145
  const rows = incompleteFindings.map((f) => {
146
146
  const msg = (f.message || f.description || "Needs manual review").replace(/\|/g, "\\|");
147
- const areaCell = f.pages_affected > 1
148
- ? `${f.pages_affected} pages`
147
+ const pagesAffected = f.pagesAffected ?? f.pages_affected;
148
+ const ruleId = f.ruleId ?? f.rule_id;
149
+ const areaCell = pagesAffected > 1
150
+ ? `${pagesAffected} pages`
149
151
  : `\`${f.areas?.[0] ?? "?"}\``;
150
152
  let actionableHint = "";
151
- if (f.rule_id === "duplicate-id-aria" && f.message) {
153
+ if (ruleId === "duplicate-id-aria" && f.message) {
152
154
  const idMatch = f.message.match(/same id attribute[:\s]+(\S+?)\.?\s*$/i);
153
155
  if (idMatch) actionableHint = ` — grep: \`id="${idMatch[1]}"\``;
154
156
  }
155
- return `| \`${f.rule_id}\` | ${f.impact ?? "?"} | ${areaCell} | ${msg}${actionableHint} |`;
157
+ return `| \`${ruleId}\` | ${f.impact ?? "?"} | ${areaCell} | ${msg}${actionableHint} |`;
156
158
  });
157
159
  return `## Potential Issues — Manual Review Required
158
160
 
@@ -1,11 +0,0 @@
1
- {
2
- "blockedExtensions": [
3
- "pdf", "jpg", "jpeg", "png", "gif", "svg", "webp", "ico",
4
- "css", "js", "mjs", "json", "xml", "zip", "tar", "gz",
5
- "mp4", "mp3", "webm", "wav", "woff", "woff2", "ttf", "otf", "eot",
6
- "avif", "csv", "txt", "map", "wasm"
7
- ],
8
- "paginationParams": [
9
- "page", "paged", "p", "pg", "offset", "cursor", "start", "from", "skip", "limit", "per_page"
10
- ]
11
- }
@@ -1,235 +0,0 @@
1
- {
2
- "platformStructureDetectors": [
3
- ["wordpress", ["wp-content/themes"]],
4
- ["drupal", ["web/themes", "themes"]],
5
- ["shopify", ["sections", "snippets", "layout", "templates"]]
6
- ],
7
- "uiLibraryPackageDetectors": [
8
- ["@radix-ui", "radix"],
9
- ["@headlessui", "headless-ui"],
10
- ["@chakra-ui", "chakra"],
11
- ["@mantine", "mantine"],
12
- ["@mui", "material-ui"],
13
- ["antd", "ant-design"],
14
- ["@shopify/polaris", "polaris"],
15
- ["@react-aria", "react-aria"],
16
- ["ariakit", "ariakit"],
17
- ["primevue", "primevue"],
18
- ["vuetify", "vuetify"],
19
- ["swiper", "swiper"]
20
- ],
21
- "frameworkPackageDetectors": [
22
- ["next", "nextjs"],
23
- ["gatsby", "gatsby"],
24
- ["nuxt", "nuxt"],
25
- ["@nuxt/core", "nuxt"],
26
- ["@angular/core", "angular"],
27
- ["astro", "astro"],
28
- ["@sveltejs/kit", "svelte"],
29
- ["svelte", "svelte"],
30
- ["vue", "vue"],
31
- ["react", "react"]
32
- ],
33
- "domFrameworkDetectors": [
34
- {
35
- "id": "nextjs",
36
- "type": "framework",
37
- "signals": [
38
- { "kind": "global", "key": "__NEXT_DATA__" },
39
- { "kind": "global", "key": "__next" },
40
- { "kind": "selector", "value": "script#__NEXT_DATA__" },
41
- { "kind": "selector", "value": "div#__next" },
42
- { "kind": "scriptSrc", "pattern": "/_next/" },
43
- { "kind": "meta", "name": "next-head-count" }
44
- ]
45
- },
46
- {
47
- "id": "nuxt",
48
- "type": "framework",
49
- "signals": [
50
- { "kind": "global", "key": "__NUXT__" },
51
- { "kind": "global", "key": "$nuxt" },
52
- { "kind": "selector", "value": "div#__nuxt" },
53
- { "kind": "scriptSrc", "pattern": "/_nuxt/" },
54
- { "kind": "meta", "name": "generator", "pattern": "Nuxt" }
55
- ]
56
- },
57
- {
58
- "id": "gatsby",
59
- "type": "framework",
60
- "signals": [
61
- { "kind": "global", "key": "___gatsby" },
62
- { "kind": "selector", "value": "div#___gatsby" },
63
- { "kind": "meta", "name": "generator", "pattern": "Gatsby" }
64
- ]
65
- },
66
- {
67
- "id": "angular",
68
- "type": "framework",
69
- "signals": [
70
- { "kind": "global", "key": "ng" },
71
- { "kind": "selector", "value": "[ng-version]" },
72
- { "kind": "selector", "value": "app-root" }
73
- ]
74
- },
75
- {
76
- "id": "svelte",
77
- "type": "framework",
78
- "signals": [
79
- { "kind": "global", "key": "__svelte" },
80
- { "kind": "selector", "value": "[data-svelte-h]" },
81
- { "kind": "meta", "name": "generator", "pattern": "Svelte" }
82
- ]
83
- },
84
- {
85
- "id": "astro",
86
- "type": "framework",
87
- "signals": [
88
- { "kind": "selector", "value": "[data-astro-cid]" },
89
- { "kind": "meta", "name": "generator", "pattern": "Astro" },
90
- { "kind": "selector", "value": "astro-island" }
91
- ]
92
- },
93
- {
94
- "id": "remix",
95
- "type": "framework",
96
- "signals": [
97
- { "kind": "global", "key": "__remixContext" },
98
- { "kind": "global", "key": "__remixManifest" }
99
- ]
100
- },
101
- {
102
- "id": "vue",
103
- "type": "framework",
104
- "signals": [
105
- { "kind": "global", "key": "__VUE__" },
106
- { "kind": "selector", "value": "[data-v-]" },
107
- { "kind": "selector", "value": "div#app[data-v-app]" }
108
- ]
109
- },
110
- {
111
- "id": "react",
112
- "type": "framework",
113
- "signals": [
114
- { "kind": "selector", "value": "[data-reactroot]" },
115
- { "kind": "selector", "value": "[data-reactid]" },
116
- { "kind": "global", "key": "__REACT_DEVTOOLS_GLOBAL_HOOK__" }
117
- ]
118
- }
119
- ],
120
- "domCmsDetectors": [
121
- {
122
- "id": "wordpress",
123
- "type": "cms",
124
- "signals": [
125
- { "kind": "meta", "name": "generator", "pattern": "WordPress" },
126
- { "kind": "scriptSrc", "pattern": "/wp-content/" },
127
- { "kind": "scriptSrc", "pattern": "/wp-includes/" },
128
- { "kind": "selector", "value": "link[href*='wp-content']" },
129
- { "kind": "selector", "value": "body.wp-site-blocks" }
130
- ]
131
- },
132
- {
133
- "id": "shopify",
134
- "type": "cms",
135
- "signals": [
136
- { "kind": "global", "key": "Shopify" },
137
- { "kind": "scriptSrc", "pattern": "cdn.shopify.com" },
138
- { "kind": "meta", "name": "shopify-digital-wallet" },
139
- { "kind": "selector", "value": "link[href*='cdn.shopify']" }
140
- ]
141
- },
142
- {
143
- "id": "drupal",
144
- "type": "cms",
145
- "signals": [
146
- { "kind": "meta", "name": "generator", "pattern": "Drupal" },
147
- { "kind": "global", "key": "Drupal" },
148
- { "kind": "scriptSrc", "pattern": "/sites/default/files/" }
149
- ]
150
- },
151
- {
152
- "id": "wix",
153
- "type": "cms",
154
- "signals": [
155
- { "kind": "meta", "name": "generator", "pattern": "Wix" },
156
- { "kind": "scriptSrc", "pattern": "static.parastorage.com" },
157
- { "kind": "scriptSrc", "pattern": "static.wixstatic.com" }
158
- ]
159
- },
160
- {
161
- "id": "squarespace",
162
- "type": "cms",
163
- "signals": [
164
- { "kind": "meta", "name": "generator", "pattern": "Squarespace" },
165
- { "kind": "scriptSrc", "pattern": "static1.squarespace.com" }
166
- ]
167
- },
168
- {
169
- "id": "webflow",
170
- "type": "cms",
171
- "signals": [
172
- { "kind": "meta", "name": "generator", "pattern": "Webflow" },
173
- { "kind": "selector", "value": "html.w-mod-js" },
174
- { "kind": "scriptSrc", "pattern": "assets.website-files.com" }
175
- ]
176
- },
177
- {
178
- "id": "joomla",
179
- "type": "cms",
180
- "signals": [
181
- { "kind": "meta", "name": "generator", "pattern": "Joomla" },
182
- { "kind": "scriptSrc", "pattern": "/media/system/js/" }
183
- ]
184
- },
185
- {
186
- "id": "magento",
187
- "type": "cms",
188
- "signals": [
189
- { "kind": "scriptSrc", "pattern": "/static/version" },
190
- { "kind": "selector", "value": "script[data-requiremodule]" },
191
- { "kind": "global", "key": "require" }
192
- ]
193
- }
194
- ],
195
- "domUiLibraryDetectors": [
196
- {
197
- "id": "bootstrap",
198
- "signals": [
199
- { "kind": "selector", "value": "link[href*='bootstrap']" },
200
- { "kind": "scriptSrc", "pattern": "bootstrap" },
201
- { "kind": "selector", "value": ".container .row .col" }
202
- ]
203
- },
204
- {
205
- "id": "tailwindcss",
206
- "signals": [
207
- { "kind": "selector", "value": "style[data-precedence]" },
208
- { "kind": "selector", "value": "link[href*='tailwind']" },
209
- { "kind": "meta", "name": "generator", "pattern": "Tailwind" }
210
- ]
211
- },
212
- {
213
- "id": "material-ui",
214
- "signals": [
215
- { "kind": "selector", "value": "[class*='MuiButton']" },
216
- { "kind": "selector", "value": "[class*='MuiTypography']" },
217
- { "kind": "selector", "value": "[class*='MuiPaper']" }
218
- ]
219
- },
220
- {
221
- "id": "jquery",
222
- "signals": [
223
- { "kind": "global", "key": "jQuery" },
224
- { "kind": "global", "key": "$" }
225
- ]
226
- },
227
- {
228
- "id": "foundation",
229
- "signals": [
230
- { "kind": "global", "key": "Foundation" },
231
- { "kind": "selector", "value": "link[href*='foundation']" }
232
- ]
233
- }
234
- ]
235
- }