@drowlink/aeo-linter-core 0.1.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 (161) hide show
  1. package/dist/__tests__/audit-contract.test.d.ts +2 -0
  2. package/dist/__tests__/audit-contract.test.d.ts.map +1 -0
  3. package/dist/__tests__/audit-contract.test.js +120 -0
  4. package/dist/__tests__/audit-contract.test.js.map +1 -0
  5. package/dist/__tests__/gatherers.test.d.ts +2 -0
  6. package/dist/__tests__/gatherers.test.d.ts.map +1 -0
  7. package/dist/__tests__/gatherers.test.js +139 -0
  8. package/dist/__tests__/gatherers.test.js.map +1 -0
  9. package/dist/__tests__/runner.test.d.ts +2 -0
  10. package/dist/__tests__/runner.test.d.ts.map +1 -0
  11. package/dist/__tests__/runner.test.js +77 -0
  12. package/dist/__tests__/runner.test.js.map +1 -0
  13. package/dist/audits/ai-accessibility/ai-bot-sitemap.d.ts +10 -0
  14. package/dist/audits/ai-accessibility/ai-bot-sitemap.d.ts.map +1 -0
  15. package/dist/audits/ai-accessibility/ai-bot-sitemap.js +27 -0
  16. package/dist/audits/ai-accessibility/ai-bot-sitemap.js.map +1 -0
  17. package/dist/audits/ai-accessibility/ai-robots-txt.d.ts +10 -0
  18. package/dist/audits/ai-accessibility/ai-robots-txt.d.ts.map +1 -0
  19. package/dist/audits/ai-accessibility/ai-robots-txt.js +54 -0
  20. package/dist/audits/ai-accessibility/ai-robots-txt.js.map +1 -0
  21. package/dist/audits/ai-accessibility/ai-x-robots-tag.d.ts +10 -0
  22. package/dist/audits/ai-accessibility/ai-x-robots-tag.d.ts.map +1 -0
  23. package/dist/audits/ai-accessibility/ai-x-robots-tag.js +36 -0
  24. package/dist/audits/ai-accessibility/ai-x-robots-tag.js.map +1 -0
  25. package/dist/audits/audit.d.ts +56 -0
  26. package/dist/audits/audit.d.ts.map +1 -0
  27. package/dist/audits/audit.js +86 -0
  28. package/dist/audits/audit.js.map +1 -0
  29. package/dist/audits/content-chunking/chunk-token-density.d.ts +10 -0
  30. package/dist/audits/content-chunking/chunk-token-density.d.ts.map +1 -0
  31. package/dist/audits/content-chunking/chunk-token-density.js +44 -0
  32. package/dist/audits/content-chunking/chunk-token-density.js.map +1 -0
  33. package/dist/audits/content-chunking/heading-hierarchy.d.ts +10 -0
  34. package/dist/audits/content-chunking/heading-hierarchy.d.ts.map +1 -0
  35. package/dist/audits/content-chunking/heading-hierarchy.js +54 -0
  36. package/dist/audits/content-chunking/heading-hierarchy.js.map +1 -0
  37. package/dist/audits/content-chunking/semantic-containers.d.ts +10 -0
  38. package/dist/audits/content-chunking/semantic-containers.d.ts.map +1 -0
  39. package/dist/audits/content-chunking/semantic-containers.js +34 -0
  40. package/dist/audits/content-chunking/semantic-containers.js.map +1 -0
  41. package/dist/audits/direct-answer-density/concise-answer-wordcount.d.ts +10 -0
  42. package/dist/audits/direct-answer-density/concise-answer-wordcount.d.ts.map +1 -0
  43. package/dist/audits/direct-answer-density/concise-answer-wordcount.js +42 -0
  44. package/dist/audits/direct-answer-density/concise-answer-wordcount.js.map +1 -0
  45. package/dist/audits/direct-answer-density/direct-definition-answering.d.ts +10 -0
  46. package/dist/audits/direct-answer-density/direct-definition-answering.d.ts.map +1 -0
  47. package/dist/audits/direct-answer-density/direct-definition-answering.js +43 -0
  48. package/dist/audits/direct-answer-density/direct-definition-answering.js.map +1 -0
  49. package/dist/audits/direct-answer-density/question-heading-alignment.d.ts +10 -0
  50. package/dist/audits/direct-answer-density/question-heading-alignment.d.ts.map +1 -0
  51. package/dist/audits/direct-answer-density/question-heading-alignment.js +35 -0
  52. package/dist/audits/direct-answer-density/question-heading-alignment.js.map +1 -0
  53. package/dist/audits/index.d.ts +19 -0
  54. package/dist/audits/index.d.ts.map +1 -0
  55. package/dist/audits/index.js +36 -0
  56. package/dist/audits/index.js.map +1 -0
  57. package/dist/audits/structured-data/entity-sameas-links.d.ts +10 -0
  58. package/dist/audits/structured-data/entity-sameas-links.d.ts.map +1 -0
  59. package/dist/audits/structured-data/entity-sameas-links.js +43 -0
  60. package/dist/audits/structured-data/entity-sameas-links.js.map +1 -0
  61. package/dist/audits/structured-data/jsonld-syntax-validity.d.ts +10 -0
  62. package/dist/audits/structured-data/jsonld-syntax-validity.d.ts.map +1 -0
  63. package/dist/audits/structured-data/jsonld-syntax-validity.js +43 -0
  64. package/dist/audits/structured-data/jsonld-syntax-validity.js.map +1 -0
  65. package/dist/audits/structured-data/rag-schema-presence.d.ts +10 -0
  66. package/dist/audits/structured-data/rag-schema-presence.d.ts.map +1 -0
  67. package/dist/audits/structured-data/rag-schema-presence.js +48 -0
  68. package/dist/audits/structured-data/rag-schema-presence.js.map +1 -0
  69. package/dist/config/default-config.d.ts +7 -0
  70. package/dist/config/default-config.d.ts.map +1 -0
  71. package/dist/config/default-config.js +71 -0
  72. package/dist/config/default-config.js.map +1 -0
  73. package/dist/gather/driver/cheerio-driver.d.ts +27 -0
  74. package/dist/gather/driver/cheerio-driver.d.ts.map +1 -0
  75. package/dist/gather/driver/cheerio-driver.js +64 -0
  76. package/dist/gather/driver/cheerio-driver.js.map +1 -0
  77. package/dist/gather/gatherer.d.ts +12 -0
  78. package/dist/gather/gatherer.d.ts.map +1 -0
  79. package/dist/gather/gatherer.js +6 -0
  80. package/dist/gather/gatherer.js.map +1 -0
  81. package/dist/gather/gatherers/content-chunks-gatherer.d.ts +10 -0
  82. package/dist/gather/gatherers/content-chunks-gatherer.d.ts.map +1 -0
  83. package/dist/gather/gatherers/content-chunks-gatherer.js +100 -0
  84. package/dist/gather/gatherers/content-chunks-gatherer.js.map +1 -0
  85. package/dist/gather/gatherers/direct-answers-gatherer.d.ts +10 -0
  86. package/dist/gather/gatherers/direct-answers-gatherer.d.ts.map +1 -0
  87. package/dist/gather/gatherers/direct-answers-gatherer.js +58 -0
  88. package/dist/gather/gatherers/direct-answers-gatherer.js.map +1 -0
  89. package/dist/gather/gatherers/headings-hierarchy-gatherer.d.ts +10 -0
  90. package/dist/gather/gatherers/headings-hierarchy-gatherer.d.ts.map +1 -0
  91. package/dist/gather/gatherers/headings-hierarchy-gatherer.js +60 -0
  92. package/dist/gather/gatherers/headings-hierarchy-gatherer.js.map +1 -0
  93. package/dist/gather/gatherers/http-headers-gatherer.d.ts +10 -0
  94. package/dist/gather/gatherers/http-headers-gatherer.d.ts.map +1 -0
  95. package/dist/gather/gatherers/http-headers-gatherer.js +25 -0
  96. package/dist/gather/gatherers/http-headers-gatherer.js.map +1 -0
  97. package/dist/gather/gatherers/jsonld-gatherer.d.ts +11 -0
  98. package/dist/gather/gatherers/jsonld-gatherer.d.ts.map +1 -0
  99. package/dist/gather/gatherers/jsonld-gatherer.js +110 -0
  100. package/dist/gather/gatherers/jsonld-gatherer.js.map +1 -0
  101. package/dist/gather/gatherers/meta-tags-gatherer.d.ts +10 -0
  102. package/dist/gather/gatherers/meta-tags-gatherer.d.ts.map +1 -0
  103. package/dist/gather/gatherers/meta-tags-gatherer.js +45 -0
  104. package/dist/gather/gatherers/meta-tags-gatherer.js.map +1 -0
  105. package/dist/gather/gatherers/robots-txt-gatherer.d.ts +12 -0
  106. package/dist/gather/gatherers/robots-txt-gatherer.d.ts.map +1 -0
  107. package/dist/gather/gatherers/robots-txt-gatherer.js +139 -0
  108. package/dist/gather/gatherers/robots-txt-gatherer.js.map +1 -0
  109. package/dist/gather/gatherers/url-gatherer.d.ts +10 -0
  110. package/dist/gather/gatherers/url-gatherer.d.ts.map +1 -0
  111. package/dist/gather/gatherers/url-gatherer.js +19 -0
  112. package/dist/gather/gatherers/url-gatherer.js.map +1 -0
  113. package/dist/gather/index.d.ts +14 -0
  114. package/dist/gather/index.d.ts.map +1 -0
  115. package/dist/gather/index.js +14 -0
  116. package/dist/gather/index.js.map +1 -0
  117. package/dist/index.d.ts +11 -0
  118. package/dist/index.d.ts.map +1 -0
  119. package/dist/index.js +11 -0
  120. package/dist/index.js.map +1 -0
  121. package/dist/report/html-reporter.d.ts +11 -0
  122. package/dist/report/html-reporter.d.ts.map +1 -0
  123. package/dist/report/html-reporter.js +285 -0
  124. package/dist/report/html-reporter.js.map +1 -0
  125. package/dist/report/index.d.ts +6 -0
  126. package/dist/report/index.d.ts.map +1 -0
  127. package/dist/report/index.js +6 -0
  128. package/dist/report/index.js.map +1 -0
  129. package/dist/report/terminal-reporter.d.ts +8 -0
  130. package/dist/report/terminal-reporter.d.ts.map +1 -0
  131. package/dist/report/terminal-reporter.js +50 -0
  132. package/dist/report/terminal-reporter.js.map +1 -0
  133. package/dist/runner/aggregator.d.ts +17 -0
  134. package/dist/runner/aggregator.d.ts.map +1 -0
  135. package/dist/runner/aggregator.js +59 -0
  136. package/dist/runner/aggregator.js.map +1 -0
  137. package/dist/runner/runner.d.ts +29 -0
  138. package/dist/runner/runner.d.ts.map +1 -0
  139. package/dist/runner/runner.js +125 -0
  140. package/dist/runner/runner.js.map +1 -0
  141. package/dist/types/artifacts.d.ts +188 -0
  142. package/dist/types/artifacts.d.ts.map +1 -0
  143. package/dist/types/artifacts.js +7 -0
  144. package/dist/types/artifacts.js.map +1 -0
  145. package/dist/types/audit.d.ts +122 -0
  146. package/dist/types/audit.d.ts.map +1 -0
  147. package/dist/types/audit.js +6 -0
  148. package/dist/types/audit.js.map +1 -0
  149. package/dist/types/config.d.ts +74 -0
  150. package/dist/types/config.d.ts.map +1 -0
  151. package/dist/types/config.js +5 -0
  152. package/dist/types/config.js.map +1 -0
  153. package/dist/types/gatherer.d.ts +32 -0
  154. package/dist/types/gatherer.d.ts.map +1 -0
  155. package/dist/types/gatherer.js +5 -0
  156. package/dist/types/gatherer.js.map +1 -0
  157. package/dist/types/index.d.ts +8 -0
  158. package/dist/types/index.d.ts.map +1 -0
  159. package/dist/types/index.js +8 -0
  160. package/dist/types/index.js.map +1 -0
  161. package/package.json +54 -0
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=audit-contract.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-contract.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/audit-contract.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,120 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { Audit } from '../audits/audit.js';
3
+ import { defaultConfig } from '../config/default-config.js';
4
+ class MockRobotsAudit extends Audit {
5
+ static meta = {
6
+ id: 'ai-robots-txt',
7
+ title: 'Robots.txt permite acceso a bots de IA',
8
+ failureTitle: 'Robots.txt bloquea rastreadores de IA',
9
+ description: 'Verifica directivas para GPTBot, PerplexityBot, etc.',
10
+ requiredArtifacts: ['RobotsTxt'],
11
+ };
12
+ static async audit(artifacts) {
13
+ const isAllowed = artifacts.RobotsTxt.aiBotsStatus.gptBot === 'allowed';
14
+ return this.generateAuditResult({
15
+ score: this.binaryScore(isAllowed),
16
+ displayValue: isAllowed ? 'GPTBot permitido' : 'GPTBot bloqueado',
17
+ details: this.makeTableDetails([
18
+ { key: 'bot', label: 'Bot de IA' },
19
+ { key: 'status', label: 'Estado' },
20
+ ], [{ bot: 'GPTBot', status: artifacts.RobotsTxt.aiBotsStatus.gptBot }]),
21
+ });
22
+ }
23
+ }
24
+ describe('AEO Linter Core Contracts (Lighthouse Architecture)', () => {
25
+ it('debe definir las 4 categorías clave de AEO con ponderaciones', () => {
26
+ const categories = Object.keys(defaultConfig.categories);
27
+ expect(categories).toContain('ai-accessibility');
28
+ expect(categories).toContain('structured-data');
29
+ expect(categories).toContain('content-chunking');
30
+ expect(categories).toContain('direct-answer-density');
31
+ // Verificar que la suma de pesos de categorías principales sea 100%
32
+ const totalWeight = Object.values(defaultConfig.categories).reduce((sum, cat) => sum + (cat.weight || 0), 0);
33
+ expect(totalWeight).toBe(100);
34
+ });
35
+ it('debe ejecutar una auditoría mock derivada de Audit y generar un AuditResult válido', async () => {
36
+ const mockArtifacts = {
37
+ URL: {
38
+ requestedUrl: 'https://example.com',
39
+ finalUrl: 'https://example.com',
40
+ domain: 'example.com',
41
+ pathname: '/',
42
+ protocol: 'https:',
43
+ },
44
+ RobotsTxt: {
45
+ rawContent: 'User-agent: GPTBot\nAllow: /',
46
+ statusCode: 200,
47
+ exists: true,
48
+ sitemaps: ['https://example.com/sitemap.xml'],
49
+ rulesByAgent: {
50
+ gptbot: { userAgent: 'GPTBot', allow: ['/'], disallow: [] },
51
+ },
52
+ aiBotsStatus: {
53
+ gptBot: 'allowed',
54
+ },
55
+ },
56
+ HttpHeaders: {
57
+ statusCode: 200,
58
+ headers: {},
59
+ xRobotsTag: null,
60
+ contentType: 'text/html',
61
+ cacheControl: null,
62
+ contentEncoding: null,
63
+ },
64
+ JSONLD: {
65
+ items: [],
66
+ schemasCountByType: {},
67
+ hasFAQPage: false,
68
+ hasHowTo: false,
69
+ hasArticle: false,
70
+ hasQAPage: false,
71
+ hasOrganization: false,
72
+ hasProduct: false,
73
+ hasSameAs: false,
74
+ sameAsUrls: [],
75
+ },
76
+ MetaTags: {
77
+ title: 'Ejemplo AEO',
78
+ description: 'Meta descripción optimizada',
79
+ canonicalUrl: 'https://example.com',
80
+ viewport: 'width=device-width',
81
+ charset: 'utf-8',
82
+ openGraph: {},
83
+ twitterCard: {},
84
+ robotsMeta: null,
85
+ },
86
+ HeadingsHierarchy: {
87
+ headings: [{ level: 1, text: 'Título H1', index: 0 }],
88
+ h1Count: 1,
89
+ h2Count: 0,
90
+ h3Count: 0,
91
+ hasSingleH1: true,
92
+ isHierarchySequential: true,
93
+ skippedLevels: [],
94
+ },
95
+ ContentChunks: {
96
+ chunks: [],
97
+ totalWordCount: 0,
98
+ totalEstimatedTokens: 0,
99
+ averageChunkTokenCount: 0,
100
+ semanticTagsUsed: ['main'],
101
+ hasSemanticMain: true,
102
+ hasSemanticArticle: false,
103
+ hasSemanticSections: false,
104
+ },
105
+ DirectAnswers: {
106
+ pairs: [],
107
+ directAnswerRatio: 0,
108
+ conciseAnswersCount: 0,
109
+ definitionPatternsFound: 0,
110
+ },
111
+ };
112
+ const result = await MockRobotsAudit.audit(mockArtifacts);
113
+ expect(result.id).toBe('ai-robots-txt');
114
+ expect(result.score).toBe(1);
115
+ expect(result.scoreDisplayMode).toBe('binary');
116
+ expect(result.displayValue).toBe('GPTBot permitido');
117
+ expect(result.details?.type).toBe('table');
118
+ });
119
+ });
120
+ //# sourceMappingURL=audit-contract.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-contract.test.js","sourceRoot":"","sources":["../../src/__tests__/audit-contract.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=gatherers.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gatherers.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/gatherers.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,139 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { CheerioDriver } from '../gather/driver/cheerio-driver.js';
3
+ import { RobotsTxtGatherer } from '../gather/gatherers/robots-txt-gatherer.js';
4
+ import { JSONLDGatherer } from '../gather/gatherers/jsonld-gatherer.js';
5
+ import { HeadingsHierarchyGatherer } from '../gather/gatherers/headings-hierarchy-gatherer.js';
6
+ import { DirectAnswersGatherer } from '../gather/gatherers/direct-answers-gatherer.js';
7
+ describe('Gatherers Pipeline', () => {
8
+ it('RobotsTxtGatherer parsea directivas de AI bots correctamente', async () => {
9
+ const mockRobotsContent = `
10
+ User-agent: GPTBot
11
+ Disallow: /private/
12
+ Allow: /
13
+
14
+ User-agent: PerplexityBot
15
+ Disallow: /
16
+
17
+ User-agent: *
18
+ Allow: /
19
+
20
+ Sitemap: https://example.com/sitemap.xml
21
+ `;
22
+ const mockDriver = new CheerioDriver({
23
+ url: 'https://example.com/test',
24
+ html: '<html><body>Hello</body></html>',
25
+ });
26
+ // Mock fetch for robots.txt
27
+ mockDriver.fetch = async () => new Response(mockRobotsContent, {
28
+ status: 200,
29
+ headers: { 'content-type': 'text/plain' },
30
+ });
31
+ const gatherer = new RobotsTxtGatherer();
32
+ const artifact = await gatherer.getArtifact({
33
+ url: 'https://example.com/test',
34
+ driver: mockDriver,
35
+ });
36
+ expect(artifact.exists).toBe(true);
37
+ expect(artifact.sitemaps).toContain('https://example.com/sitemap.xml');
38
+ expect(artifact.aiBotsStatus.gptBot).toBe('allowed');
39
+ expect(artifact.aiBotsStatus.perplexityBot).toBe('disallowed');
40
+ });
41
+ it('JSONLDGatherer extrae tipos de esquemas y sameAs', async () => {
42
+ const html = `
43
+ <!DOCTYPE html>
44
+ <html>
45
+ <head>
46
+ <script type="application/ld+json">
47
+ {
48
+ "@context": "https://schema.org",
49
+ "@type": "FAQPage",
50
+ "mainEntity": [{
51
+ "@type": "Question",
52
+ "name": "¿Qué es AEO?",
53
+ "acceptedAnswer": {
54
+ "@type": "Answer",
55
+ "text": "AEO es la optimización para motores de respuesta."
56
+ }
57
+ }]
58
+ }
59
+ </script>
60
+ <script type="application/ld+json">
61
+ {
62
+ "@context": "https://schema.org",
63
+ "@type": "Organization",
64
+ "name": "AEO Corp",
65
+ "sameAs": [
66
+ "https://www.wikidata.org/wiki/Q12345",
67
+ "https://twitter.com/aeocorp"
68
+ ]
69
+ }
70
+ </script>
71
+ </head>
72
+ <body></body>
73
+ </html>
74
+ `;
75
+ const mockDriver = new CheerioDriver({
76
+ url: 'https://example.com',
77
+ html,
78
+ });
79
+ const gatherer = new JSONLDGatherer();
80
+ const artifact = await gatherer.getArtifact({
81
+ url: 'https://example.com',
82
+ driver: mockDriver,
83
+ });
84
+ expect(artifact.items.length).toBe(2);
85
+ expect(artifact.hasFAQPage).toBe(true);
86
+ expect(artifact.hasOrganization).toBe(true);
87
+ expect(artifact.hasSameAs).toBe(true);
88
+ expect(artifact.sameAsUrls).toContain('https://www.wikidata.org/wiki/Q12345');
89
+ });
90
+ it('HeadingsHierarchyGatherer detecta jerarquías y saltos de nivel', async () => {
91
+ const html = `
92
+ <html>
93
+ <body>
94
+ <h1>Título Principal</h1>
95
+ <h3>Salto brusco H3 sin H2</h3>
96
+ <h2>Ahora un H2</h2>
97
+ </body>
98
+ </html>
99
+ `;
100
+ const mockDriver = new CheerioDriver({
101
+ url: 'https://example.com',
102
+ html,
103
+ });
104
+ const gatherer = new HeadingsHierarchyGatherer();
105
+ const artifact = await gatherer.getArtifact({
106
+ url: 'https://example.com',
107
+ driver: mockDriver,
108
+ });
109
+ expect(artifact.h1Count).toBe(1);
110
+ expect(artifact.hasSingleH1).toBe(true);
111
+ expect(artifact.isHierarchySequential).toBe(false);
112
+ expect(artifact.skippedLevels.length).toBe(1);
113
+ expect(artifact.skippedLevels[0]?.from).toBe(1);
114
+ expect(artifact.skippedLevels[0]?.to).toBe(3);
115
+ });
116
+ it('DirectAnswersGatherer detecta preguntas y respuestas directas concisas', async () => {
117
+ const html = `
118
+ <html>
119
+ <body>
120
+ <h2>¿Qué es Answer Engine Optimization?</h2>
121
+ <p>Answer Engine Optimization es un conjunto de técnicas de arquitectura web y datos estructurados orientadas a maximizar la visibilidad en motores de IA generativa y sistemas RAG.</p>
122
+ </body>
123
+ </html>
124
+ `;
125
+ const mockDriver = new CheerioDriver({
126
+ url: 'https://example.com',
127
+ html,
128
+ });
129
+ const gatherer = new DirectAnswersGatherer();
130
+ const artifact = await gatherer.getArtifact({
131
+ url: 'https://example.com',
132
+ driver: mockDriver,
133
+ });
134
+ expect(artifact.pairs.length).toBe(1);
135
+ expect(artifact.pairs[0]?.hasDirectDefinition).toBe(true);
136
+ expect(artifact.pairs[0]?.isConcise).toBe(true);
137
+ });
138
+ });
139
+ //# sourceMappingURL=gatherers.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gatherers.test.js","sourceRoot":"","sources":["../../src/__tests__/gatherers.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AACxE,OAAO,EAAE,yBAAyB,EAAE,MAAM,oDAAoD,CAAC;AAE/F,OAAO,EAAE,qBAAqB,EAAE,MAAM,gDAAgD,CAAC;AAEvF,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;QAC5E,MAAM,iBAAiB,GAAG;;;;;;;;;;;;KAYzB,CAAC;QAEF,MAAM,UAAU,GAAG,IAAI,aAAa,CAAC;YACnC,GAAG,EAAE,0BAA0B;YAC/B,IAAI,EAAE,iCAAiC;SACxC,CAAC,CAAC;QAEH,4BAA4B;QAC5B,UAAU,CAAC,KAAK,GAAG,KAAK,IAAI,EAAE,CAC5B,IAAI,QAAQ,CAAC,iBAAiB,EAAE;YAC9B,MAAM,EAAE,GAAG;YACX,OAAO,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE;SAC1C,CAAC,CAAC;QAEL,MAAM,QAAQ,GAAG,IAAI,iBAAiB,EAAE,CAAC;QACzC,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC;YAC1C,GAAG,EAAE,0BAA0B;YAC/B,MAAM,EAAE,UAAU;SACnB,CAAC,CAAC;QAEH,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,iCAAiC,CAAC,CAAC;QACvE,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACrD,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAgCZ,CAAC;QAEF,MAAM,UAAU,GAAG,IAAI,aAAa,CAAC;YACnC,GAAG,EAAE,qBAAqB;YAC1B,IAAI;SACL,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,IAAI,cAAc,EAAE,CAAC;QACtC,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC;YAC1C,GAAG,EAAE,qBAAqB;YAC1B,MAAM,EAAE,UAAU;SACnB,CAAC,CAAC;QAEH,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5C,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,sCAAsC,CAAC,CAAC;IAChF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,KAAK,IAAI,EAAE;QAC9E,MAAM,IAAI,GAAG;;;;;;;;KAQZ,CAAC;QAEF,MAAM,UAAU,GAAG,IAAI,aAAa,CAAC;YACnC,GAAG,EAAE,qBAAqB;YAC1B,IAAI;SACL,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,IAAI,yBAAyB,EAAE,CAAC;QACjD,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC;YAC1C,GAAG,EAAE,qBAAqB;YAC1B,MAAM,EAAE,UAAU;SACnB,CAAC,CAAC;QAEH,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnD,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC9C,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChD,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wEAAwE,EAAE,KAAK,IAAI,EAAE;QACtF,MAAM,IAAI,GAAG;;;;;;;KAOZ,CAAC;QAEF,MAAM,UAAU,GAAG,IAAI,aAAa,CAAC;YACnC,GAAG,EAAE,qBAAqB;YAC1B,IAAI;SACL,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,IAAI,qBAAqB,EAAE,CAAC;QAC7C,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC;YAC1C,GAAG,EAAE,qBAAqB;YAC1B,MAAM,EAAE,UAAU;SACnB,CAAC,CAAC;QAEH,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1D,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=runner.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/runner.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,77 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { Runner } from '../runner/runner.js';
3
+ import { CheerioDriver } from '../gather/driver/cheerio-driver.js';
4
+ import { HtmlReporter } from '../report/html-reporter.js';
5
+ import { TerminalReporter } from '../report/terminal-reporter.js';
6
+ describe('Runner and Aggregator Full Pipeline', () => {
7
+ it('ejecuta el ciclo de vida completo de 3 fases y genera reportes', async () => {
8
+ const mockHtml = `
9
+ <!DOCTYPE html>
10
+ <html lang="es">
11
+ <head>
12
+ <title>AEO Testing Page</title>
13
+ <meta name="description" content="Página de prueba para linter AEO">
14
+ <script type="application/ld+json">
15
+ {
16
+ "@context": "https://schema.org",
17
+ "@type": "FAQPage",
18
+ "mainEntity": [{
19
+ "@type": "Question",
20
+ "name": "¿Qué es GEO?",
21
+ "acceptedAnswer": {
22
+ "@type": "Answer",
23
+ "text": "GEO es Generative Engine Optimization."
24
+ }
25
+ }]
26
+ }
27
+ </script>
28
+ <script type="application/ld+json">
29
+ {
30
+ "@context": "https://schema.org",
31
+ "@type": "Organization",
32
+ "name": "Acme AEO",
33
+ "sameAs": ["https://wikidata.org/wiki/Q999"]
34
+ }
35
+ </script>
36
+ </head>
37
+ <body>
38
+ <main>
39
+ <article>
40
+ <h1>Guía Completa de AEO</h1>
41
+ <h2>¿Qué es la densidad de respuestas directas?</h2>
42
+ <p>La densidad de respuestas directas es la proporción de consultas de usuario que reciben una definición clara y sintetizada en menos de 60 palabras al inicio de la sección temática.</p>
43
+
44
+ <h2>Estructuración Semántica para RAG</h2>
45
+ <p>Dividir el texto en bloques de 200 a 400 tokens optimiza la precisión de búsqueda semántica vectorial en modelos como OpenAI y Cohere.</p>
46
+ </article>
47
+ </main>
48
+ </body>
49
+ </html>
50
+ `;
51
+ const mockDriver = new CheerioDriver({
52
+ url: 'https://aeo-example.com/test',
53
+ html: mockHtml,
54
+ });
55
+ mockDriver.fetch = async () => new Response('User-agent: GPTBot\nAllow: /\nSitemap: https://aeo-example.com/sitemap.xml', {
56
+ status: 200,
57
+ });
58
+ const report = await Runner.run('https://aeo-example.com/test', {
59
+ driver: mockDriver,
60
+ });
61
+ expect(report.url).toBe('https://aeo-example.com/test');
62
+ expect(report.overallScore).toBeGreaterThan(70);
63
+ expect(report.categories['ai-accessibility']?.score).toBe(1);
64
+ expect(report.categories['structured-data']?.score).toBeGreaterThanOrEqual(0.8);
65
+ expect(report.categories['content-chunking']?.score).toBeGreaterThanOrEqual(0.8);
66
+ expect(report.categories['direct-answer-density']?.score).toBe(1);
67
+ // Verificar generación de reportes
68
+ const terminalOutput = TerminalReporter.generate(report);
69
+ expect(terminalOutput).toContain('Score General AEO');
70
+ expect(terminalOutput).toContain('AI Accessibility & Crawling');
71
+ const htmlOutput = HtmlReporter.generate(report);
72
+ expect(htmlOutput).toContain('<!DOCTYPE html>');
73
+ expect(htmlOutput).toContain('https://aeo-example.com/test');
74
+ expect(htmlOutput).toContain('gauge-container');
75
+ });
76
+ });
77
+ //# sourceMappingURL=runner.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.test.js","sourceRoot":"","sources":["../../src/__tests__/runner.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAElE,QAAQ,CAAC,qCAAqC,EAAE,GAAG,EAAE;IACnD,EAAE,CAAC,gEAAgE,EAAE,KAAK,IAAI,EAAE;QAC9E,MAAM,QAAQ,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA0ChB,CAAC;QAEF,MAAM,UAAU,GAAG,IAAI,aAAa,CAAC;YACnC,GAAG,EAAE,8BAA8B;YACnC,IAAI,EAAE,QAAQ;SACf,CAAC,CAAC;QAEH,UAAU,CAAC,KAAK,GAAG,KAAK,IAAI,EAAE,CAC5B,IAAI,QAAQ,CAAC,4EAA4E,EAAE;YACzF,MAAM,EAAE,GAAG;SACZ,CAAC,CAAC;QAEL,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,8BAA8B,EAAE;YAC9D,MAAM,EAAE,UAAU;SACnB,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;QACxD,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;QAChD,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC7D,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE,KAAK,CAAC,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAC;QAChF,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,KAAK,CAAC,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAC;QACjF,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,uBAAuB,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAElE,mCAAmC;QACnC,MAAM,cAAc,GAAG,gBAAgB,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACzD,MAAM,CAAC,cAAc,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;QACtD,MAAM,CAAC,cAAc,CAAC,CAAC,SAAS,CAAC,6BAA6B,CAAC,CAAC;QAEhE,MAAM,UAAU,GAAG,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACjD,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAChD,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,8BAA8B,CAAC,CAAC;QAC7D,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @fileoverview Auditoría para verificar la declaración de Sitemaps accesibles
3
+ */
4
+ import { Audit } from '../audit.js';
5
+ import type { Artifacts, AuditMeta, AuditResult } from '../../types/index.js';
6
+ export declare class AiBotSitemapAudit extends Audit {
7
+ static meta: AuditMeta;
8
+ static audit(artifacts: Artifacts): Promise<AuditResult>;
9
+ }
10
+ //# sourceMappingURL=ai-bot-sitemap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-bot-sitemap.d.ts","sourceRoot":"","sources":["../../../src/audits/ai-accessibility/ai-bot-sitemap.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAE9E,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,OAAuB,IAAI,EAAE,SAAS,CAOpC;WAE2B,KAAK,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;CAc/E"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @fileoverview Auditoría para verificar la declaración de Sitemaps accesibles
3
+ */
4
+ import { Audit } from '../audit.js';
5
+ export class AiBotSitemapAudit extends Audit {
6
+ static meta = {
7
+ id: 'ai-bot-sitemap',
8
+ title: 'El archivo robots.txt declara Sitemaps XML válidos',
9
+ failureTitle: 'No se encontraron declaraciones de Sitemap en robots.txt',
10
+ description: 'Los Sitemaps XML permiten a los rastreadores de Answer Engines descubrir URLs profundas y estructuradas con alta eficiencia de rastreo.',
11
+ requiredArtifacts: ['RobotsTxt'],
12
+ };
13
+ static async audit(artifacts) {
14
+ const sitemaps = artifacts.RobotsTxt.sitemaps;
15
+ const hasSitemap = sitemaps.length > 0;
16
+ return this.generateAuditResult({
17
+ score: hasSitemap ? 1 : 0.5,
18
+ displayValue: hasSitemap
19
+ ? `${sitemaps.length} sitemap(s) declarados`
20
+ : 'Ningún sitemap declarado en robots.txt',
21
+ details: hasSitemap
22
+ ? this.makeListDetails(sitemaps)
23
+ : undefined,
24
+ });
25
+ }
26
+ }
27
+ //# sourceMappingURL=ai-bot-sitemap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-bot-sitemap.js","sourceRoot":"","sources":["../../../src/audits/ai-accessibility/ai-bot-sitemap.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAGpC,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACnC,MAAM,CAAU,IAAI,GAAc;QACvC,EAAE,EAAE,gBAAgB;QACpB,KAAK,EAAE,oDAAoD;QAC3D,YAAY,EAAE,0DAA0D;QACxE,WAAW,EACT,yIAAyI;QAC3I,iBAAiB,EAAE,CAAC,WAAW,CAAC;KACjC,CAAC;IAEK,MAAM,CAAU,KAAK,CAAC,KAAK,CAAC,SAAoB;QACrD,MAAM,QAAQ,GAAG,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC;QAC9C,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;QAEvC,OAAO,IAAI,CAAC,mBAAmB,CAAC;YAC9B,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;YAC3B,YAAY,EAAE,UAAU;gBACtB,CAAC,CAAC,GAAG,QAAQ,CAAC,MAAM,wBAAwB;gBAC5C,CAAC,CAAC,wCAAwC;YAC5C,OAAO,EAAE,UAAU;gBACjB,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC;gBAChC,CAAC,CAAC,SAAS;SACd,CAAC,CAAC;IACL,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @fileoverview Auditoría que verifica el acceso permitido a rastreadores de IA en robots.txt
3
+ */
4
+ import { Audit } from '../audit.js';
5
+ import type { Artifacts, AuditMeta, AuditResult } from '../../types/index.js';
6
+ export declare class AiRobotsTxtAudit extends Audit {
7
+ static meta: AuditMeta;
8
+ static audit(artifacts: Artifacts): Promise<AuditResult>;
9
+ }
10
+ //# sourceMappingURL=ai-robots-txt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-robots-txt.d.ts","sourceRoot":"","sources":["../../../src/audits/ai-accessibility/ai-robots-txt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAE9E,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,OAAuB,IAAI,EAAE,SAAS,CAOpC;WAE2B,KAAK,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;CAgD/E"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * @fileoverview Auditoría que verifica el acceso permitido a rastreadores de IA en robots.txt
3
+ */
4
+ import { Audit } from '../audit.js';
5
+ export class AiRobotsTxtAudit extends Audit {
6
+ static meta = {
7
+ id: 'ai-robots-txt',
8
+ title: 'El archivo robots.txt permite el rastreo de los principales bots de IA',
9
+ failureTitle: 'El archivo robots.txt bloquea o restringe a rastreadores de IA',
10
+ description: 'Los Answer Engines y sistemas RAG (ChatGPT/SearchGPT, Perplexity, Claude, Gemini) utilizan crawlers dedicados como GPTBot, PerplexityBot y ClaudeBot para indexar y citar fuentes actualizadas.',
11
+ requiredArtifacts: ['RobotsTxt'],
12
+ };
13
+ static async audit(artifacts) {
14
+ const robots = artifacts.RobotsTxt;
15
+ if (!robots.exists || !robots.rawContent) {
16
+ // Si no existe robots.txt, por estándar todos los bots tienen permitido el acceso total
17
+ return this.generateAuditResult({
18
+ score: 1,
19
+ displayValue: 'Robots.txt no restringe el acceso (acceso libre)',
20
+ explanation: 'No se encontró archivo robots.txt restrictivo, por lo que los bots de IA pueden acceder al contenido.',
21
+ });
22
+ }
23
+ const aiBots = [
24
+ { id: 'GPTBot', name: 'OpenAI (SearchGPT/ChatGPT)', status: robots.aiBotsStatus.gptBot || 'not_specified' },
25
+ { id: 'PerplexityBot', name: 'Perplexity AI', status: robots.aiBotsStatus.perplexityBot || 'not_specified' },
26
+ { id: 'ClaudeBot', name: 'Anthropic Claude', status: robots.aiBotsStatus.claudeBot || 'not_specified' },
27
+ { id: 'Google-Extended', name: 'Google Gemini / Vertex', status: robots.aiBotsStatus.googleExtended || 'not_specified' },
28
+ { id: 'CCBot', name: 'Common Crawl (Dataset Open Source)', status: robots.aiBotsStatus.ccBot || 'not_specified' },
29
+ { id: 'Bytespider', name: 'ByteDance / Doubao', status: robots.aiBotsStatus.bytespider || 'not_specified' },
30
+ ];
31
+ let allowedCount = 0;
32
+ const tableItems = aiBots.map((bot) => {
33
+ const isAllowed = bot.status === 'allowed' || bot.status === 'not_specified';
34
+ if (isAllowed)
35
+ allowedCount++;
36
+ return {
37
+ bot: bot.id,
38
+ purpose: bot.name,
39
+ status: bot.status === 'disallowed' ? 'Bloqueado (Disallow)' : bot.status === 'partially_disallowed' ? 'Parcialmente restringido' : 'Permitido',
40
+ };
41
+ });
42
+ const score = allowedCount / aiBots.length;
43
+ return this.generateAuditResult({
44
+ score: score >= 0.8 ? 1 : score,
45
+ displayValue: `${allowedCount} de ${aiBots.length} bots de IA con acceso permitido`,
46
+ details: this.makeTableDetails([
47
+ { key: 'bot', label: 'User-Agent', valueType: 'code' },
48
+ { key: 'purpose', label: 'Plataforma / Motor', valueType: 'text' },
49
+ { key: 'status', label: 'Directiva', valueType: 'status' },
50
+ ], tableItems),
51
+ });
52
+ }
53
+ }
54
+ //# sourceMappingURL=ai-robots-txt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-robots-txt.js","sourceRoot":"","sources":["../../../src/audits/ai-accessibility/ai-robots-txt.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @fileoverview Auditoría que verifica las cabeceras HTTP X-Robots-Tag para indexación por IA
3
+ */
4
+ import { Audit } from '../audit.js';
5
+ import type { Artifacts, AuditMeta, AuditResult } from '../../types/index.js';
6
+ export declare class AiXRobotsTagAudit extends Audit {
7
+ static meta: AuditMeta;
8
+ static audit(artifacts: Artifacts): Promise<AuditResult>;
9
+ }
10
+ //# sourceMappingURL=ai-x-robots-tag.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-x-robots-tag.d.ts","sourceRoot":"","sources":["../../../src/audits/ai-accessibility/ai-x-robots-tag.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAE9E,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,OAAuB,IAAI,EAAE,SAAS,CAOpC;WAE2B,KAAK,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;CA0B/E"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @fileoverview Auditoría que verifica las cabeceras HTTP X-Robots-Tag para indexación por IA
3
+ */
4
+ import { Audit } from '../audit.js';
5
+ export class AiXRobotsTagAudit extends Audit {
6
+ static meta = {
7
+ id: 'ai-x-robots-tag',
8
+ title: 'Las cabeceras HTTP no bloquean la indexación ni el archivo de IA',
9
+ failureTitle: 'Las cabeceras HTTP X-Robots-Tag restringen la indexación',
10
+ description: 'Directivas como `noindex`, `noarchive` o `noai` en la cabecera HTTP `X-Robots-Tag` impiden que los motores de IA almacenen en caché y procesen la página en sus pipelines de recuperación.',
11
+ requiredArtifacts: ['HttpHeaders'],
12
+ };
13
+ static async audit(artifacts) {
14
+ const xRobots = artifacts.HttpHeaders.xRobotsTag;
15
+ if (!xRobots) {
16
+ return this.generateAuditResult({
17
+ score: 1,
18
+ displayValue: 'Cabecera X-Robots-Tag limpia (sin restricciones)',
19
+ });
20
+ }
21
+ const lower = xRobots.toLowerCase();
22
+ const blockingDirectives = ['noindex', 'none', 'noarchive', 'noai'];
23
+ const foundBlocking = blockingDirectives.filter((d) => lower.includes(d));
24
+ const isBlocked = foundBlocking.length > 0;
25
+ return this.generateAuditResult({
26
+ score: isBlocked ? 0 : 1,
27
+ displayValue: isBlocked
28
+ ? `Directivas bloqueantes encontradas: ${foundBlocking.join(', ')}`
29
+ : `Directivas permisivas: ${xRobots}`,
30
+ explanation: isBlocked
31
+ ? `Se detectó '${xRobots}' en la cabecera X-Robots-Tag, lo cual impide el análisis por modelos de lenguaje.`
32
+ : undefined,
33
+ });
34
+ }
35
+ }
36
+ //# sourceMappingURL=ai-x-robots-tag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-x-robots-tag.js","sourceRoot":"","sources":["../../../src/audits/ai-accessibility/ai-x-robots-tag.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAGpC,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACnC,MAAM,CAAU,IAAI,GAAc;QACvC,EAAE,EAAE,iBAAiB;QACrB,KAAK,EAAE,kEAAkE;QACzE,YAAY,EAAE,0DAA0D;QACxE,WAAW,EACT,4LAA4L;QAC9L,iBAAiB,EAAE,CAAC,aAAa,CAAC;KACnC,CAAC;IAEK,MAAM,CAAU,KAAK,CAAC,KAAK,CAAC,SAAoB;QACrD,MAAM,OAAO,GAAG,SAAS,CAAC,WAAW,CAAC,UAAU,CAAC;QAEjD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,mBAAmB,CAAC;gBAC9B,KAAK,EAAE,CAAC;gBACR,YAAY,EAAE,kDAAkD;aACjE,CAAC,CAAC;QACL,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;QACpC,MAAM,kBAAkB,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;QACpE,MAAM,aAAa,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QAE1E,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC;QAE3C,OAAO,IAAI,CAAC,mBAAmB,CAAC;YAC9B,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACxB,YAAY,EAAE,SAAS;gBACrB,CAAC,CAAC,uCAAuC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;gBACnE,CAAC,CAAC,0BAA0B,OAAO,EAAE;YACvC,WAAW,EAAE,SAAS;gBACpB,CAAC,CAAC,eAAe,OAAO,oFAAoF;gBAC5G,CAAC,CAAC,SAAS;SACd,CAAC,CAAC;IACL,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @fileoverview Clase base abstracta Audit y utilidades de resultado, siguiendo el diseño de Google Lighthouse.
3
+ * Cada auditoría concreta hereda de Audit e implementa su método estático `audit()` como una función pura
4
+ * que evalúa los artefactos requeridos y produce un `AuditResult`.
5
+ */
6
+ import type { Artifacts, AuditResult, AuditMeta, AuditContext, AuditDetails, TableHeading, TableDetails, ListDetails, ScoreDisplayMode } from '../types/index.js';
7
+ export declare abstract class Audit {
8
+ /**
9
+ * Metadatos estáticos de la auditoría.
10
+ * Debe ser sobrescrito por cada subclase de auditoría concreta.
11
+ */
12
+ static meta: AuditMeta;
13
+ /**
14
+ * Método puro de ejecución de la auditoría.
15
+ * @param artifacts Artefactos inmutables recolectados por los Gatherers
16
+ * @param context Contexto de ejecución opcional
17
+ */
18
+ static audit(artifacts: Artifacts, context?: AuditContext): Promise<AuditResult>;
19
+ /**
20
+ * Helper para generar un resultado de auditoría consistente
21
+ */
22
+ static generateAuditResult(options: {
23
+ id?: string;
24
+ score: number | null;
25
+ scoreDisplayMode?: ScoreDisplayMode;
26
+ title?: string;
27
+ description?: string;
28
+ numericValue?: number;
29
+ numericUnit?: string;
30
+ displayValue?: string;
31
+ explanation?: string;
32
+ errorMessage?: string;
33
+ details?: AuditDetails;
34
+ warnings?: string[];
35
+ }): AuditResult;
36
+ /**
37
+ * Helper para construir un detalle de tipo tabla (Lighthouse TableDetails)
38
+ */
39
+ static makeTableDetails(headings: TableHeading[], items: Array<Record<string, unknown>>, summary?: TableDetails['summary']): TableDetails;
40
+ /**
41
+ * Helper para construir un detalle de tipo lista
42
+ */
43
+ static makeListDetails(items: Array<string | {
44
+ text: string;
45
+ subItems?: string[];
46
+ }>): ListDetails;
47
+ /**
48
+ * Helper para calcular puntaje binario
49
+ */
50
+ static binaryScore(condition: boolean): number;
51
+ /**
52
+ * Helper para calcular puntaje normalizado lineal o acotado
53
+ */
54
+ static clampScore(value: number, min?: number, max?: number): number;
55
+ }
56
+ //# sourceMappingURL=audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/audits/audit.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,SAAS,EACT,WAAW,EACX,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,gBAAgB,EACjB,MAAM,mBAAmB,CAAC;AAE3B,8BAAsB,KAAK;IACzB;;;OAGG;IACH,OAAc,IAAI,EAAE,SAAS,CAAC;IAE9B;;;;OAIG;WACiB,KAAK,CACvB,SAAS,EAAE,SAAS,EACpB,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,WAAW,CAAC;IAIvB;;OAEG;WACW,mBAAmB,CAAC,OAAO,EAAE;QACzC,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;QACpC,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,OAAO,CAAC,EAAE,YAAY,CAAC;QACvB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,GAAG,WAAW;IAiCf;;OAEG;WACW,gBAAgB,CAC5B,QAAQ,EAAE,YAAY,EAAE,EACxB,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACrC,OAAO,CAAC,EAAE,YAAY,CAAC,SAAS,CAAC,GAChC,YAAY;IASf;;OAEG;WACW,eAAe,CAC3B,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,GAC3D,WAAW;IAOd;;OAEG;WACW,WAAW,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM;IAIrD;;OAEG;WACW,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,SAAI,EAAE,GAAG,SAAI,GAAG,MAAM;CAGlE"}