mcp-web-validator 1.3.18 → 1.3.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,14 @@ All notable changes to this project are documented here. The project follows [Se
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [1.3.19] - 2026-09-22
8
+
9
+ ### Fixed
10
+
11
+ - Preserved full Jigsaw CSS diagnostic totals and actionable/compatibility counts when local/package output is capped at 200 messages, with explicit truncation metadata/disclosure so validation-report summaries and heuristic scoring no longer undercount large result sets.
12
+ - Preserved full SEO/accessibility and JSON-LD severity counts when structured findings are capped at 200, exposing total/truncation metadata so standalone narration and validation-report summaries/scoring no longer undercount large audits.
13
+ - Decoded charset-less XML media types, including `application/xhtml+xml`, with XML-aware BOM, UTF-16 signature, and XML declaration encoding detection instead of silently treating non-UTF-8 XML as UTF-8.
14
+
7
15
  ## [1.3.18] - 2026-09-22
8
16
 
9
17
  ### Fixed
package/dist/index.d.ts CHANGED
@@ -1,17 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
- import { auditSeoMetadata, checkBrokenLinks, validateSchemaMarkup } from "./seo-auditor.js";
3
+ import { auditSeoMetadata, auditSeoMetadataDetailed, checkBrokenLinks, validateSchemaMarkup, validateSchemaMarkupDetailed } from "./seo-auditor.js";
4
4
  import { type ValidationReport } from "./report.js";
5
5
  import { readTextFile } from "./network.js";
6
- import { validateCssContent, validateHtmlContent, validateHtmlContentDetailed } from "./w3c-validator.js";
6
+ import { validateCssContent, validateCssContentDetailed, validateHtmlContent, validateHtmlContentDetailed } from "./w3c-validator.js";
7
7
  export declare const SERVER_VERSION: string;
8
8
  interface ValidationReportDependencies {
9
9
  readTextFile: typeof readTextFile;
10
10
  validateHtmlContent: typeof validateHtmlContent;
11
11
  validateHtmlContentDetailed?: typeof validateHtmlContentDetailed;
12
12
  validateCssContent: typeof validateCssContent;
13
+ validateCssContentDetailed?: typeof validateCssContentDetailed;
13
14
  auditSeoMetadata: typeof auditSeoMetadata;
15
+ auditSeoMetadataDetailed?: typeof auditSeoMetadataDetailed;
14
16
  validateSchemaMarkup: typeof validateSchemaMarkup;
17
+ validateSchemaMarkupDetailed?: typeof validateSchemaMarkupDetailed;
15
18
  checkBrokenLinks: typeof checkBrokenLinks;
16
19
  }
17
20
  export interface GenerateValidationReportOptions {
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ import { createValidationReport, validationReportChecks, } from "./report.js";
10
10
  import { fetchPublicText, getErrorMessage, readTextFile } from "./network.js";
11
11
  import { cssValidationContent, failureContent, htmlValidationContent, linkCheckContent, reportContent, schemaValidationContent, screenshotCaptureContent, seoAuditContent, } from "./presentation.js";
12
12
  import { PACKAGE_VERSION } from "./version.js";
13
- import { getW3CMessageSeverity, MAX_CSS_VALIDATION_BYTES, validateCssContent, validateHtmlContent, validateHtmlContentDetailed, } from "./w3c-validator.js";
13
+ import { getW3CMessageSeverity, MAX_CSS_VALIDATION_BYTES, validateCssContent, validateCssContentDetailed, validateHtmlContent, validateHtmlContentDetailed, } from "./w3c-validator.js";
14
14
  export const SERVER_VERSION = PACKAGE_VERSION;
15
15
  const HTML_MAX_BYTES = 2_000_000;
16
16
  const CSS_MAX_BYTES = MAX_CSS_VALIDATION_BYTES;
@@ -49,6 +49,11 @@ const seoIssueSchema = z.object({
49
49
  message: z.string(),
50
50
  element: z.string().optional(),
51
51
  });
52
+ const auditCountsSchema = z.object({
53
+ error: z.number().int().nonnegative(),
54
+ warning: z.number().int().nonnegative(),
55
+ info: z.number().int().nonnegative(),
56
+ });
52
57
  const linkStatusSchema = z.object({
53
58
  url: z.string(),
54
59
  status: z.union([z.number().int(), z.enum(["blocked", "failed"])]),
@@ -125,8 +130,14 @@ function failedReport(filePath, error) {
125
130
  htmlTotalMessages: 0,
126
131
  htmlTruncated: false,
127
132
  cssMessages: [],
133
+ cssTotalMessages: 0,
134
+ cssTruncated: false,
128
135
  seoIssues: [],
136
+ seoTotalIssues: 0,
137
+ seoTruncated: false,
129
138
  schemaIssues: [],
139
+ schemaTotalIssues: 0,
140
+ schemaTruncated: false,
130
141
  links: [],
131
142
  failedChecks: ["input"],
132
143
  errors: [`${path.basename(filePath || "document")}: ${error}`],
@@ -137,8 +148,11 @@ const validationReportDependencies = {
137
148
  validateHtmlContent,
138
149
  validateHtmlContentDetailed,
139
150
  validateCssContent,
151
+ validateCssContentDetailed,
140
152
  auditSeoMetadata,
153
+ auditSeoMetadataDetailed,
141
154
  validateSchemaMarkup,
155
+ validateSchemaMarkupDetailed,
142
156
  checkBrokenLinks,
143
157
  };
144
158
  /** Runs independent validation checks without discarding successful results when another check fails. */
@@ -169,11 +183,50 @@ export async function generateValidationReport({ htmlFilePath, cssFilePath, base
169
183
  counts[getW3CMessageSeverity(message)] += 1;
170
184
  return { messages, total: messages.length, truncated: false, counts };
171
185
  });
186
+ const cssValidation = css === undefined
187
+ ? Promise.resolve({
188
+ messages: [],
189
+ total: 0,
190
+ truncated: false,
191
+ counts: { error: 0, compatibilityLimitation: 0 },
192
+ })
193
+ : dependencies.validateCssContentDetailed
194
+ ? dependencies.validateCssContentDetailed(css)
195
+ : dependencies.validateCssContent(css).then((messages) => {
196
+ const compatibilityLimitation = messages.filter((message) => message.compatibility === "known-validator-limitation").length;
197
+ return {
198
+ messages,
199
+ total: messages.length,
200
+ truncated: false,
201
+ counts: {
202
+ error: messages.length - compatibilityLimitation,
203
+ compatibilityLimitation,
204
+ },
205
+ };
206
+ });
207
+ const seoValidation = dependencies.auditSeoMetadataDetailed
208
+ ? Promise.resolve().then(() => dependencies.auditSeoMetadataDetailed(html))
209
+ : Promise.resolve().then(() => {
210
+ const issues = dependencies.auditSeoMetadata(html);
211
+ const counts = { error: 0, warning: 0, info: 0 };
212
+ for (const issue of issues)
213
+ counts[issue.severity] += 1;
214
+ return { issues, totalIssues: issues.length, truncated: false, counts };
215
+ });
216
+ const schemaValidation = dependencies.validateSchemaMarkupDetailed
217
+ ? Promise.resolve().then(() => dependencies.validateSchemaMarkupDetailed(html))
218
+ : Promise.resolve().then(() => {
219
+ const issues = dependencies.validateSchemaMarkup(html);
220
+ const counts = { error: 0, warning: 0, info: 0 };
221
+ for (const issue of issues)
222
+ counts[issue.severity] += 1;
223
+ return { issues, totalIssues: issues.length, truncated: false, counts };
224
+ });
172
225
  const [htmlResult, cssResult, seoResult, schemaResult, linksResult] = await Promise.allSettled([
173
226
  htmlValidation,
174
- css === undefined ? Promise.resolve([]) : dependencies.validateCssContent(css),
175
- Promise.resolve().then(() => dependencies.auditSeoMetadata(html)),
176
- Promise.resolve().then(() => dependencies.validateSchemaMarkup(html)),
227
+ cssValidation,
228
+ seoValidation,
229
+ schemaValidation,
177
230
  dependencies.checkBrokenLinks(html, baseUrl, 25),
178
231
  ]);
179
232
  if (htmlResult.status === "rejected")
@@ -193,9 +246,18 @@ export async function generateValidationReport({ htmlFilePath, cssFilePath, base
193
246
  htmlTotalMessages: htmlResult.status === "fulfilled" ? htmlResult.value.total : 0,
194
247
  htmlTruncated: htmlResult.status === "fulfilled" ? htmlResult.value.truncated : false,
195
248
  htmlCounts: htmlResult.status === "fulfilled" ? htmlResult.value.counts : undefined,
196
- cssMessages: cssResult.status === "fulfilled" ? cssResult.value : [],
197
- seoIssues: seoResult.status === "fulfilled" ? seoResult.value.slice(0, 200) : [],
198
- schemaIssues: schemaResult.status === "fulfilled" ? schemaResult.value.slice(0, 200) : [],
249
+ cssMessages: cssResult.status === "fulfilled" ? cssResult.value.messages : [],
250
+ cssTotalMessages: cssResult.status === "fulfilled" ? cssResult.value.total : 0,
251
+ cssTruncated: cssResult.status === "fulfilled" ? cssResult.value.truncated : false,
252
+ cssCounts: cssResult.status === "fulfilled" ? cssResult.value.counts : undefined,
253
+ seoIssues: seoResult.status === "fulfilled" ? seoResult.value.issues : [],
254
+ seoTotalIssues: seoResult.status === "fulfilled" ? seoResult.value.totalIssues : 0,
255
+ seoTruncated: seoResult.status === "fulfilled" ? seoResult.value.truncated : false,
256
+ seoCounts: seoResult.status === "fulfilled" ? seoResult.value.counts : undefined,
257
+ schemaIssues: schemaResult.status === "fulfilled" ? schemaResult.value.issues : [],
258
+ schemaTotalIssues: schemaResult.status === "fulfilled" ? schemaResult.value.totalIssues : 0,
259
+ schemaTruncated: schemaResult.status === "fulfilled" ? schemaResult.value.truncated : false,
260
+ schemaCounts: schemaResult.status === "fulfilled" ? schemaResult.value.counts : undefined,
199
261
  links: linksResult.status === "fulfilled" ? linksResult.value : [],
200
262
  failedChecks,
201
263
  errors,
@@ -279,18 +341,24 @@ export function createServer() {
279
341
  },
280
342
  outputSchema: {
281
343
  errors: z.array(cssMessageSchema),
344
+ totalMessages: z.number().int().nonnegative(),
345
+ truncated: z.boolean(),
282
346
  error: z.string().optional(),
283
347
  },
284
348
  annotations: externalReadOnlyAnnotations,
285
349
  }, async ({ filePath }) => {
286
350
  try {
287
351
  const css = await readTextFile(filePath, CSS_MAX_BYTES);
288
- const errors = await validateCssContent(css);
289
- return result({ errors }, cssValidationContent(errors));
352
+ const validation = await validateCssContentDetailed(css);
353
+ return result({
354
+ errors: validation.messages,
355
+ totalMessages: validation.total,
356
+ truncated: validation.truncated,
357
+ }, cssValidationContent(validation.messages, validation.total, validation.counts));
290
358
  }
291
359
  catch (cause) {
292
360
  const error = getErrorMessage(cause);
293
- return result({ errors: [], error }, failureContent("CSS validation", error, "Confirm the file exists, is readable, and is within the size limit, then retry."), true);
361
+ return result({ errors: [], totalMessages: 0, truncated: false, error }, failureContent("CSS validation", error, "Confirm the file exists, is readable, and is within the size limit, then retry."), true);
294
362
  }
295
363
  });
296
364
  server.registerTool("seo.metadata", {
@@ -303,17 +371,18 @@ export function createServer() {
303
371
  issues: z.array(seoIssueSchema),
304
372
  totalIssues: z.number().int().nonnegative(),
305
373
  truncated: z.boolean(),
374
+ counts: auditCountsSchema,
306
375
  error: z.string().optional(),
307
376
  },
308
377
  annotations: localReadOnlyAnnotations,
309
378
  }, async ({ htmlContent }) => {
310
379
  try {
311
- const { issues, totalIssues, truncated } = auditSeoMetadataDetailed(htmlContent);
312
- return result({ issues, totalIssues, truncated }, seoAuditContent(issues, totalIssues, truncated));
380
+ const { issues, totalIssues, truncated, counts } = auditSeoMetadataDetailed(htmlContent);
381
+ return result({ issues, totalIssues, truncated, counts }, seoAuditContent(issues, totalIssues, truncated, counts));
313
382
  }
314
383
  catch (cause) {
315
384
  const error = getErrorMessage(cause);
316
- return result({ issues: [], totalIssues: 0, truncated: false, error }, failureContent("SEO audit", error, "Confirm the supplied HTML is complete and within the size limit, then retry."), true);
385
+ return result({ issues: [], totalIssues: 0, truncated: false, counts: { error: 0, warning: 0, info: 0 }, error }, failureContent("SEO audit", error, "Confirm the supplied HTML is complete and within the size limit, then retry."), true);
317
386
  }
318
387
  });
319
388
  server.registerTool("links.broken", {
@@ -357,17 +426,18 @@ export function createServer() {
357
426
  issues: z.array(seoIssueSchema),
358
427
  totalIssues: z.number().int().nonnegative(),
359
428
  truncated: z.boolean(),
429
+ counts: auditCountsSchema,
360
430
  error: z.string().optional(),
361
431
  },
362
432
  annotations: localReadOnlyAnnotations,
363
433
  }, async ({ htmlContent }) => {
364
434
  try {
365
- const { issues, totalIssues, truncated } = validateSchemaMarkupDetailed(htmlContent);
366
- return result({ issues, totalIssues, truncated }, schemaValidationContent(issues, totalIssues, truncated, htmlContent));
435
+ const { issues, totalIssues, truncated, counts } = validateSchemaMarkupDetailed(htmlContent);
436
+ return result({ issues, totalIssues, truncated, counts }, schemaValidationContent(issues, totalIssues, truncated, htmlContent));
367
437
  }
368
438
  catch (cause) {
369
439
  const error = getErrorMessage(cause);
370
- return result({ issues: [], totalIssues: 0, truncated: false, error }, failureContent("JSON-LD syntax", error, "Confirm the supplied HTML is complete and within the size limit, then retry."), true);
440
+ return result({ issues: [], totalIssues: 0, truncated: false, counts: { error: 0, warning: 0, info: 0 }, error }, failureContent("JSON-LD syntax", error, "Confirm the supplied HTML is complete and within the size limit, then retry."), true);
371
441
  }
372
442
  });
373
443
  server.registerTool("report.validation", {
@@ -389,8 +459,14 @@ export function createServer() {
389
459
  htmlTotalMessages: z.number().int().nonnegative(),
390
460
  htmlTruncated: z.boolean(),
391
461
  cssMessages: z.array(cssMessageSchema),
462
+ cssTotalMessages: z.number().int().nonnegative(),
463
+ cssTruncated: z.boolean(),
392
464
  seoIssues: z.array(seoIssueSchema),
465
+ seoTotalIssues: z.number().int().nonnegative(),
466
+ seoTruncated: z.boolean(),
393
467
  schemaIssues: z.array(seoIssueSchema),
468
+ schemaTotalIssues: z.number().int().nonnegative(),
469
+ schemaTruncated: z.boolean(),
394
470
  links: z.array(linkStatusSchema),
395
471
  failedChecks: z.array(z.enum(validationReportChecks)),
396
472
  errors: z.array(z.string()).optional(),
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EACL,gBAAgB,EAChB,wBAAwB,EACxB,gBAAgB,EAChB,oBAAoB,EACpB,4BAA4B,GAC7B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,sBAAsB,EAGtB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,EACL,oBAAoB,EACpB,cAAc,EACd,qBAAqB,EACrB,gBAAgB,EAChB,aAAa,EACb,uBAAuB,EACvB,wBAAwB,EACxB,eAAe,GAChB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EACL,qBAAqB,EACrB,wBAAwB,EACxB,kBAAkB,EAClB,mBAAmB,EACnB,2BAA2B,GAC5B,MAAM,oBAAoB,CAAC;AAE5B,MAAM,CAAC,MAAM,cAAc,GAAG,eAAe,CAAC;AAE9C,MAAM,cAAc,GAAG,SAAS,CAAC;AACjC,MAAM,aAAa,GAAG,wBAAwB,CAAC;AAC/C,MAAM,eAAe,GAAG,KAAK,CAAC;AAC9B,MAAM,aAAa,GAAG,CAAC,CAAC;AAExB,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;AACrE,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;AAChE,MAAM,eAAe,GAAG,CAAC;KACtB,MAAM,EAAE;KACR,GAAG,EAAE;KACL,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;IAChB,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC;IACzC,OAAO,QAAQ,KAAK,OAAO,IAAI,QAAQ,KAAK,QAAQ,CAAC;AACvD,CAAC,EAAE,6BAA6B,CAAC,CAAC;AAEpC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACrC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACvC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACtC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACxC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC/B,CAAC,CAAC;AAEH,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACtB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,4BAA4B,CAAC,CAAC,QAAQ,EAAE;CAClE,CAAC,CAAC;AAEH,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gDAAgD,CAAC;IAC3E,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;IAC9C,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,eAAe,CAAC,CAAC;IACnE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC/B,CAAC,CAAC;AAEH,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE;IACf,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAClE,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE;IACf,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC/B,CAAC,CAAC;AAEH,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE;IACxB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACvB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACxB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;CACvB,CAAC,CAAC;AAEH,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IACzD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IACtD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IACrD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IACrD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IACtD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IAC1C,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IAC5C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACzC,2BAA2B,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IAC3D,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACzC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IAC3C,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IAC5C,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IAC5C,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;CAC5C,CAAC,CAAC;AAEH,MAAM,2BAA2B,GAAG;IAClC,4EAA4E;IAC5E,YAAY,EAAE,IAAI;IAClB,eAAe,EAAE,KAAK;IACtB,cAAc,EAAE,IAAI;IACpB,aAAa,EAAE,IAAI;CACX,CAAC;AAEX,MAAM,wBAAwB,GAAG;IAC/B,YAAY,EAAE,IAAI;IAClB,eAAe,EAAE,KAAK;IACtB,cAAc,EAAE,IAAI;IACpB,aAAa,EAAE,KAAK;CACZ,CAAC;AAEX,SAAS,MAAM,CACb,iBAAoB,EACpB,OAAe,EACf,OAAO,GAAG,KAAK;IAEf,OAAO;QACL,iBAAiB,EAAE,iBAA4C;QAC/D,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,OAAO;aACd;SACF;QACD,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtC,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,QAAgB,EAAE,KAAa;IACnD,OAAO;QACL,MAAM,EAAE,6CAA6C,KAAK,EAAE;QAC5D,OAAO,EAAE;YACP,YAAY,EAAE,IAAI;YAClB,SAAS,EAAE,IAAI;YACf,QAAQ,EAAE,IAAI;YACd,QAAQ,EAAE,IAAI;YACd,SAAS,EAAE,IAAI;YACf,UAAU,EAAE,CAAC;YACb,YAAY,EAAE,CAAC;YACf,SAAS,EAAE,CAAC;YACZ,2BAA2B,EAAE,CAAC;YAC9B,SAAS,EAAE,CAAC;YACZ,WAAW,EAAE,CAAC;YACd,YAAY,EAAE,CAAC;YACf,YAAY,EAAE,CAAC;YACf,WAAW,EAAE,CAAC;SACf;QACD,YAAY,EAAE,EAAE;QAChB,iBAAiB,EAAE,CAAC;QACpB,aAAa,EAAE,KAAK;QACpB,WAAW,EAAE,EAAE;QACf,SAAS,EAAE,EAAE;QACb,YAAY,EAAE,EAAE;QAChB,KAAK,EAAE,EAAE;QACT,YAAY,EAAE,CAAC,OAAO,CAAC;QACvB,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,IAAI,UAAU,CAAC,KAAK,KAAK,EAAE,CAAC;KAC/D,CAAC;AACJ,CAAC;AAYD,MAAM,4BAA4B,GAAiC;IACjE,YAAY;IACZ,mBAAmB;IACnB,2BAA2B;IAC3B,kBAAkB;IAClB,gBAAgB;IAChB,oBAAoB;IACpB,gBAAgB;CACjB,CAAC;AAQF,yGAAyG;AACzG,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,EAAE,YAAY,EAAE,WAAW,EAAE,OAAO,EAAmC,EACvE,YAAY,GAAiC,4BAA4B;IAEzE,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,YAAY,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;IAC3E,MAAM,YAAY,GAA4B,EAAE,CAAC;IACjD,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,aAAa,GAAG,CAAC,KAA4B,EAAE,KAAa,EAAE,KAAc,EAAQ,EAAE;QAC1F,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAClC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,qBAAqB,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACrE,CAAC,CAAC;IAEF,IAAI,GAAuB,CAAC;IAC5B,IAAI,WAAW,EAAE,CAAC;QAChB,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,YAAY,CAAC,YAAY,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;QACpE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,aAAa,CAAC,KAAK,EAAE,gBAAgB,EAAE,KAAK,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAED,MAAM,cAAc,GAAG,YAAY,CAAC,2BAA2B;QAC7D,CAAC,CAAC,YAAY,CAAC,2BAA2B,CAAC,IAAI,CAAC;QAChD,CAAC,CAAC,YAAY,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE;YACvD,MAAM,MAAM,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YACjD,KAAK,MAAM,OAAO,IAAI,QAAQ;gBAAE,MAAM,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC;YAC5E,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QACxE,CAAC,CAAC,CAAC;IACP,MAAM,CAAC,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,CAAC,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC;QAC7F,cAAc;QACd,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,kBAAkB,CAAC,GAAG,CAAC;QAC9E,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACjE,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC;QACrE,YAAY,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC;KACjD,CAAC,CAAC;IAEH,IAAI,UAAU,CAAC,MAAM,KAAK,UAAU;QAAE,aAAa,CAAC,MAAM,EAAE,iBAAiB,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IAClG,IAAI,SAAS,CAAC,MAAM,KAAK,UAAU;QAAE,aAAa,CAAC,KAAK,EAAE,gBAAgB,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;IAC9F,IAAI,SAAS,CAAC,MAAM,KAAK,UAAU;QAAE,aAAa,CAAC,KAAK,EAAE,cAAc,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;IAC5F,IAAI,YAAY,CAAC,MAAM,KAAK,UAAU;QAAE,aAAa,CAAC,QAAQ,EAAE,kBAAkB,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IACzG,IAAI,WAAW,CAAC,MAAM,KAAK,UAAU;QAAE,aAAa,CAAC,OAAO,EAAE,eAAe,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAEnG,OAAO,sBAAsB,CAAC;QAC5B,YAAY;QACZ,UAAU,EAAE,GAAG,KAAK,SAAS;QAC7B,YAAY,EAAE,UAAU,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;QAChF,iBAAiB,EAAE,UAAU,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACjF,aAAa,EAAE,UAAU,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK;QACrF,UAAU,EAAE,UAAU,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;QACnF,WAAW,EAAE,SAAS,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;QACpE,SAAS,EAAE,SAAS,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE;QAChF,YAAY,EAAE,YAAY,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE;QACzF,KAAK,EAAE,WAAW,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;QAClE,YAAY;QACZ,MAAM;KACP,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,cAAc,EAAE,EACtD;QACE,YAAY,EACV,6TAA6T;KAChU,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,YAAY,EACZ;QACE,KAAK,EAAE,qBAAqB;QAC5B,WAAW,EACT,kIAAkI;QACpI,WAAW,EAAE;YACX,QAAQ,EAAE,cAAc,CAAC,QAAQ,CAAC,sDAAsD,CAAC;SAC1F;QACD,YAAY,EAAE;YACZ,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC;YACjC,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;YAC7C,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE;YACtB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SAC7B;QACD,WAAW,EAAE,2BAA2B;KACzC,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;YAC1D,MAAM,UAAU,GAAG,MAAM,2BAA2B,CAAC,IAAI,CAAC,CAAC;YAC3D,OAAO,MAAM,CACX,EAAE,MAAM,EAAE,UAAU,CAAC,QAAQ,EAAE,aAAa,EAAE,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,UAAU,CAAC,SAAS,EAAE,EACjG,qBAAqB,CAAC,UAAU,CAAC,QAAQ,EAAE,SAAS,EAAE,UAAU,CAAC,KAAK,EAAE,UAAU,CAAC,MAAM,CAAC,CAC3F,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;YACrC,OAAO,MAAM,CACX,EAAE,MAAM,EAAE,EAAE,EAAE,aAAa,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,EACzD,cAAc,CACZ,iBAAiB,EACjB,KAAK,EACL,0GAA0G,CAC3G,EACD,IAAI,CACL,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,UAAU,EACV;QACE,KAAK,EAAE,uBAAuB;QAC9B,WAAW,EACT,2KAA2K;QAC7K,WAAW,EAAE;YACX,GAAG,EAAE,eAAe,CAAC,QAAQ,CAAC,uCAAuC,CAAC;SACvE;QACD,YAAY,EAAE;YACZ,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC;YACjC,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;YAC7C,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE;YACtB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;YACjC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SAC7B;QACD,WAAW,EAAE,2BAA2B;KACzC,EACD,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE;QAChB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE;gBACzC,QAAQ,EAAE,cAAc;gBACxB,SAAS,EAAE,MAAM;gBACjB,YAAY,EAAE,CAAC;gBACf,oBAAoB,EAAE,CAAC,WAAW,EAAE,uBAAuB,CAAC;gBAC5D,OAAO,EAAE;oBACP,MAAM,EAAE,uCAAuC;oBAC/C,YAAY,EAAE,2BAA2B,cAAc,0CAA0C;iBAClG;aACF,CAAC,CAAC;YACH,IAAI,OAAO,CAAC,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;gBAClD,MAAM,IAAI,KAAK,CAAC,4BAA4B,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;YACjE,CAAC;YACD,MAAM,UAAU,GAAG,MAAM,2BAA2B,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACnE,OAAO,MAAM,CACX;gBACE,MAAM,EAAE,UAAU,CAAC,QAAQ;gBAC3B,aAAa,EAAE,UAAU,CAAC,KAAK;gBAC/B,SAAS,EAAE,UAAU,CAAC,SAAS;gBAC/B,UAAU,EAAE,OAAO,CAAC,GAAG;aACxB,EACD,qBAAqB,CAAC,UAAU,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,EAAE,UAAU,CAAC,KAAK,EAAE,UAAU,CAAC,MAAM,CAAC,CAC7F,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;YACrC,OAAO,MAAM,CACX,EAAE,MAAM,EAAE,EAAE,EAAE,aAAa,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,EACzD,cAAc,CACZ,gBAAgB,EAChB,KAAK,EACL,iGAAiG,CAClG,EACD,IAAI,CACL,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,WAAW,EACX;QACE,KAAK,EAAE,oBAAoB;QAC3B,WAAW,EACT,8HAA8H;QAChI,WAAW,EAAE;YACX,QAAQ,EAAE,cAAc,CAAC,QAAQ,CAAC,oDAAoD,CAAC;SACxF;QACD,YAAY,EAAE;YACZ,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC;YACjC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SAC7B;QACD,WAAW,EAAE,2BAA2B;KACzC,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;YACxD,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,GAAG,CAAC,CAAC;YAC7C,OAAO,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC;QAC1D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;YACrC,OAAO,MAAM,CACX,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,EACrB,cAAc,CACZ,gBAAgB,EAChB,KAAK,EACL,iFAAiF,CAClF,EACD,IAAI,CACL,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;QACE,KAAK,EAAE,oBAAoB;QAC3B,WAAW,EACT,oIAAoI;QACtI,WAAW,EAAE;YACX,WAAW,EAAE,iBAAiB,CAAC,QAAQ,CAAC,qCAAqC,CAAC;SAC/E;QACD,YAAY,EAAE;YACZ,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC;YAC/B,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;YAC3C,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE;YACtB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SAC7B;QACD,WAAW,EAAE,wBAAwB;KACtC,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE;QACxB,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,wBAAwB,CAAC,WAAW,CAAC,CAAC;YACjF,OAAO,MAAM,CACX,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,EAClC,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,SAAS,CAAC,CAChD,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;YACrC,OAAO,MAAM,CACX,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,EACvD,cAAc,CACZ,WAAW,EACX,KAAK,EACL,8EAA8E,CAC/E,EACD,IAAI,CACL,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;QACE,KAAK,EAAE,oBAAoB;QAC3B,WAAW,EACT,iJAAiJ;QACnJ,WAAW,EAAE;YACX,WAAW,EAAE,iBAAiB,CAAC,QAAQ,CAAC,4CAA4C,CAAC;YACrF,OAAO,EAAE,eAAe;iBACrB,QAAQ,EAAE;iBACV,QAAQ,CAAC,kEAAkE,CAAC;YAC/E,QAAQ,EAAE,CAAC;iBACR,MAAM,EAAE;iBACR,GAAG,EAAE;iBACL,GAAG,CAAC,CAAC,CAAC;iBACN,GAAG,CAAC,EAAE,CAAC;iBACP,OAAO,CAAC,EAAE,CAAC;iBACX,QAAQ,CAAC,gEAAgE,CAAC;SAC9E;QACD,YAAY,EAAE;YACZ,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC;YAChC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SAC7B;QACD,WAAW,EAAE,2BAA2B;KACzC,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC3C,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;YACrE,OAAO,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;QAC7D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;YACrC,OAAO,MAAM,CACX,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EACpB,cAAc,CACZ,YAAY,EACZ,KAAK,EACL,4FAA4F,CAC7F,EACD,IAAI,CACL,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,eAAe,EACf;QACE,KAAK,EAAE,yBAAyB;QAChC,WAAW,EACT,2IAA2I;QAC7I,WAAW,EAAE;YACX,WAAW,EAAE,iBAAiB,CAAC,QAAQ,CAAC,4CAA4C,CAAC;SACtF;QACD,YAAY,EAAE;YACZ,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC;YAC/B,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;YAC3C,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE;YACtB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SAC7B;QACD,WAAW,EAAE,wBAAwB;KACtC,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE;QACxB,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,4BAA4B,CAAC,WAAW,CAAC,CAAC;YACrF,OAAO,MAAM,CACX,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,EAClC,uBAAuB,CAAC,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,CAAC,CACrE,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;YACrC,OAAO,MAAM,CACX,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,EACvD,cAAc,CACZ,gBAAgB,EAChB,KAAK,EACL,8EAA8E,CAC/E,EACD,IAAI,CACL,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,mBAAmB,EACnB;QACE,KAAK,EAAE,8BAA8B;QACrC,WAAW,EACT,iKAAiK;QACnK,WAAW,EAAE;YACX,YAAY,EAAE,cAAc,CAAC,QAAQ,CAAC,gDAAgD,CAAC;YACvF,WAAW,EAAE,cAAc;iBACxB,QAAQ,EAAE;iBACV,QAAQ,CAAC,wDAAwD,CAAC;YACrE,OAAO,EAAE,eAAe;iBACrB,QAAQ,EAAE;iBACV,QAAQ,CAAC,kEAAkE,CAAC;SAChF;QACD,YAAY,EAAE;YACZ,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;YAClB,OAAO,EAAE,mBAAmB;YAC5B,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC;YACvC,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;YACjD,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE;YAC1B,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC;YACtC,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC;YAClC,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC;YACrC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC;YAChC,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;YACrD,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;SACvC;QACD,WAAW,EAAE,2BAA2B;KACzC,EACD,KAAK,EAAE,EAAE,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,EAAE;QAC/C,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,MAAM,wBAAwB,CAAC;gBAChD,YAAY;gBACZ,WAAW;gBACX,OAAO;aACR,CAAC,CAAC;YACH,OAAO,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC;QACvD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;YACrC,MAAM,UAAU,GAAG,YAAY,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;YACrD,OAAO,MAAM,CACX,UAAU,EACV,cAAc,CACZ,mBAAmB,EACnB,KAAK,EACL,8FAA8F,CAC/F,EACD,IAAI,CACL,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,oBAAoB,EACpB;QACE,KAAK,EAAE,gCAAgC;QACvC,WAAW,EACT,gQAAgQ;QAClQ,WAAW,EAAE;YACX,UAAU,EAAE,CAAC;iBACV,MAAM,EAAE;iBACR,IAAI,EAAE;iBACN,GAAG,CAAC,CAAC,CAAC;iBACN,GAAG,CAAC,eAAe,CAAC;iBACpB,QAAQ,CAAC,2CAA2C,CAAC;YACxD,SAAS,EAAE,cAAc;iBACtB,QAAQ,EAAE;iBACV,OAAO,CAAC,4BAA4B,CAAC;iBACrC,QAAQ,CAAC,kDAAkD,CAAC;YAC/D,SAAS,EAAE,CAAC;iBACT,KAAK,CACJ,CAAC,CAAC,MAAM,CAAC;gBACP,IAAI,EAAE,CAAC;qBACJ,MAAM,EAAE;qBACR,KAAK,CAAC,uBAAuB,CAAC;qBAC9B,QAAQ,CAAC,mDAAmD,CAAC;gBAChE,KAAK,EAAE,CAAC;qBACL,MAAM,EAAE;qBACR,GAAG,EAAE;qBACL,GAAG,CAAC,GAAG,CAAC;qBACR,GAAG,CAAC,KAAK,CAAC;qBACV,QAAQ,CAAC,iDAAiD,CAAC;gBAC9D,MAAM,EAAE,CAAC;qBACN,MAAM,EAAE;qBACR,GAAG,EAAE;qBACL,GAAG,CAAC,GAAG,CAAC;qBACR,GAAG,CAAC,KAAK,CAAC;qBACV,QAAQ,CAAC,kDAAkD,CAAC;aAChE,CAAC,CACH;iBACA,GAAG,CAAC,CAAC,CAAC;iBACN,GAAG,CAAC,aAAa,CAAC;iBAClB,QAAQ,EAAE;iBACV,QAAQ,CAAC,+EAA+E,CAAC;SAC7F;QACD,YAAY,EAAE;YACZ,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC;YACtC,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE;YAC3B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SAC7B;QACD,WAAW,EAAE;YACX,YAAY,EAAE,KAAK;YACnB,eAAe,EAAE,IAAI;YACrB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,IAAI;SACpB;KACF,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,EAAE;QAC7C,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAChD,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,MAAM,kBAAkB,CAAC,UAAU,EAAE,eAAe,EAAE,SAAS,CAAC,CAAC;YACrF,OAAO,MAAM,CACX,EAAE,WAAW,EAAE,eAAe,EAAE,EAChC,wBAAwB,CAAC,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,CAC9D,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;YACrC,OAAO,MAAM,CACX,EAAE,WAAW,EAAE,EAAE,EAAE,eAAe,EAAE,KAAK,EAAE,EAC3C,cAAc,CACZ,oBAAoB,EACpB,KAAK,EACL,+FAA+F,CAChG,EACD,IAAI,CACL,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,GAAG;IACvB,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC;IACjD,OAAO,CAAC,KAAK,CAAC,qBAAqB,cAAc,mBAAmB,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AACpG,IAAI,WAAW,KAAK,OAAO,IAAI,CAAC,GAAG,EAAE,CAAC;IACpC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QAC7B,OAAO,CAAC,KAAK,CAAC,yCAAyC,EAAE,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC;QACjF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["#!/usr/bin/env node\nimport * as path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { z } from \"zod\";\nimport { captureScreenshots } from \"./screenshot.js\";\nimport {\n auditSeoMetadata,\n auditSeoMetadataDetailed,\n checkBrokenLinks,\n validateSchemaMarkup,\n validateSchemaMarkupDetailed,\n} from \"./seo-auditor.js\";\nimport {\n createValidationReport,\n type ValidationReport,\n type ValidationReportCheck,\n validationReportChecks,\n} from \"./report.js\";\nimport { fetchPublicText, getErrorMessage, readTextFile } from \"./network.js\";\nimport {\n cssValidationContent,\n failureContent,\n htmlValidationContent,\n linkCheckContent,\n reportContent,\n schemaValidationContent,\n screenshotCaptureContent,\n seoAuditContent,\n} from \"./presentation.js\";\nimport { PACKAGE_VERSION } from \"./version.js\";\nimport {\n getW3CMessageSeverity,\n MAX_CSS_VALIDATION_BYTES,\n validateCssContent,\n validateHtmlContent,\n validateHtmlContentDetailed,\n} from \"./w3c-validator.js\";\n\nexport const SERVER_VERSION = PACKAGE_VERSION;\n\nconst HTML_MAX_BYTES = 2_000_000;\nconst CSS_MAX_BYTES = MAX_CSS_VALIDATION_BYTES;\nconst PATH_MAX_LENGTH = 4_096;\nconst MAX_VIEWPORTS = 8;\n\nconst filePathSchema = z.string().trim().min(1).max(PATH_MAX_LENGTH);\nconst htmlContentSchema = z.string().min(1).max(HTML_MAX_BYTES);\nconst publicUrlSchema = z\n .string()\n .url()\n .refine((value) => {\n const protocol = new URL(value).protocol;\n return protocol === \"http:\" || protocol === \"https:\";\n }, \"URL must use HTTP or HTTPS.\");\n\nconst w3cMessageSchema = z.object({\n type: z.string(),\n subType: z.string().optional(),\n message: z.string(),\n lastLine: z.number().int().optional(),\n lastColumn: z.number().int().optional(),\n firstLine: z.number().int().optional(),\n firstColumn: z.number().int().optional(),\n extract: z.string().optional(),\n});\n\nconst cssMessageSchema = z.object({\n line: z.number().int(),\n type: z.string(),\n message: z.string(),\n context: z.string().optional(),\n compatibility: z.literal(\"known-validator-limitation\").optional(),\n});\n\nconst seoIssueSchema = z.object({\n code: z.string().describe(\"Stable machine-readable audit rule identifier.\"),\n severity: z.enum([\"error\", \"warning\", \"info\"]),\n category: z.enum([\"SEO\", \"Schema\", \"BrokenLinks\", \"Accessibility\"]),\n message: z.string(),\n element: z.string().optional(),\n});\n\nconst linkStatusSchema = z.object({\n url: z.string(),\n status: z.union([z.number().int(), z.enum([\"blocked\", \"failed\"])]),\n ok: z.boolean(),\n message: z.string().optional(),\n});\n\nconst screenshotSchema = z.object({\n viewportName: z.string(),\n width: z.number().int(),\n height: z.number().int(),\n outputPath: z.string(),\n});\n\nconst reportSummarySchema = z.object({\n overallScore: z.number().int().min(0).max(100).nullable(),\n htmlScore: z.number().int().min(0).max(100).nullable(),\n cssScore: z.number().int().min(0).max(100).nullable(),\n seoScore: z.number().int().min(0).max(100).nullable(),\n linkScore: z.number().int().min(0).max(100).nullable(),\n htmlErrors: z.number().int().nonnegative(),\n htmlWarnings: z.number().int().nonnegative(),\n cssErrors: z.number().int().nonnegative(),\n cssCompatibilityLimitations: z.number().int().nonnegative(),\n seoErrors: z.number().int().nonnegative(),\n seoWarnings: z.number().int().nonnegative(),\n schemaErrors: z.number().int().nonnegative(),\n linksChecked: z.number().int().nonnegative(),\n brokenLinks: z.number().int().nonnegative(),\n});\n\nconst externalReadOnlyAnnotations = {\n // These calls contact external recipients but do not modify external state.\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: true,\n} as const;\n\nconst localReadOnlyAnnotations = {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n} as const;\n\nfunction result<T extends object>(\n structuredContent: T,\n content: string,\n isError = false,\n): CallToolResult {\n return {\n structuredContent: structuredContent as Record<string, unknown>,\n content: [\n {\n type: \"text\",\n text: content,\n },\n ],\n ...(isError ? { isError: true } : {}),\n };\n}\n\nfunction failedReport(filePath: string, error: string): ValidationReport {\n return {\n report: `Validation report could not be generated: ${error}`,\n summary: {\n overallScore: null,\n htmlScore: null,\n cssScore: null,\n seoScore: null,\n linkScore: null,\n htmlErrors: 0,\n htmlWarnings: 0,\n cssErrors: 0,\n cssCompatibilityLimitations: 0,\n seoErrors: 0,\n seoWarnings: 0,\n schemaErrors: 0,\n linksChecked: 0,\n brokenLinks: 0,\n },\n htmlMessages: [],\n htmlTotalMessages: 0,\n htmlTruncated: false,\n cssMessages: [],\n seoIssues: [],\n schemaIssues: [],\n links: [],\n failedChecks: [\"input\"],\n errors: [`${path.basename(filePath || \"document\")}: ${error}`],\n };\n}\n\ninterface ValidationReportDependencies {\n readTextFile: typeof readTextFile;\n validateHtmlContent: typeof validateHtmlContent;\n validateHtmlContentDetailed?: typeof validateHtmlContentDetailed;\n validateCssContent: typeof validateCssContent;\n auditSeoMetadata: typeof auditSeoMetadata;\n validateSchemaMarkup: typeof validateSchemaMarkup;\n checkBrokenLinks: typeof checkBrokenLinks;\n}\n\nconst validationReportDependencies: ValidationReportDependencies = {\n readTextFile,\n validateHtmlContent,\n validateHtmlContentDetailed,\n validateCssContent,\n auditSeoMetadata,\n validateSchemaMarkup,\n checkBrokenLinks,\n};\n\nexport interface GenerateValidationReportOptions {\n htmlFilePath: string;\n cssFilePath?: string;\n baseUrl?: string;\n}\n\n/** Runs independent validation checks without discarding successful results when another check fails. */\nexport async function generateValidationReport(\n { htmlFilePath, cssFilePath, baseUrl }: GenerateValidationReportOptions,\n dependencies: ValidationReportDependencies = validationReportDependencies,\n): Promise<ValidationReport> {\n const html = await dependencies.readTextFile(htmlFilePath, HTML_MAX_BYTES);\n const failedChecks: ValidationReportCheck[] = [];\n const errors: string[] = [];\n const recordFailure = (check: ValidationReportCheck, label: string, cause: unknown): void => {\n if (!failedChecks.includes(check)) {\n failedChecks.push(check);\n }\n errors.push(`${label} was unavailable: ${getErrorMessage(cause)}`);\n };\n\n let css: string | undefined;\n if (cssFilePath) {\n try {\n css = await dependencies.readTextFile(cssFilePath, CSS_MAX_BYTES);\n } catch (cause) {\n recordFailure(\"css\", \"CSS validation\", cause);\n }\n }\n\n const htmlValidation = dependencies.validateHtmlContentDetailed\n ? dependencies.validateHtmlContentDetailed(html)\n : dependencies.validateHtmlContent(html).then((messages) => {\n const counts = { error: 0, warning: 0, info: 0 };\n for (const message of messages) counts[getW3CMessageSeverity(message)] += 1;\n return { messages, total: messages.length, truncated: false, counts };\n });\n const [htmlResult, cssResult, seoResult, schemaResult, linksResult] = await Promise.allSettled([\n htmlValidation,\n css === undefined ? Promise.resolve([]) : dependencies.validateCssContent(css),\n Promise.resolve().then(() => dependencies.auditSeoMetadata(html)),\n Promise.resolve().then(() => dependencies.validateSchemaMarkup(html)),\n dependencies.checkBrokenLinks(html, baseUrl, 25),\n ]);\n\n if (htmlResult.status === \"rejected\") recordFailure(\"html\", \"HTML validation\", htmlResult.reason);\n if (cssResult.status === \"rejected\") recordFailure(\"css\", \"CSS validation\", cssResult.reason);\n if (seoResult.status === \"rejected\") recordFailure(\"seo\", \"SEO analysis\", seoResult.reason);\n if (schemaResult.status === \"rejected\") recordFailure(\"schema\", \"JSON-LD analysis\", schemaResult.reason);\n if (linksResult.status === \"rejected\") recordFailure(\"links\", \"Link checking\", linksResult.reason);\n\n return createValidationReport({\n htmlFilePath,\n cssAudited: css !== undefined,\n htmlMessages: htmlResult.status === \"fulfilled\" ? htmlResult.value.messages : [],\n htmlTotalMessages: htmlResult.status === \"fulfilled\" ? htmlResult.value.total : 0,\n htmlTruncated: htmlResult.status === \"fulfilled\" ? htmlResult.value.truncated : false,\n htmlCounts: htmlResult.status === \"fulfilled\" ? htmlResult.value.counts : undefined,\n cssMessages: cssResult.status === \"fulfilled\" ? cssResult.value : [],\n seoIssues: seoResult.status === \"fulfilled\" ? seoResult.value.slice(0, 200) : [],\n schemaIssues: schemaResult.status === \"fulfilled\" ? schemaResult.value.slice(0, 200) : [],\n links: linksResult.status === \"fulfilled\" ? linksResult.value : [],\n failedChecks,\n errors,\n });\n}\n\nexport function createServer(): McpServer {\n const server = new McpServer(\n { name: \"mcp-web-validator\", version: SERVER_VERSION },\n {\n instructions:\n \"Validate only files, markup, and public URLs the user owns or is authorized to inspect. HTML and CSS validation send supplied content to W3C-operated validators. Link checks contact public links without following redirects. Screenshot capture executes page content in a sandboxed local browser and writes PNG files.\",\n },\n );\n\n server.registerTool(\n \"html.local\",\n {\n title: \"Validate local HTML\",\n description:\n \"Reads a bounded local HTML file and sends its markup to the W3C Nu HTML Checker. Use only files the user is authorized to share.\",\n inputSchema: {\n filePath: filePathSchema.describe(\"Absolute or workspace-relative path to an HTML file.\"),\n },\n outputSchema: {\n errors: z.array(w3cMessageSchema),\n totalMessages: z.number().int().nonnegative(),\n truncated: z.boolean(),\n error: z.string().optional(),\n },\n annotations: externalReadOnlyAnnotations,\n },\n async ({ filePath }) => {\n try {\n const html = await readTextFile(filePath, HTML_MAX_BYTES);\n const validation = await validateHtmlContentDetailed(html);\n return result(\n { errors: validation.messages, totalMessages: validation.total, truncated: validation.truncated },\n htmlValidationContent(validation.messages, undefined, validation.total, validation.counts),\n );\n } catch (cause) {\n const error = getErrorMessage(cause);\n return result(\n { errors: [], totalMessages: 0, truncated: false, error },\n failureContent(\n \"HTML validation\",\n error,\n \"Confirm the file exists and is readable, then retry. If the W3C service is unavailable, try again later.\",\n ),\n true,\n );\n }\n },\n );\n\n server.registerTool(\n \"html.url\",\n {\n title: \"Validate a public URL\",\n description:\n \"Fetches a bounded public HTTP(S) page, then sends its markup to the W3C Nu HTML Checker. Private, reserved, credentialed, and nonstandard-port destinations are rejected.\",\n inputSchema: {\n url: publicUrlSchema.describe(\"Public HTTP(S) URL on port 80 or 443.\"),\n },\n outputSchema: {\n errors: z.array(w3cMessageSchema),\n totalMessages: z.number().int().nonnegative(),\n truncated: z.boolean(),\n fetchedUrl: z.string().optional(),\n error: z.string().optional(),\n },\n annotations: externalReadOnlyAnnotations,\n },\n async ({ url }) => {\n try {\n const fetched = await fetchPublicText(url, {\n maxBytes: HTML_MAX_BYTES,\n timeoutMs: 15_000,\n maxRedirects: 3,\n acceptedContentTypes: [\"text/html\", \"application/xhtml+xml\"],\n headers: {\n accept: \"text/html,application/xhtml+xml;q=0.9\",\n \"user-agent\": `DigestSEO-Web-Validator/${SERVER_VERSION} (+https://digestseo.com/validator-mcp/)`,\n },\n });\n if (fetched.status < 200 || fetched.status >= 300) {\n throw new Error(`Target URL returned HTTP ${fetched.status}.`);\n }\n const validation = await validateHtmlContentDetailed(fetched.text);\n return result(\n {\n errors: validation.messages,\n totalMessages: validation.total,\n truncated: validation.truncated,\n fetchedUrl: fetched.url,\n },\n htmlValidationContent(validation.messages, fetched.url, validation.total, validation.counts),\n );\n } catch (cause) {\n const error = getErrorMessage(cause);\n return result(\n { errors: [], totalMessages: 0, truncated: false, error },\n failureContent(\n \"URL validation\",\n error,\n \"Confirm the URL is public, uses HTTP or HTTPS on a standard port, and returns HTML, then retry.\",\n ),\n true,\n );\n }\n },\n );\n\n server.registerTool(\n \"css.local\",\n {\n title: \"Validate local CSS\",\n description:\n \"Reads a bounded local CSS file and sends it to the W3C Jigsaw CSS Validator. Use only files the user is authorized to share.\",\n inputSchema: {\n filePath: filePathSchema.describe(\"Absolute or workspace-relative path to a CSS file.\"),\n },\n outputSchema: {\n errors: z.array(cssMessageSchema),\n error: z.string().optional(),\n },\n annotations: externalReadOnlyAnnotations,\n },\n async ({ filePath }) => {\n try {\n const css = await readTextFile(filePath, CSS_MAX_BYTES);\n const errors = await validateCssContent(css);\n return result({ errors }, cssValidationContent(errors));\n } catch (cause) {\n const error = getErrorMessage(cause);\n return result(\n { errors: [], error },\n failureContent(\n \"CSS validation\",\n error,\n \"Confirm the file exists, is readable, and is within the size limit, then retry.\",\n ),\n true,\n );\n }\n },\n );\n\n server.registerTool(\n \"seo.metadata\",\n {\n title: \"Audit SEO metadata\",\n description:\n \"Analyzes supplied HTML locally for metadata, heading structure, viewport configuration, image alternatives, and Open Graph fields.\",\n inputSchema: {\n htmlContent: htmlContentSchema.describe(\"Raw HTML markup to inspect locally.\"),\n },\n outputSchema: {\n issues: z.array(seoIssueSchema),\n totalIssues: z.number().int().nonnegative(),\n truncated: z.boolean(),\n error: z.string().optional(),\n },\n annotations: localReadOnlyAnnotations,\n },\n async ({ htmlContent }) => {\n try {\n const { issues, totalIssues, truncated } = auditSeoMetadataDetailed(htmlContent);\n return result(\n { issues, totalIssues, truncated },\n seoAuditContent(issues, totalIssues, truncated),\n );\n } catch (cause) {\n const error = getErrorMessage(cause);\n return result(\n { issues: [], totalIssues: 0, truncated: false, error },\n failureContent(\n \"SEO audit\",\n error,\n \"Confirm the supplied HTML is complete and within the size limit, then retry.\",\n ),\n true,\n );\n }\n },\n );\n\n server.registerTool(\n \"links.broken\",\n {\n title: \"Check public links\",\n description:\n \"Resolves and checks up to 25 public HTTP(S) links in supplied HTML. Redirects are reported but not followed, and response bodies are discarded.\",\n inputSchema: {\n htmlContent: htmlContentSchema.describe(\"Raw HTML markup containing links to check.\"),\n baseUrl: publicUrlSchema\n .optional()\n .describe(\"Optional public HTTP(S) base URL used to resolve relative links.\"),\n maxLinks: z\n .number()\n .int()\n .min(1)\n .max(25)\n .default(25)\n .describe(\"Maximum number of public HTTP(S) links to check, from 1 to 25.\"),\n },\n outputSchema: {\n links: z.array(linkStatusSchema),\n error: z.string().optional(),\n },\n annotations: externalReadOnlyAnnotations,\n },\n async ({ htmlContent, baseUrl, maxLinks }) => {\n try {\n const links = await checkBrokenLinks(htmlContent, baseUrl, maxLinks);\n return result({ links }, linkCheckContent(links, baseUrl));\n } catch (cause) {\n const error = getErrorMessage(cause);\n return result(\n { links: [], error },\n failureContent(\n \"Link check\",\n error,\n \"Confirm the base URL is public and the supplied HTML is within the size limit, then retry.\",\n ),\n true,\n );\n }\n },\n );\n\n server.registerTool(\n \"schema.markup\",\n {\n title: \"Validate JSON-LD syntax\",\n description:\n \"Parses JSON-LD blocks in supplied HTML locally and reports empty blocks or JSON syntax errors. It does not validate vocabulary semantics.\",\n inputSchema: {\n htmlContent: htmlContentSchema.describe(\"Raw HTML containing JSON-LD script blocks.\"),\n },\n outputSchema: {\n issues: z.array(seoIssueSchema),\n totalIssues: z.number().int().nonnegative(),\n truncated: z.boolean(),\n error: z.string().optional(),\n },\n annotations: localReadOnlyAnnotations,\n },\n async ({ htmlContent }) => {\n try {\n const { issues, totalIssues, truncated } = validateSchemaMarkupDetailed(htmlContent);\n return result(\n { issues, totalIssues, truncated },\n schemaValidationContent(issues, totalIssues, truncated, htmlContent),\n );\n } catch (cause) {\n const error = getErrorMessage(cause);\n return result(\n { issues: [], totalIssues: 0, truncated: false, error },\n failureContent(\n \"JSON-LD syntax\",\n error,\n \"Confirm the supplied HTML is complete and within the size limit, then retry.\",\n ),\n true,\n );\n }\n },\n );\n\n server.registerTool(\n \"report.validation\",\n {\n title: \"Generate a validation report\",\n description:\n \"Combines W3C HTML/CSS validation, local SEO/accessibility checks, JSON-LD syntax checks, and a bounded public-link check into a Markdown and structured report.\",\n inputSchema: {\n htmlFilePath: filePathSchema.describe(\"Absolute or workspace-relative HTML file path.\"),\n cssFilePath: filePathSchema\n .optional()\n .describe(\"Optional absolute or workspace-relative CSS file path.\"),\n baseUrl: publicUrlSchema\n .optional()\n .describe(\"Optional public HTTP(S) base URL used to resolve relative links.\"),\n },\n outputSchema: {\n report: z.string(),\n summary: reportSummarySchema,\n htmlMessages: z.array(w3cMessageSchema),\n htmlTotalMessages: z.number().int().nonnegative(),\n htmlTruncated: z.boolean(),\n cssMessages: z.array(cssMessageSchema),\n seoIssues: z.array(seoIssueSchema),\n schemaIssues: z.array(seoIssueSchema),\n links: z.array(linkStatusSchema),\n failedChecks: z.array(z.enum(validationReportChecks)),\n errors: z.array(z.string()).optional(),\n },\n annotations: externalReadOnlyAnnotations,\n },\n async ({ htmlFilePath, cssFilePath, baseUrl }) => {\n try {\n const reportData = await generateValidationReport({\n htmlFilePath,\n cssFilePath,\n baseUrl,\n });\n return result(reportData, reportContent(reportData));\n } catch (cause) {\n const error = getErrorMessage(cause);\n const reportData = failedReport(htmlFilePath, error);\n return result(\n reportData,\n failureContent(\n \"Validation report\",\n error,\n \"Confirm the input paths are readable and any base URL is public, then regenerate the report.\",\n ),\n true,\n );\n }\n },\n );\n\n server.registerTool(\n \"screenshot.capture\",\n {\n title: \"Capture responsive screenshots\",\n description:\n \"Renders a local HTML file or HTTP(S) URL in a sandboxed local Chromium browser and writes PNG screenshots to the requested directory. Downloads the pinned headless browser on first use if it is not already cached. Existing matching files may be replaced.\",\n inputSchema: {\n targetPath: z\n .string()\n .trim()\n .min(1)\n .max(PATH_MAX_LENGTH)\n .describe(\"Local HTML path or HTTP(S) URL to render.\"),\n outputDir: filePathSchema\n .optional()\n .default(\".mcp-validator/screenshots\")\n .describe(\"Directory where PNG screenshots will be written.\"),\n viewports: z\n .array(\n z.object({\n name: z\n .string()\n .regex(/^[A-Za-z0-9_-]{1,50}$/)\n .describe(\"Safe filename label for this screenshot viewport.\"),\n width: z\n .number()\n .int()\n .min(200)\n .max(3_840)\n .describe(\"Viewport width in CSS pixels, from 200 to 3840.\"),\n height: z\n .number()\n .int()\n .min(200)\n .max(4_320)\n .describe(\"Viewport height in CSS pixels, from 200 to 4320.\"),\n }),\n )\n .min(1)\n .max(MAX_VIEWPORTS)\n .optional()\n .describe(\"Optional viewport definitions; defaults to desktop, tablet, and mobile sizes.\"),\n },\n outputSchema: {\n screenshots: z.array(screenshotSchema),\n outputDirectory: z.string(),\n error: z.string().optional(),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: true,\n idempotentHint: true,\n openWorldHint: true,\n },\n },\n async ({ targetPath, outputDir, viewports }) => {\n const outputDirectory = path.resolve(outputDir);\n try {\n const screenshots = await captureScreenshots(targetPath, outputDirectory, viewports);\n return result(\n { screenshots, outputDirectory },\n screenshotCaptureContent(screenshots.length, outputDirectory),\n );\n } catch (cause) {\n const error = getErrorMessage(cause);\n return result(\n { screenshots: [], outputDirectory, error },\n failureContent(\n \"Screenshot capture\",\n error,\n \"Confirm the target is reachable or readable and the output directory is writable, then retry.\",\n ),\n true,\n );\n }\n },\n );\n\n return server;\n}\n\nexport async function run(): Promise<void> {\n const server = createServer();\n await server.connect(new StdioServerTransport());\n console.error(`mcp-web-validator ${SERVER_VERSION} started on stdio`);\n}\n\nconst invokedPath = process.argv[1] ? pathToFileURL(path.resolve(process.argv[1])).href : undefined;\nif (invokedPath === import.meta.url) {\n run().catch((cause: unknown) => {\n console.error(\"Fatal error starting mcp-web-validator:\", getErrorMessage(cause));\n process.exitCode = 1;\n });\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EACL,gBAAgB,EAChB,wBAAwB,EACxB,gBAAgB,EAChB,oBAAoB,EACpB,4BAA4B,GAC7B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,sBAAsB,EAGtB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,EACL,oBAAoB,EACpB,cAAc,EACd,qBAAqB,EACrB,gBAAgB,EAChB,aAAa,EACb,uBAAuB,EACvB,wBAAwB,EACxB,eAAe,GAChB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EACL,qBAAqB,EACrB,wBAAwB,EACxB,kBAAkB,EAClB,0BAA0B,EAC1B,mBAAmB,EACnB,2BAA2B,GAC5B,MAAM,oBAAoB,CAAC;AAE5B,MAAM,CAAC,MAAM,cAAc,GAAG,eAAe,CAAC;AAE9C,MAAM,cAAc,GAAG,SAAS,CAAC;AACjC,MAAM,aAAa,GAAG,wBAAwB,CAAC;AAC/C,MAAM,eAAe,GAAG,KAAK,CAAC;AAC9B,MAAM,aAAa,GAAG,CAAC,CAAC;AAExB,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;AACrE,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;AAChE,MAAM,eAAe,GAAG,CAAC;KACtB,MAAM,EAAE;KACR,GAAG,EAAE;KACL,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;IAChB,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC;IACzC,OAAO,QAAQ,KAAK,OAAO,IAAI,QAAQ,KAAK,QAAQ,CAAC;AACvD,CAAC,EAAE,6BAA6B,CAAC,CAAC;AAEpC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACrC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACvC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACtC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACxC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC/B,CAAC,CAAC;AAEH,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACtB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,4BAA4B,CAAC,CAAC,QAAQ,EAAE;CAClE,CAAC,CAAC;AAEH,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gDAAgD,CAAC;IAC3E,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;IAC9C,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,eAAe,CAAC,CAAC;IACnE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC/B,CAAC,CAAC;AAEH,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACjC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACrC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACvC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;CACrC,CAAC,CAAC;AAEH,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE;IACf,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAClE,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE;IACf,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC/B,CAAC,CAAC;AAEH,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE;IACxB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACvB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACxB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;CACvB,CAAC,CAAC;AAEH,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IACzD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IACtD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IACrD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IACrD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IACtD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IAC1C,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IAC5C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACzC,2BAA2B,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IAC3D,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACzC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IAC3C,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IAC5C,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IAC5C,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;CAC5C,CAAC,CAAC;AAEH,MAAM,2BAA2B,GAAG;IAClC,4EAA4E;IAC5E,YAAY,EAAE,IAAI;IAClB,eAAe,EAAE,KAAK;IACtB,cAAc,EAAE,IAAI;IACpB,aAAa,EAAE,IAAI;CACX,CAAC;AAEX,MAAM,wBAAwB,GAAG;IAC/B,YAAY,EAAE,IAAI;IAClB,eAAe,EAAE,KAAK;IACtB,cAAc,EAAE,IAAI;IACpB,aAAa,EAAE,KAAK;CACZ,CAAC;AAEX,SAAS,MAAM,CACb,iBAAoB,EACpB,OAAe,EACf,OAAO,GAAG,KAAK;IAEf,OAAO;QACL,iBAAiB,EAAE,iBAA4C;QAC/D,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,OAAO;aACd;SACF;QACD,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtC,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,QAAgB,EAAE,KAAa;IACnD,OAAO;QACL,MAAM,EAAE,6CAA6C,KAAK,EAAE;QAC5D,OAAO,EAAE;YACP,YAAY,EAAE,IAAI;YAClB,SAAS,EAAE,IAAI;YACf,QAAQ,EAAE,IAAI;YACd,QAAQ,EAAE,IAAI;YACd,SAAS,EAAE,IAAI;YACf,UAAU,EAAE,CAAC;YACb,YAAY,EAAE,CAAC;YACf,SAAS,EAAE,CAAC;YACZ,2BAA2B,EAAE,CAAC;YAC9B,SAAS,EAAE,CAAC;YACZ,WAAW,EAAE,CAAC;YACd,YAAY,EAAE,CAAC;YACf,YAAY,EAAE,CAAC;YACf,WAAW,EAAE,CAAC;SACf;QACD,YAAY,EAAE,EAAE;QAChB,iBAAiB,EAAE,CAAC;QACpB,aAAa,EAAE,KAAK;QACpB,WAAW,EAAE,EAAE;QACf,gBAAgB,EAAE,CAAC;QACnB,YAAY,EAAE,KAAK;QACnB,SAAS,EAAE,EAAE;QACb,cAAc,EAAE,CAAC;QACjB,YAAY,EAAE,KAAK;QACnB,YAAY,EAAE,EAAE;QAChB,iBAAiB,EAAE,CAAC;QACpB,eAAe,EAAE,KAAK;QACtB,KAAK,EAAE,EAAE;QACT,YAAY,EAAE,CAAC,OAAO,CAAC;QACvB,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,IAAI,UAAU,CAAC,KAAK,KAAK,EAAE,CAAC;KAC/D,CAAC;AACJ,CAAC;AAeD,MAAM,4BAA4B,GAAiC;IACjE,YAAY;IACZ,mBAAmB;IACnB,2BAA2B;IAC3B,kBAAkB;IAClB,0BAA0B;IAC1B,gBAAgB;IAChB,wBAAwB;IACxB,oBAAoB;IACpB,4BAA4B;IAC5B,gBAAgB;CACjB,CAAC;AAQF,yGAAyG;AACzG,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,EAAE,YAAY,EAAE,WAAW,EAAE,OAAO,EAAmC,EACvE,YAAY,GAAiC,4BAA4B;IAEzE,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,YAAY,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;IAC3E,MAAM,YAAY,GAA4B,EAAE,CAAC;IACjD,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,aAAa,GAAG,CAAC,KAA4B,EAAE,KAAa,EAAE,KAAc,EAAQ,EAAE;QAC1F,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAClC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,qBAAqB,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACrE,CAAC,CAAC;IAEF,IAAI,GAAuB,CAAC;IAC5B,IAAI,WAAW,EAAE,CAAC;QAChB,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,YAAY,CAAC,YAAY,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;QACpE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,aAAa,CAAC,KAAK,EAAE,gBAAgB,EAAE,KAAK,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAED,MAAM,cAAc,GAAG,YAAY,CAAC,2BAA2B;QAC7D,CAAC,CAAC,YAAY,CAAC,2BAA2B,CAAC,IAAI,CAAC;QAChD,CAAC,CAAC,YAAY,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE;YACvD,MAAM,MAAM,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YACjD,KAAK,MAAM,OAAO,IAAI,QAAQ;gBAAE,MAAM,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC;YAC5E,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QACxE,CAAC,CAAC,CAAC;IACP,MAAM,aAAa,GAAG,GAAG,KAAK,SAAS;QACrC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;YACd,QAAQ,EAAE,EAAE;YACZ,KAAK,EAAE,CAAC;YACR,SAAS,EAAE,KAAK;YAChB,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,uBAAuB,EAAE,CAAC,EAAE;SACjD,CAAC;QACJ,CAAC,CAAC,YAAY,CAAC,0BAA0B;YACvC,CAAC,CAAC,YAAY,CAAC,0BAA0B,CAAC,GAAG,CAAC;YAC9C,CAAC,CAAC,YAAY,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE;gBACrD,MAAM,uBAAuB,GAAG,QAAQ,CAAC,MAAM,CAC7C,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,aAAa,KAAK,4BAA4B,CACpE,CAAC,MAAM,CAAC;gBACT,OAAO;oBACL,QAAQ;oBACR,KAAK,EAAE,QAAQ,CAAC,MAAM;oBACtB,SAAS,EAAE,KAAK;oBAChB,MAAM,EAAE;wBACN,KAAK,EAAE,QAAQ,CAAC,MAAM,GAAG,uBAAuB;wBAChD,uBAAuB;qBACxB;iBACF,CAAC;YACJ,CAAC,CAAC,CAAC;IACT,MAAM,aAAa,GAAG,YAAY,CAAC,wBAAwB;QACzD,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,wBAAyB,CAAC,IAAI,CAAC,CAAC;QAC5E,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;YAC1B,MAAM,MAAM,GAAG,YAAY,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;YACnD,MAAM,MAAM,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YACjD,KAAK,MAAM,KAAK,IAAI,MAAM;gBAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACxD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAC1E,CAAC,CAAC,CAAC;IACP,MAAM,gBAAgB,GAAG,YAAY,CAAC,4BAA4B;QAChE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,4BAA6B,CAAC,IAAI,CAAC,CAAC;QAChF,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;YAC1B,MAAM,MAAM,GAAG,YAAY,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC;YACvD,MAAM,MAAM,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YACjD,KAAK,MAAM,KAAK,IAAI,MAAM;gBAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACxD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAC1E,CAAC,CAAC,CAAC;IACP,MAAM,CAAC,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,CAAC,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC;QAC7F,cAAc;QACd,aAAa;QACb,aAAa;QACb,gBAAgB;QAChB,YAAY,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC;KACjD,CAAC,CAAC;IAEH,IAAI,UAAU,CAAC,MAAM,KAAK,UAAU;QAAE,aAAa,CAAC,MAAM,EAAE,iBAAiB,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IAClG,IAAI,SAAS,CAAC,MAAM,KAAK,UAAU;QAAE,aAAa,CAAC,KAAK,EAAE,gBAAgB,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;IAC9F,IAAI,SAAS,CAAC,MAAM,KAAK,UAAU;QAAE,aAAa,CAAC,KAAK,EAAE,cAAc,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;IAC5F,IAAI,YAAY,CAAC,MAAM,KAAK,UAAU;QAAE,aAAa,CAAC,QAAQ,EAAE,kBAAkB,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IACzG,IAAI,WAAW,CAAC,MAAM,KAAK,UAAU;QAAE,aAAa,CAAC,OAAO,EAAE,eAAe,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAEnG,OAAO,sBAAsB,CAAC;QAC5B,YAAY;QACZ,UAAU,EAAE,GAAG,KAAK,SAAS;QAC7B,YAAY,EAAE,UAAU,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;QAChF,iBAAiB,EAAE,UAAU,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACjF,aAAa,EAAE,UAAU,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK;QACrF,UAAU,EAAE,UAAU,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;QACnF,WAAW,EAAE,SAAS,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;QAC7E,gBAAgB,EAAE,SAAS,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC9E,YAAY,EAAE,SAAS,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK;QAClF,SAAS,EAAE,SAAS,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;QAChF,SAAS,EAAE,SAAS,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;QACzE,cAAc,EAAE,SAAS,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QAClF,YAAY,EAAE,SAAS,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK;QAClF,SAAS,EAAE,SAAS,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;QAChF,YAAY,EAAE,YAAY,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;QAClF,iBAAiB,EAAE,YAAY,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QAC3F,eAAe,EAAE,YAAY,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK;QAC3F,YAAY,EAAE,YAAY,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;QACzF,KAAK,EAAE,WAAW,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;QAClE,YAAY;QACZ,MAAM;KACP,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,cAAc,EAAE,EACtD;QACE,YAAY,EACV,6TAA6T;KAChU,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,YAAY,EACZ;QACE,KAAK,EAAE,qBAAqB;QAC5B,WAAW,EACT,kIAAkI;QACpI,WAAW,EAAE;YACX,QAAQ,EAAE,cAAc,CAAC,QAAQ,CAAC,sDAAsD,CAAC;SAC1F;QACD,YAAY,EAAE;YACZ,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC;YACjC,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;YAC7C,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE;YACtB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SAC7B;QACD,WAAW,EAAE,2BAA2B;KACzC,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;YAC1D,MAAM,UAAU,GAAG,MAAM,2BAA2B,CAAC,IAAI,CAAC,CAAC;YAC3D,OAAO,MAAM,CACX,EAAE,MAAM,EAAE,UAAU,CAAC,QAAQ,EAAE,aAAa,EAAE,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,UAAU,CAAC,SAAS,EAAE,EACjG,qBAAqB,CAAC,UAAU,CAAC,QAAQ,EAAE,SAAS,EAAE,UAAU,CAAC,KAAK,EAAE,UAAU,CAAC,MAAM,CAAC,CAC3F,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;YACrC,OAAO,MAAM,CACX,EAAE,MAAM,EAAE,EAAE,EAAE,aAAa,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,EACzD,cAAc,CACZ,iBAAiB,EACjB,KAAK,EACL,0GAA0G,CAC3G,EACD,IAAI,CACL,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,UAAU,EACV;QACE,KAAK,EAAE,uBAAuB;QAC9B,WAAW,EACT,2KAA2K;QAC7K,WAAW,EAAE;YACX,GAAG,EAAE,eAAe,CAAC,QAAQ,CAAC,uCAAuC,CAAC;SACvE;QACD,YAAY,EAAE;YACZ,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC;YACjC,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;YAC7C,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE;YACtB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;YACjC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SAC7B;QACD,WAAW,EAAE,2BAA2B;KACzC,EACD,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE;QAChB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE;gBACzC,QAAQ,EAAE,cAAc;gBACxB,SAAS,EAAE,MAAM;gBACjB,YAAY,EAAE,CAAC;gBACf,oBAAoB,EAAE,CAAC,WAAW,EAAE,uBAAuB,CAAC;gBAC5D,OAAO,EAAE;oBACP,MAAM,EAAE,uCAAuC;oBAC/C,YAAY,EAAE,2BAA2B,cAAc,0CAA0C;iBAClG;aACF,CAAC,CAAC;YACH,IAAI,OAAO,CAAC,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;gBAClD,MAAM,IAAI,KAAK,CAAC,4BAA4B,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;YACjE,CAAC;YACD,MAAM,UAAU,GAAG,MAAM,2BAA2B,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACnE,OAAO,MAAM,CACX;gBACE,MAAM,EAAE,UAAU,CAAC,QAAQ;gBAC3B,aAAa,EAAE,UAAU,CAAC,KAAK;gBAC/B,SAAS,EAAE,UAAU,CAAC,SAAS;gBAC/B,UAAU,EAAE,OAAO,CAAC,GAAG;aACxB,EACD,qBAAqB,CAAC,UAAU,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,EAAE,UAAU,CAAC,KAAK,EAAE,UAAU,CAAC,MAAM,CAAC,CAC7F,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;YACrC,OAAO,MAAM,CACX,EAAE,MAAM,EAAE,EAAE,EAAE,aAAa,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,EACzD,cAAc,CACZ,gBAAgB,EAChB,KAAK,EACL,iGAAiG,CAClG,EACD,IAAI,CACL,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,WAAW,EACX;QACE,KAAK,EAAE,oBAAoB;QAC3B,WAAW,EACT,8HAA8H;QAChI,WAAW,EAAE;YACX,QAAQ,EAAE,cAAc,CAAC,QAAQ,CAAC,oDAAoD,CAAC;SACxF;QACD,YAAY,EAAE;YACZ,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC;YACjC,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;YAC7C,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE;YACtB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SAC7B;QACD,WAAW,EAAE,2BAA2B;KACzC,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;YACxD,MAAM,UAAU,GAAG,MAAM,0BAA0B,CAAC,GAAG,CAAC,CAAC;YACzD,OAAO,MAAM,CACX;gBACE,MAAM,EAAE,UAAU,CAAC,QAAQ;gBAC3B,aAAa,EAAE,UAAU,CAAC,KAAK;gBAC/B,SAAS,EAAE,UAAU,CAAC,SAAS;aAChC,EACD,oBAAoB,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,KAAK,EAAE,UAAU,CAAC,MAAM,CAAC,CAC/E,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;YACrC,OAAO,MAAM,CACX,EAAE,MAAM,EAAE,EAAE,EAAE,aAAa,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,EACzD,cAAc,CACZ,gBAAgB,EAChB,KAAK,EACL,iFAAiF,CAClF,EACD,IAAI,CACL,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;QACE,KAAK,EAAE,oBAAoB;QAC3B,WAAW,EACT,oIAAoI;QACtI,WAAW,EAAE;YACX,WAAW,EAAE,iBAAiB,CAAC,QAAQ,CAAC,qCAAqC,CAAC;SAC/E;QACD,YAAY,EAAE;YACZ,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC;YAC/B,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;YAC3C,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE;YACtB,MAAM,EAAE,iBAAiB;YACzB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SAC7B;QACD,WAAW,EAAE,wBAAwB;KACtC,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE;QACxB,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,wBAAwB,CAAC,WAAW,CAAC,CAAC;YACzF,OAAO,MAAM,CACX,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,EAC1C,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,CAAC,CACxD,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;YACrC,OAAO,MAAM,CACX,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,EAClG,cAAc,CACZ,WAAW,EACX,KAAK,EACL,8EAA8E,CAC/E,EACD,IAAI,CACL,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;QACE,KAAK,EAAE,oBAAoB;QAC3B,WAAW,EACT,iJAAiJ;QACnJ,WAAW,EAAE;YACX,WAAW,EAAE,iBAAiB,CAAC,QAAQ,CAAC,4CAA4C,CAAC;YACrF,OAAO,EAAE,eAAe;iBACrB,QAAQ,EAAE;iBACV,QAAQ,CAAC,kEAAkE,CAAC;YAC/E,QAAQ,EAAE,CAAC;iBACR,MAAM,EAAE;iBACR,GAAG,EAAE;iBACL,GAAG,CAAC,CAAC,CAAC;iBACN,GAAG,CAAC,EAAE,CAAC;iBACP,OAAO,CAAC,EAAE,CAAC;iBACX,QAAQ,CAAC,gEAAgE,CAAC;SAC9E;QACD,YAAY,EAAE;YACZ,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC;YAChC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SAC7B;QACD,WAAW,EAAE,2BAA2B;KACzC,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC3C,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;YACrE,OAAO,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;QAC7D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;YACrC,OAAO,MAAM,CACX,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EACpB,cAAc,CACZ,YAAY,EACZ,KAAK,EACL,4FAA4F,CAC7F,EACD,IAAI,CACL,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,eAAe,EACf;QACE,KAAK,EAAE,yBAAyB;QAChC,WAAW,EACT,2IAA2I;QAC7I,WAAW,EAAE;YACX,WAAW,EAAE,iBAAiB,CAAC,QAAQ,CAAC,4CAA4C,CAAC;SACtF;QACD,YAAY,EAAE;YACZ,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC;YAC/B,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;YAC3C,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE;YACtB,MAAM,EAAE,iBAAiB;YACzB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SAC7B;QACD,WAAW,EAAE,wBAAwB;KACtC,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE;QACxB,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,4BAA4B,CAAC,WAAW,CAAC,CAAC;YAC7F,OAAO,MAAM,CACX,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,EAC1C,uBAAuB,CAAC,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,CAAC,CACrE,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;YACrC,OAAO,MAAM,CACX,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,EAClG,cAAc,CACZ,gBAAgB,EAChB,KAAK,EACL,8EAA8E,CAC/E,EACD,IAAI,CACL,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,mBAAmB,EACnB;QACE,KAAK,EAAE,8BAA8B;QACrC,WAAW,EACT,iKAAiK;QACnK,WAAW,EAAE;YACX,YAAY,EAAE,cAAc,CAAC,QAAQ,CAAC,gDAAgD,CAAC;YACvF,WAAW,EAAE,cAAc;iBACxB,QAAQ,EAAE;iBACV,QAAQ,CAAC,wDAAwD,CAAC;YACrE,OAAO,EAAE,eAAe;iBACrB,QAAQ,EAAE;iBACV,QAAQ,CAAC,kEAAkE,CAAC;SAChF;QACD,YAAY,EAAE;YACZ,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;YAClB,OAAO,EAAE,mBAAmB;YAC5B,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC;YACvC,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;YACjD,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE;YAC1B,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC;YACtC,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;YAChD,YAAY,EAAE,CAAC,CAAC,OAAO,EAAE;YACzB,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC;YAClC,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;YAC9C,YAAY,EAAE,CAAC,CAAC,OAAO,EAAE;YACzB,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC;YACrC,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;YACjD,eAAe,EAAE,CAAC,CAAC,OAAO,EAAE;YAC5B,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC;YAChC,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;YACrD,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;SACvC;QACD,WAAW,EAAE,2BAA2B;KACzC,EACD,KAAK,EAAE,EAAE,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,EAAE;QAC/C,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,MAAM,wBAAwB,CAAC;gBAChD,YAAY;gBACZ,WAAW;gBACX,OAAO;aACR,CAAC,CAAC;YACH,OAAO,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC;QACvD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;YACrC,MAAM,UAAU,GAAG,YAAY,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;YACrD,OAAO,MAAM,CACX,UAAU,EACV,cAAc,CACZ,mBAAmB,EACnB,KAAK,EACL,8FAA8F,CAC/F,EACD,IAAI,CACL,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,oBAAoB,EACpB;QACE,KAAK,EAAE,gCAAgC;QACvC,WAAW,EACT,gQAAgQ;QAClQ,WAAW,EAAE;YACX,UAAU,EAAE,CAAC;iBACV,MAAM,EAAE;iBACR,IAAI,EAAE;iBACN,GAAG,CAAC,CAAC,CAAC;iBACN,GAAG,CAAC,eAAe,CAAC;iBACpB,QAAQ,CAAC,2CAA2C,CAAC;YACxD,SAAS,EAAE,cAAc;iBACtB,QAAQ,EAAE;iBACV,OAAO,CAAC,4BAA4B,CAAC;iBACrC,QAAQ,CAAC,kDAAkD,CAAC;YAC/D,SAAS,EAAE,CAAC;iBACT,KAAK,CACJ,CAAC,CAAC,MAAM,CAAC;gBACP,IAAI,EAAE,CAAC;qBACJ,MAAM,EAAE;qBACR,KAAK,CAAC,uBAAuB,CAAC;qBAC9B,QAAQ,CAAC,mDAAmD,CAAC;gBAChE,KAAK,EAAE,CAAC;qBACL,MAAM,EAAE;qBACR,GAAG,EAAE;qBACL,GAAG,CAAC,GAAG,CAAC;qBACR,GAAG,CAAC,KAAK,CAAC;qBACV,QAAQ,CAAC,iDAAiD,CAAC;gBAC9D,MAAM,EAAE,CAAC;qBACN,MAAM,EAAE;qBACR,GAAG,EAAE;qBACL,GAAG,CAAC,GAAG,CAAC;qBACR,GAAG,CAAC,KAAK,CAAC;qBACV,QAAQ,CAAC,kDAAkD,CAAC;aAChE,CAAC,CACH;iBACA,GAAG,CAAC,CAAC,CAAC;iBACN,GAAG,CAAC,aAAa,CAAC;iBAClB,QAAQ,EAAE;iBACV,QAAQ,CAAC,+EAA+E,CAAC;SAC7F;QACD,YAAY,EAAE;YACZ,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC;YACtC,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE;YAC3B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SAC7B;QACD,WAAW,EAAE;YACX,YAAY,EAAE,KAAK;YACnB,eAAe,EAAE,IAAI;YACrB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,IAAI;SACpB;KACF,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,EAAE;QAC7C,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAChD,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,MAAM,kBAAkB,CAAC,UAAU,EAAE,eAAe,EAAE,SAAS,CAAC,CAAC;YACrF,OAAO,MAAM,CACX,EAAE,WAAW,EAAE,eAAe,EAAE,EAChC,wBAAwB,CAAC,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,CAC9D,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;YACrC,OAAO,MAAM,CACX,EAAE,WAAW,EAAE,EAAE,EAAE,eAAe,EAAE,KAAK,EAAE,EAC3C,cAAc,CACZ,oBAAoB,EACpB,KAAK,EACL,+FAA+F,CAChG,EACD,IAAI,CACL,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,GAAG;IACvB,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC;IACjD,OAAO,CAAC,KAAK,CAAC,qBAAqB,cAAc,mBAAmB,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AACpG,IAAI,WAAW,KAAK,OAAO,IAAI,CAAC,GAAG,EAAE,CAAC;IACpC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QAC7B,OAAO,CAAC,KAAK,CAAC,yCAAyC,EAAE,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC;QACjF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["#!/usr/bin/env node\nimport * as path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { z } from \"zod\";\nimport { captureScreenshots } from \"./screenshot.js\";\nimport {\n auditSeoMetadata,\n auditSeoMetadataDetailed,\n checkBrokenLinks,\n validateSchemaMarkup,\n validateSchemaMarkupDetailed,\n} from \"./seo-auditor.js\";\nimport {\n createValidationReport,\n type ValidationReport,\n type ValidationReportCheck,\n validationReportChecks,\n} from \"./report.js\";\nimport { fetchPublicText, getErrorMessage, readTextFile } from \"./network.js\";\nimport {\n cssValidationContent,\n failureContent,\n htmlValidationContent,\n linkCheckContent,\n reportContent,\n schemaValidationContent,\n screenshotCaptureContent,\n seoAuditContent,\n} from \"./presentation.js\";\nimport { PACKAGE_VERSION } from \"./version.js\";\nimport {\n getW3CMessageSeverity,\n MAX_CSS_VALIDATION_BYTES,\n validateCssContent,\n validateCssContentDetailed,\n validateHtmlContent,\n validateHtmlContentDetailed,\n} from \"./w3c-validator.js\";\n\nexport const SERVER_VERSION = PACKAGE_VERSION;\n\nconst HTML_MAX_BYTES = 2_000_000;\nconst CSS_MAX_BYTES = MAX_CSS_VALIDATION_BYTES;\nconst PATH_MAX_LENGTH = 4_096;\nconst MAX_VIEWPORTS = 8;\n\nconst filePathSchema = z.string().trim().min(1).max(PATH_MAX_LENGTH);\nconst htmlContentSchema = z.string().min(1).max(HTML_MAX_BYTES);\nconst publicUrlSchema = z\n .string()\n .url()\n .refine((value) => {\n const protocol = new URL(value).protocol;\n return protocol === \"http:\" || protocol === \"https:\";\n }, \"URL must use HTTP or HTTPS.\");\n\nconst w3cMessageSchema = z.object({\n type: z.string(),\n subType: z.string().optional(),\n message: z.string(),\n lastLine: z.number().int().optional(),\n lastColumn: z.number().int().optional(),\n firstLine: z.number().int().optional(),\n firstColumn: z.number().int().optional(),\n extract: z.string().optional(),\n});\n\nconst cssMessageSchema = z.object({\n line: z.number().int(),\n type: z.string(),\n message: z.string(),\n context: z.string().optional(),\n compatibility: z.literal(\"known-validator-limitation\").optional(),\n});\n\nconst seoIssueSchema = z.object({\n code: z.string().describe(\"Stable machine-readable audit rule identifier.\"),\n severity: z.enum([\"error\", \"warning\", \"info\"]),\n category: z.enum([\"SEO\", \"Schema\", \"BrokenLinks\", \"Accessibility\"]),\n message: z.string(),\n element: z.string().optional(),\n});\n\nconst auditCountsSchema = z.object({\n error: z.number().int().nonnegative(),\n warning: z.number().int().nonnegative(),\n info: z.number().int().nonnegative(),\n});\n\nconst linkStatusSchema = z.object({\n url: z.string(),\n status: z.union([z.number().int(), z.enum([\"blocked\", \"failed\"])]),\n ok: z.boolean(),\n message: z.string().optional(),\n});\n\nconst screenshotSchema = z.object({\n viewportName: z.string(),\n width: z.number().int(),\n height: z.number().int(),\n outputPath: z.string(),\n});\n\nconst reportSummarySchema = z.object({\n overallScore: z.number().int().min(0).max(100).nullable(),\n htmlScore: z.number().int().min(0).max(100).nullable(),\n cssScore: z.number().int().min(0).max(100).nullable(),\n seoScore: z.number().int().min(0).max(100).nullable(),\n linkScore: z.number().int().min(0).max(100).nullable(),\n htmlErrors: z.number().int().nonnegative(),\n htmlWarnings: z.number().int().nonnegative(),\n cssErrors: z.number().int().nonnegative(),\n cssCompatibilityLimitations: z.number().int().nonnegative(),\n seoErrors: z.number().int().nonnegative(),\n seoWarnings: z.number().int().nonnegative(),\n schemaErrors: z.number().int().nonnegative(),\n linksChecked: z.number().int().nonnegative(),\n brokenLinks: z.number().int().nonnegative(),\n});\n\nconst externalReadOnlyAnnotations = {\n // These calls contact external recipients but do not modify external state.\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: true,\n} as const;\n\nconst localReadOnlyAnnotations = {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n} as const;\n\nfunction result<T extends object>(\n structuredContent: T,\n content: string,\n isError = false,\n): CallToolResult {\n return {\n structuredContent: structuredContent as Record<string, unknown>,\n content: [\n {\n type: \"text\",\n text: content,\n },\n ],\n ...(isError ? { isError: true } : {}),\n };\n}\n\nfunction failedReport(filePath: string, error: string): ValidationReport {\n return {\n report: `Validation report could not be generated: ${error}`,\n summary: {\n overallScore: null,\n htmlScore: null,\n cssScore: null,\n seoScore: null,\n linkScore: null,\n htmlErrors: 0,\n htmlWarnings: 0,\n cssErrors: 0,\n cssCompatibilityLimitations: 0,\n seoErrors: 0,\n seoWarnings: 0,\n schemaErrors: 0,\n linksChecked: 0,\n brokenLinks: 0,\n },\n htmlMessages: [],\n htmlTotalMessages: 0,\n htmlTruncated: false,\n cssMessages: [],\n cssTotalMessages: 0,\n cssTruncated: false,\n seoIssues: [],\n seoTotalIssues: 0,\n seoTruncated: false,\n schemaIssues: [],\n schemaTotalIssues: 0,\n schemaTruncated: false,\n links: [],\n failedChecks: [\"input\"],\n errors: [`${path.basename(filePath || \"document\")}: ${error}`],\n };\n}\n\ninterface ValidationReportDependencies {\n readTextFile: typeof readTextFile;\n validateHtmlContent: typeof validateHtmlContent;\n validateHtmlContentDetailed?: typeof validateHtmlContentDetailed;\n validateCssContent: typeof validateCssContent;\n validateCssContentDetailed?: typeof validateCssContentDetailed;\n auditSeoMetadata: typeof auditSeoMetadata;\n auditSeoMetadataDetailed?: typeof auditSeoMetadataDetailed;\n validateSchemaMarkup: typeof validateSchemaMarkup;\n validateSchemaMarkupDetailed?: typeof validateSchemaMarkupDetailed;\n checkBrokenLinks: typeof checkBrokenLinks;\n}\n\nconst validationReportDependencies: ValidationReportDependencies = {\n readTextFile,\n validateHtmlContent,\n validateHtmlContentDetailed,\n validateCssContent,\n validateCssContentDetailed,\n auditSeoMetadata,\n auditSeoMetadataDetailed,\n validateSchemaMarkup,\n validateSchemaMarkupDetailed,\n checkBrokenLinks,\n};\n\nexport interface GenerateValidationReportOptions {\n htmlFilePath: string;\n cssFilePath?: string;\n baseUrl?: string;\n}\n\n/** Runs independent validation checks without discarding successful results when another check fails. */\nexport async function generateValidationReport(\n { htmlFilePath, cssFilePath, baseUrl }: GenerateValidationReportOptions,\n dependencies: ValidationReportDependencies = validationReportDependencies,\n): Promise<ValidationReport> {\n const html = await dependencies.readTextFile(htmlFilePath, HTML_MAX_BYTES);\n const failedChecks: ValidationReportCheck[] = [];\n const errors: string[] = [];\n const recordFailure = (check: ValidationReportCheck, label: string, cause: unknown): void => {\n if (!failedChecks.includes(check)) {\n failedChecks.push(check);\n }\n errors.push(`${label} was unavailable: ${getErrorMessage(cause)}`);\n };\n\n let css: string | undefined;\n if (cssFilePath) {\n try {\n css = await dependencies.readTextFile(cssFilePath, CSS_MAX_BYTES);\n } catch (cause) {\n recordFailure(\"css\", \"CSS validation\", cause);\n }\n }\n\n const htmlValidation = dependencies.validateHtmlContentDetailed\n ? dependencies.validateHtmlContentDetailed(html)\n : dependencies.validateHtmlContent(html).then((messages) => {\n const counts = { error: 0, warning: 0, info: 0 };\n for (const message of messages) counts[getW3CMessageSeverity(message)] += 1;\n return { messages, total: messages.length, truncated: false, counts };\n });\n const cssValidation = css === undefined\n ? Promise.resolve({\n messages: [],\n total: 0,\n truncated: false,\n counts: { error: 0, compatibilityLimitation: 0 },\n })\n : dependencies.validateCssContentDetailed\n ? dependencies.validateCssContentDetailed(css)\n : dependencies.validateCssContent(css).then((messages) => {\n const compatibilityLimitation = messages.filter(\n (message) => message.compatibility === \"known-validator-limitation\",\n ).length;\n return {\n messages,\n total: messages.length,\n truncated: false,\n counts: {\n error: messages.length - compatibilityLimitation,\n compatibilityLimitation,\n },\n };\n });\n const seoValidation = dependencies.auditSeoMetadataDetailed\n ? Promise.resolve().then(() => dependencies.auditSeoMetadataDetailed!(html))\n : Promise.resolve().then(() => {\n const issues = dependencies.auditSeoMetadata(html);\n const counts = { error: 0, warning: 0, info: 0 };\n for (const issue of issues) counts[issue.severity] += 1;\n return { issues, totalIssues: issues.length, truncated: false, counts };\n });\n const schemaValidation = dependencies.validateSchemaMarkupDetailed\n ? Promise.resolve().then(() => dependencies.validateSchemaMarkupDetailed!(html))\n : Promise.resolve().then(() => {\n const issues = dependencies.validateSchemaMarkup(html);\n const counts = { error: 0, warning: 0, info: 0 };\n for (const issue of issues) counts[issue.severity] += 1;\n return { issues, totalIssues: issues.length, truncated: false, counts };\n });\n const [htmlResult, cssResult, seoResult, schemaResult, linksResult] = await Promise.allSettled([\n htmlValidation,\n cssValidation,\n seoValidation,\n schemaValidation,\n dependencies.checkBrokenLinks(html, baseUrl, 25),\n ]);\n\n if (htmlResult.status === \"rejected\") recordFailure(\"html\", \"HTML validation\", htmlResult.reason);\n if (cssResult.status === \"rejected\") recordFailure(\"css\", \"CSS validation\", cssResult.reason);\n if (seoResult.status === \"rejected\") recordFailure(\"seo\", \"SEO analysis\", seoResult.reason);\n if (schemaResult.status === \"rejected\") recordFailure(\"schema\", \"JSON-LD analysis\", schemaResult.reason);\n if (linksResult.status === \"rejected\") recordFailure(\"links\", \"Link checking\", linksResult.reason);\n\n return createValidationReport({\n htmlFilePath,\n cssAudited: css !== undefined,\n htmlMessages: htmlResult.status === \"fulfilled\" ? htmlResult.value.messages : [],\n htmlTotalMessages: htmlResult.status === \"fulfilled\" ? htmlResult.value.total : 0,\n htmlTruncated: htmlResult.status === \"fulfilled\" ? htmlResult.value.truncated : false,\n htmlCounts: htmlResult.status === \"fulfilled\" ? htmlResult.value.counts : undefined,\n cssMessages: cssResult.status === \"fulfilled\" ? cssResult.value.messages : [],\n cssTotalMessages: cssResult.status === \"fulfilled\" ? cssResult.value.total : 0,\n cssTruncated: cssResult.status === \"fulfilled\" ? cssResult.value.truncated : false,\n cssCounts: cssResult.status === \"fulfilled\" ? cssResult.value.counts : undefined,\n seoIssues: seoResult.status === \"fulfilled\" ? seoResult.value.issues : [],\n seoTotalIssues: seoResult.status === \"fulfilled\" ? seoResult.value.totalIssues : 0,\n seoTruncated: seoResult.status === \"fulfilled\" ? seoResult.value.truncated : false,\n seoCounts: seoResult.status === \"fulfilled\" ? seoResult.value.counts : undefined,\n schemaIssues: schemaResult.status === \"fulfilled\" ? schemaResult.value.issues : [],\n schemaTotalIssues: schemaResult.status === \"fulfilled\" ? schemaResult.value.totalIssues : 0,\n schemaTruncated: schemaResult.status === \"fulfilled\" ? schemaResult.value.truncated : false,\n schemaCounts: schemaResult.status === \"fulfilled\" ? schemaResult.value.counts : undefined,\n links: linksResult.status === \"fulfilled\" ? linksResult.value : [],\n failedChecks,\n errors,\n });\n}\n\nexport function createServer(): McpServer {\n const server = new McpServer(\n { name: \"mcp-web-validator\", version: SERVER_VERSION },\n {\n instructions:\n \"Validate only files, markup, and public URLs the user owns or is authorized to inspect. HTML and CSS validation send supplied content to W3C-operated validators. Link checks contact public links without following redirects. Screenshot capture executes page content in a sandboxed local browser and writes PNG files.\",\n },\n );\n\n server.registerTool(\n \"html.local\",\n {\n title: \"Validate local HTML\",\n description:\n \"Reads a bounded local HTML file and sends its markup to the W3C Nu HTML Checker. Use only files the user is authorized to share.\",\n inputSchema: {\n filePath: filePathSchema.describe(\"Absolute or workspace-relative path to an HTML file.\"),\n },\n outputSchema: {\n errors: z.array(w3cMessageSchema),\n totalMessages: z.number().int().nonnegative(),\n truncated: z.boolean(),\n error: z.string().optional(),\n },\n annotations: externalReadOnlyAnnotations,\n },\n async ({ filePath }) => {\n try {\n const html = await readTextFile(filePath, HTML_MAX_BYTES);\n const validation = await validateHtmlContentDetailed(html);\n return result(\n { errors: validation.messages, totalMessages: validation.total, truncated: validation.truncated },\n htmlValidationContent(validation.messages, undefined, validation.total, validation.counts),\n );\n } catch (cause) {\n const error = getErrorMessage(cause);\n return result(\n { errors: [], totalMessages: 0, truncated: false, error },\n failureContent(\n \"HTML validation\",\n error,\n \"Confirm the file exists and is readable, then retry. If the W3C service is unavailable, try again later.\",\n ),\n true,\n );\n }\n },\n );\n\n server.registerTool(\n \"html.url\",\n {\n title: \"Validate a public URL\",\n description:\n \"Fetches a bounded public HTTP(S) page, then sends its markup to the W3C Nu HTML Checker. Private, reserved, credentialed, and nonstandard-port destinations are rejected.\",\n inputSchema: {\n url: publicUrlSchema.describe(\"Public HTTP(S) URL on port 80 or 443.\"),\n },\n outputSchema: {\n errors: z.array(w3cMessageSchema),\n totalMessages: z.number().int().nonnegative(),\n truncated: z.boolean(),\n fetchedUrl: z.string().optional(),\n error: z.string().optional(),\n },\n annotations: externalReadOnlyAnnotations,\n },\n async ({ url }) => {\n try {\n const fetched = await fetchPublicText(url, {\n maxBytes: HTML_MAX_BYTES,\n timeoutMs: 15_000,\n maxRedirects: 3,\n acceptedContentTypes: [\"text/html\", \"application/xhtml+xml\"],\n headers: {\n accept: \"text/html,application/xhtml+xml;q=0.9\",\n \"user-agent\": `DigestSEO-Web-Validator/${SERVER_VERSION} (+https://digestseo.com/validator-mcp/)`,\n },\n });\n if (fetched.status < 200 || fetched.status >= 300) {\n throw new Error(`Target URL returned HTTP ${fetched.status}.`);\n }\n const validation = await validateHtmlContentDetailed(fetched.text);\n return result(\n {\n errors: validation.messages,\n totalMessages: validation.total,\n truncated: validation.truncated,\n fetchedUrl: fetched.url,\n },\n htmlValidationContent(validation.messages, fetched.url, validation.total, validation.counts),\n );\n } catch (cause) {\n const error = getErrorMessage(cause);\n return result(\n { errors: [], totalMessages: 0, truncated: false, error },\n failureContent(\n \"URL validation\",\n error,\n \"Confirm the URL is public, uses HTTP or HTTPS on a standard port, and returns HTML, then retry.\",\n ),\n true,\n );\n }\n },\n );\n\n server.registerTool(\n \"css.local\",\n {\n title: \"Validate local CSS\",\n description:\n \"Reads a bounded local CSS file and sends it to the W3C Jigsaw CSS Validator. Use only files the user is authorized to share.\",\n inputSchema: {\n filePath: filePathSchema.describe(\"Absolute or workspace-relative path to a CSS file.\"),\n },\n outputSchema: {\n errors: z.array(cssMessageSchema),\n totalMessages: z.number().int().nonnegative(),\n truncated: z.boolean(),\n error: z.string().optional(),\n },\n annotations: externalReadOnlyAnnotations,\n },\n async ({ filePath }) => {\n try {\n const css = await readTextFile(filePath, CSS_MAX_BYTES);\n const validation = await validateCssContentDetailed(css);\n return result(\n {\n errors: validation.messages,\n totalMessages: validation.total,\n truncated: validation.truncated,\n },\n cssValidationContent(validation.messages, validation.total, validation.counts),\n );\n } catch (cause) {\n const error = getErrorMessage(cause);\n return result(\n { errors: [], totalMessages: 0, truncated: false, error },\n failureContent(\n \"CSS validation\",\n error,\n \"Confirm the file exists, is readable, and is within the size limit, then retry.\",\n ),\n true,\n );\n }\n },\n );\n\n server.registerTool(\n \"seo.metadata\",\n {\n title: \"Audit SEO metadata\",\n description:\n \"Analyzes supplied HTML locally for metadata, heading structure, viewport configuration, image alternatives, and Open Graph fields.\",\n inputSchema: {\n htmlContent: htmlContentSchema.describe(\"Raw HTML markup to inspect locally.\"),\n },\n outputSchema: {\n issues: z.array(seoIssueSchema),\n totalIssues: z.number().int().nonnegative(),\n truncated: z.boolean(),\n counts: auditCountsSchema,\n error: z.string().optional(),\n },\n annotations: localReadOnlyAnnotations,\n },\n async ({ htmlContent }) => {\n try {\n const { issues, totalIssues, truncated, counts } = auditSeoMetadataDetailed(htmlContent);\n return result(\n { issues, totalIssues, truncated, counts },\n seoAuditContent(issues, totalIssues, truncated, counts),\n );\n } catch (cause) {\n const error = getErrorMessage(cause);\n return result(\n { issues: [], totalIssues: 0, truncated: false, counts: { error: 0, warning: 0, info: 0 }, error },\n failureContent(\n \"SEO audit\",\n error,\n \"Confirm the supplied HTML is complete and within the size limit, then retry.\",\n ),\n true,\n );\n }\n },\n );\n\n server.registerTool(\n \"links.broken\",\n {\n title: \"Check public links\",\n description:\n \"Resolves and checks up to 25 public HTTP(S) links in supplied HTML. Redirects are reported but not followed, and response bodies are discarded.\",\n inputSchema: {\n htmlContent: htmlContentSchema.describe(\"Raw HTML markup containing links to check.\"),\n baseUrl: publicUrlSchema\n .optional()\n .describe(\"Optional public HTTP(S) base URL used to resolve relative links.\"),\n maxLinks: z\n .number()\n .int()\n .min(1)\n .max(25)\n .default(25)\n .describe(\"Maximum number of public HTTP(S) links to check, from 1 to 25.\"),\n },\n outputSchema: {\n links: z.array(linkStatusSchema),\n error: z.string().optional(),\n },\n annotations: externalReadOnlyAnnotations,\n },\n async ({ htmlContent, baseUrl, maxLinks }) => {\n try {\n const links = await checkBrokenLinks(htmlContent, baseUrl, maxLinks);\n return result({ links }, linkCheckContent(links, baseUrl));\n } catch (cause) {\n const error = getErrorMessage(cause);\n return result(\n { links: [], error },\n failureContent(\n \"Link check\",\n error,\n \"Confirm the base URL is public and the supplied HTML is within the size limit, then retry.\",\n ),\n true,\n );\n }\n },\n );\n\n server.registerTool(\n \"schema.markup\",\n {\n title: \"Validate JSON-LD syntax\",\n description:\n \"Parses JSON-LD blocks in supplied HTML locally and reports empty blocks or JSON syntax errors. It does not validate vocabulary semantics.\",\n inputSchema: {\n htmlContent: htmlContentSchema.describe(\"Raw HTML containing JSON-LD script blocks.\"),\n },\n outputSchema: {\n issues: z.array(seoIssueSchema),\n totalIssues: z.number().int().nonnegative(),\n truncated: z.boolean(),\n counts: auditCountsSchema,\n error: z.string().optional(),\n },\n annotations: localReadOnlyAnnotations,\n },\n async ({ htmlContent }) => {\n try {\n const { issues, totalIssues, truncated, counts } = validateSchemaMarkupDetailed(htmlContent);\n return result(\n { issues, totalIssues, truncated, counts },\n schemaValidationContent(issues, totalIssues, truncated, htmlContent),\n );\n } catch (cause) {\n const error = getErrorMessage(cause);\n return result(\n { issues: [], totalIssues: 0, truncated: false, counts: { error: 0, warning: 0, info: 0 }, error },\n failureContent(\n \"JSON-LD syntax\",\n error,\n \"Confirm the supplied HTML is complete and within the size limit, then retry.\",\n ),\n true,\n );\n }\n },\n );\n\n server.registerTool(\n \"report.validation\",\n {\n title: \"Generate a validation report\",\n description:\n \"Combines W3C HTML/CSS validation, local SEO/accessibility checks, JSON-LD syntax checks, and a bounded public-link check into a Markdown and structured report.\",\n inputSchema: {\n htmlFilePath: filePathSchema.describe(\"Absolute or workspace-relative HTML file path.\"),\n cssFilePath: filePathSchema\n .optional()\n .describe(\"Optional absolute or workspace-relative CSS file path.\"),\n baseUrl: publicUrlSchema\n .optional()\n .describe(\"Optional public HTTP(S) base URL used to resolve relative links.\"),\n },\n outputSchema: {\n report: z.string(),\n summary: reportSummarySchema,\n htmlMessages: z.array(w3cMessageSchema),\n htmlTotalMessages: z.number().int().nonnegative(),\n htmlTruncated: z.boolean(),\n cssMessages: z.array(cssMessageSchema),\n cssTotalMessages: z.number().int().nonnegative(),\n cssTruncated: z.boolean(),\n seoIssues: z.array(seoIssueSchema),\n seoTotalIssues: z.number().int().nonnegative(),\n seoTruncated: z.boolean(),\n schemaIssues: z.array(seoIssueSchema),\n schemaTotalIssues: z.number().int().nonnegative(),\n schemaTruncated: z.boolean(),\n links: z.array(linkStatusSchema),\n failedChecks: z.array(z.enum(validationReportChecks)),\n errors: z.array(z.string()).optional(),\n },\n annotations: externalReadOnlyAnnotations,\n },\n async ({ htmlFilePath, cssFilePath, baseUrl }) => {\n try {\n const reportData = await generateValidationReport({\n htmlFilePath,\n cssFilePath,\n baseUrl,\n });\n return result(reportData, reportContent(reportData));\n } catch (cause) {\n const error = getErrorMessage(cause);\n const reportData = failedReport(htmlFilePath, error);\n return result(\n reportData,\n failureContent(\n \"Validation report\",\n error,\n \"Confirm the input paths are readable and any base URL is public, then regenerate the report.\",\n ),\n true,\n );\n }\n },\n );\n\n server.registerTool(\n \"screenshot.capture\",\n {\n title: \"Capture responsive screenshots\",\n description:\n \"Renders a local HTML file or HTTP(S) URL in a sandboxed local Chromium browser and writes PNG screenshots to the requested directory. Downloads the pinned headless browser on first use if it is not already cached. Existing matching files may be replaced.\",\n inputSchema: {\n targetPath: z\n .string()\n .trim()\n .min(1)\n .max(PATH_MAX_LENGTH)\n .describe(\"Local HTML path or HTTP(S) URL to render.\"),\n outputDir: filePathSchema\n .optional()\n .default(\".mcp-validator/screenshots\")\n .describe(\"Directory where PNG screenshots will be written.\"),\n viewports: z\n .array(\n z.object({\n name: z\n .string()\n .regex(/^[A-Za-z0-9_-]{1,50}$/)\n .describe(\"Safe filename label for this screenshot viewport.\"),\n width: z\n .number()\n .int()\n .min(200)\n .max(3_840)\n .describe(\"Viewport width in CSS pixels, from 200 to 3840.\"),\n height: z\n .number()\n .int()\n .min(200)\n .max(4_320)\n .describe(\"Viewport height in CSS pixels, from 200 to 4320.\"),\n }),\n )\n .min(1)\n .max(MAX_VIEWPORTS)\n .optional()\n .describe(\"Optional viewport definitions; defaults to desktop, tablet, and mobile sizes.\"),\n },\n outputSchema: {\n screenshots: z.array(screenshotSchema),\n outputDirectory: z.string(),\n error: z.string().optional(),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: true,\n idempotentHint: true,\n openWorldHint: true,\n },\n },\n async ({ targetPath, outputDir, viewports }) => {\n const outputDirectory = path.resolve(outputDir);\n try {\n const screenshots = await captureScreenshots(targetPath, outputDirectory, viewports);\n return result(\n { screenshots, outputDirectory },\n screenshotCaptureContent(screenshots.length, outputDirectory),\n );\n } catch (cause) {\n const error = getErrorMessage(cause);\n return result(\n { screenshots: [], outputDirectory, error },\n failureContent(\n \"Screenshot capture\",\n error,\n \"Confirm the target is reachable or readable and the output directory is writable, then retry.\",\n ),\n true,\n );\n }\n },\n );\n\n return server;\n}\n\nexport async function run(): Promise<void> {\n const server = createServer();\n await server.connect(new StdioServerTransport());\n console.error(`mcp-web-validator ${SERVER_VERSION} started on stdio`);\n}\n\nconst invokedPath = process.argv[1] ? pathToFileURL(path.resolve(process.argv[1])).href : undefined;\nif (invokedPath === import.meta.url) {\n run().catch((cause: unknown) => {\n console.error(\"Fatal error starting mcp-web-validator:\", getErrorMessage(cause));\n process.exitCode = 1;\n });\n}\n"]}
package/dist/network.d.ts CHANGED
@@ -36,7 +36,7 @@ export declare function getErrorMessage(error: unknown): string;
36
36
  export declare function resolvePublicHttpUrl(input: string | URL): Promise<ResolvedPublicHttpUrl>;
37
37
  export declare function assertPublicHttpUrl(input: string | URL): Promise<URL>;
38
38
  export declare function cancelResponseBody(response: Response): Promise<void>;
39
- export declare function readResponseText(response: Response, maxBytes: number, encoding?: string, sniffHtmlEncoding?: boolean): Promise<string>;
39
+ export declare function readResponseText(response: Response, maxBytes: number, encoding?: string, sniffHtmlEncoding?: boolean, sniffXmlEncoding?: boolean): Promise<string>;
40
40
  /** Fetches a public HTTP(S) URL while validating every redirect target. */
41
41
  export declare function fetchPublicHttp(input: string | URL, options?: PublicFetchOptions): Promise<PublicHttpResult>;
42
42
  /** Fetches bounded text from a public URL and rejects non-success responses. */
package/dist/network.js CHANGED
@@ -195,7 +195,41 @@ function isSupportedCharacterEncoding(encoding) {
195
195
  return false;
196
196
  }
197
197
  }
198
- export async function readResponseText(response, maxBytes, encoding, sniffHtmlEncoding = false) {
198
+ function getXmlCharacterEncoding(bytes) {
199
+ if (bytes.length >= 4) {
200
+ if (bytes[0] === 0x00 && bytes[1] === 0x00 && bytes[2] === 0xfe && bytes[3] === 0xff) {
201
+ return "utf-32be";
202
+ }
203
+ if (bytes[0] === 0xff && bytes[1] === 0xfe && bytes[2] === 0x00 && bytes[3] === 0x00) {
204
+ return "utf-32le";
205
+ }
206
+ if (bytes[0] === 0x00 && bytes[1] === 0x3c && bytes[2] === 0x00 && bytes[3] === 0x3f) {
207
+ return "utf-16be";
208
+ }
209
+ if (bytes[0] === 0x3c && bytes[1] === 0x00 && bytes[2] === 0x3f && bytes[3] === 0x00) {
210
+ return "utf-16le";
211
+ }
212
+ }
213
+ if (bytes.length >= 3 && bytes[0] === 0xef && bytes[1] === 0xbb && bytes[2] === 0xbf) {
214
+ return "utf-8";
215
+ }
216
+ if (bytes.length >= 2) {
217
+ if (bytes[0] === 0xfe && bytes[1] === 0xff) {
218
+ return "utf-16be";
219
+ }
220
+ if (bytes[0] === 0xff && bytes[1] === 0xfe) {
221
+ return "utf-16le";
222
+ }
223
+ }
224
+ const declarationBytes = bytes.subarray(0, HTML_ENCODING_SNIFF_BYTES);
225
+ let declaration = "";
226
+ for (const byte of declarationBytes) {
227
+ declaration += byte < 0x80 ? String.fromCharCode(byte) : "\ufffd";
228
+ }
229
+ const match = /^<\?xml\s+[^?]*\bencoding\s*=\s*(["'])([^"']+)\1/i.exec(declaration);
230
+ return match?.[2].trim() || "utf-8";
231
+ }
232
+ export async function readResponseText(response, maxBytes, encoding, sniffHtmlEncoding = false, sniffXmlEncoding = false) {
199
233
  assertPositiveInteger(maxBytes, "maxBytes");
200
234
  const declaredLength = Number(response.headers.get("content-length"));
201
235
  if (Number.isFinite(declaredLength) && declaredLength > maxBytes) {
@@ -224,7 +258,7 @@ export async function readResponseText(response, maxBytes, encoding, sniffHtmlEn
224
258
  if (decoder)
225
259
  return;
226
260
  let encodingLabel = encoding ?? "utf-8";
227
- if (encoding === undefined && sniffHtmlEncoding) {
261
+ if (encoding === undefined && (sniffHtmlEncoding || sniffXmlEncoding)) {
228
262
  const sniffLength = Math.min(pendingBytes, HTML_ENCODING_SNIFF_BYTES);
229
263
  const sniffBytes = new Uint8Array(sniffLength);
230
264
  let copied = 0;
@@ -235,10 +269,12 @@ export async function readResponseText(response, maxBytes, encoding, sniffHtmlEn
235
269
  sniffBytes.set(chunk.subarray(0, length), copied);
236
270
  copied += length;
237
271
  }
238
- encodingLabel = getEncoding(sniffBytes, {
239
- maxBytes: HTML_ENCODING_SNIFF_BYTES,
240
- defaultEncoding: "utf-8",
241
- });
272
+ encodingLabel = sniffXmlEncoding
273
+ ? getXmlCharacterEncoding(sniffBytes)
274
+ : getEncoding(sniffBytes, {
275
+ maxBytes: HTML_ENCODING_SNIFF_BYTES,
276
+ defaultEncoding: "utf-8",
277
+ });
242
278
  }
243
279
  decoder = await createDecoder(encodingLabel);
244
280
  for (const chunk of pendingChunks) {
@@ -247,7 +283,7 @@ export async function readResponseText(response, maxBytes, encoding, sniffHtmlEn
247
283
  pendingChunks = [];
248
284
  pendingBytes = 0;
249
285
  };
250
- if (encoding !== undefined || !sniffHtmlEncoding) {
286
+ if (encoding !== undefined || (!sniffHtmlEncoding && !sniffXmlEncoding)) {
251
287
  await startDecoder();
252
288
  }
253
289
  try {
@@ -391,8 +427,11 @@ export async function fetchPublicText(input, options = {}) {
391
427
  const declaredEncoding = getDeclaredCharacterEncoding(contentTypeHeader);
392
428
  const shouldSniffHtmlEncoding = contentType === "text/html"
393
429
  && (declaredEncoding === undefined || !isSupportedCharacterEncoding(declaredEncoding));
430
+ const shouldSniffXmlEncoding = declaredEncoding === undefined
431
+ && contentType !== null
432
+ && (contentType === "application/xml" || contentType === "text/xml" || contentType.endsWith("+xml"));
394
433
  return {
395
- text: await readResponseText(response, maxBytes, shouldSniffHtmlEncoding ? undefined : declaredEncoding, shouldSniffHtmlEncoding),
434
+ text: await readResponseText(response, maxBytes, shouldSniffHtmlEncoding || shouldSniffXmlEncoding ? undefined : declaredEncoding, shouldSniffHtmlEncoding, shouldSniffXmlEncoding),
396
435
  url: url.href,
397
436
  status: response.status,
398
437
  contentType: contentTypeHeader,