afdocs 0.1.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +48 -24
  2. package/dist/checks/authentication/auth-alternative-access.d.ts +2 -0
  3. package/dist/checks/authentication/auth-alternative-access.d.ts.map +1 -0
  4. package/dist/checks/authentication/auth-alternative-access.js +17 -0
  5. package/dist/checks/authentication/auth-alternative-access.js.map +1 -0
  6. package/dist/checks/authentication/auth-gate-detection.d.ts +2 -0
  7. package/dist/checks/authentication/auth-gate-detection.d.ts.map +1 -0
  8. package/dist/checks/authentication/auth-gate-detection.js +175 -0
  9. package/dist/checks/authentication/auth-gate-detection.js.map +1 -0
  10. package/dist/checks/content-structure/markdown-code-fence-validity.js +119 -5
  11. package/dist/checks/content-structure/markdown-code-fence-validity.js.map +1 -1
  12. package/dist/checks/index.d.ts +2 -0
  13. package/dist/checks/index.d.ts.map +1 -1
  14. package/dist/checks/index.js +3 -0
  15. package/dist/checks/index.js.map +1 -1
  16. package/dist/checks/llms-txt/llms-txt-exists.js +83 -6
  17. package/dist/checks/llms-txt/llms-txt-exists.js.map +1 -1
  18. package/dist/checks/llms-txt/llms-txt-links-markdown.js +46 -21
  19. package/dist/checks/llms-txt/llms-txt-links-markdown.js.map +1 -1
  20. package/dist/checks/llms-txt/llms-txt-links-resolve.js +10 -3
  21. package/dist/checks/llms-txt/llms-txt-links-resolve.js.map +1 -1
  22. package/dist/checks/markdown-availability/content-negotiation.js +101 -5
  23. package/dist/checks/markdown-availability/content-negotiation.js.map +1 -1
  24. package/dist/checks/markdown-availability/markdown-url-support.js +82 -5
  25. package/dist/checks/markdown-availability/markdown-url-support.js.map +1 -1
  26. package/dist/checks/observability/cache-header-hygiene.js +200 -5
  27. package/dist/checks/observability/cache-header-hygiene.js.map +1 -1
  28. package/dist/checks/page-size/content-start-position.js +161 -5
  29. package/dist/checks/page-size/content-start-position.js.map +1 -1
  30. package/dist/checks/page-size/page-size-html.js +127 -5
  31. package/dist/checks/page-size/page-size-html.js.map +1 -1
  32. package/dist/checks/page-size/page-size-markdown.js +100 -5
  33. package/dist/checks/page-size/page-size-markdown.js.map +1 -1
  34. package/dist/checks/url-stability/http-status-codes.js +106 -5
  35. package/dist/checks/url-stability/http-status-codes.js.map +1 -1
  36. package/dist/cli/commands/check.d.ts.map +1 -1
  37. package/dist/cli/commands/check.js +9 -1
  38. package/dist/cli/commands/check.js.map +1 -1
  39. package/dist/cli/formatters/text.d.ts +4 -1
  40. package/dist/cli/formatters/text.d.ts.map +1 -1
  41. package/dist/cli/formatters/text.js +94 -1
  42. package/dist/cli/formatters/text.js.map +1 -1
  43. package/dist/constants.d.ts +6 -0
  44. package/dist/constants.d.ts.map +1 -1
  45. package/dist/constants.js +3 -0
  46. package/dist/constants.js.map +1 -1
  47. package/dist/helpers/detect-markdown.d.ts +10 -0
  48. package/dist/helpers/detect-markdown.d.ts.map +1 -0
  49. package/dist/helpers/detect-markdown.js +29 -0
  50. package/dist/helpers/detect-markdown.js.map +1 -0
  51. package/dist/helpers/get-markdown-content.d.ts +23 -0
  52. package/dist/helpers/get-markdown-content.d.ts.map +1 -0
  53. package/dist/helpers/get-markdown-content.js +93 -0
  54. package/dist/helpers/get-markdown-content.js.map +1 -0
  55. package/dist/helpers/get-page-urls.d.ts +42 -0
  56. package/dist/helpers/get-page-urls.d.ts.map +1 -0
  57. package/dist/helpers/get-page-urls.js +236 -0
  58. package/dist/helpers/get-page-urls.js.map +1 -0
  59. package/dist/helpers/html-to-markdown.d.ts +7 -0
  60. package/dist/helpers/html-to-markdown.d.ts.map +1 -0
  61. package/dist/helpers/html-to-markdown.js +11 -0
  62. package/dist/helpers/html-to-markdown.js.map +1 -0
  63. package/dist/helpers/index.d.ts +5 -0
  64. package/dist/helpers/index.d.ts.map +1 -1
  65. package/dist/helpers/index.js +4 -0
  66. package/dist/helpers/index.js.map +1 -1
  67. package/dist/helpers/to-md-urls.d.ts +7 -0
  68. package/dist/helpers/to-md-urls.d.ts.map +1 -0
  69. package/dist/helpers/to-md-urls.js +24 -0
  70. package/dist/helpers/to-md-urls.js.map +1 -0
  71. package/dist/runner.d.ts.map +1 -1
  72. package/dist/runner.js +21 -14
  73. package/dist/runner.js.map +1 -1
  74. package/dist/types.d.ts +13 -1
  75. package/dist/types.d.ts.map +1 -1
  76. package/package.json +4 -2
@@ -1,10 +1,105 @@
1
1
  import { registerCheck } from '../registry.js';
2
- async function check(_ctx) {
2
+ import { getMarkdownContent } from '../../helpers/get-markdown-content.js';
3
+ function sizeStatus(chars, pass, fail) {
4
+ if (chars <= pass)
5
+ return 'pass';
6
+ if (chars <= fail)
7
+ return 'warn';
8
+ return 'fail';
9
+ }
10
+ function worstStatus(statuses) {
11
+ if (statuses.includes('fail'))
12
+ return 'fail';
13
+ if (statuses.includes('warn'))
14
+ return 'warn';
15
+ return 'pass';
16
+ }
17
+ function formatSize(chars) {
18
+ if (chars >= 1000)
19
+ return `${Math.round(chars / 1000)}K`;
20
+ return String(chars);
21
+ }
22
+ async function check(ctx) {
23
+ const id = 'page-size-markdown';
24
+ const category = 'page-size';
25
+ const { pass: passThreshold, fail: failThreshold } = ctx.options.thresholds;
26
+ const mdResult = await getMarkdownContent(ctx);
27
+ if (mdResult.mode === 'cached' && !mdResult.depPassed) {
28
+ return {
29
+ id,
30
+ category,
31
+ status: 'skip',
32
+ message: 'Site does not serve markdown; skipping markdown size check',
33
+ };
34
+ }
35
+ if (mdResult.pages.length === 0) {
36
+ const hint = mdResult.mode === 'standalone'
37
+ ? 'No markdown content found; skipping size check'
38
+ : 'No cached markdown pages available to measure';
39
+ return { id, category, status: 'skip', message: hint };
40
+ }
41
+ // Build mdUrl map from markdown-url-support results for richer reporting
42
+ const mdUrlMap = new Map();
43
+ const mdUrlResult = ctx.previousResults.get('markdown-url-support');
44
+ const mdUrlPages = mdUrlResult?.details?.pageResults;
45
+ if (mdUrlPages) {
46
+ for (const p of mdUrlPages) {
47
+ if (p.supported)
48
+ mdUrlMap.set(p.url, p.mdUrl);
49
+ }
50
+ }
51
+ const pageResults = mdResult.pages
52
+ .filter((p) => p.source !== 'llms-txt') // llms.txt files aren't doc pages to size-check
53
+ .map((page) => {
54
+ const chars = page.content.length;
55
+ const mdUrl = mdUrlMap.get(page.url) ?? page.url;
56
+ return {
57
+ url: page.url,
58
+ mdUrl,
59
+ characters: chars,
60
+ status: sizeStatus(chars, passThreshold, failThreshold),
61
+ source: page.source,
62
+ };
63
+ });
64
+ if (pageResults.length === 0) {
65
+ return { id, category, status: 'skip', message: 'No markdown pages available to measure' };
66
+ }
67
+ const sizes = pageResults.map((r) => r.characters).sort((a, b) => a - b);
68
+ const median = sizes[Math.floor(sizes.length / 2)];
69
+ const max = sizes[sizes.length - 1];
70
+ const passBucket = pageResults.filter((r) => r.status === 'pass').length;
71
+ const warnBucket = pageResults.filter((r) => r.status === 'warn').length;
72
+ const failBucket = pageResults.filter((r) => r.status === 'fail').length;
73
+ const overallStatus = worstStatus(pageResults.map((r) => r.status));
74
+ const sampled = mdResult.mode === 'standalone'; // standalone always samples via discoverAndSamplePages
75
+ const pageLabel = sampled ? 'sampled pages' : 'pages';
76
+ let message;
77
+ if (overallStatus === 'pass') {
78
+ message = `All ${pageResults.length} ${pageLabel} under ${formatSize(passThreshold)} chars (median ${formatSize(median)}, max ${formatSize(max)})`;
79
+ }
80
+ else if (overallStatus === 'warn') {
81
+ message = `${warnBucket} of ${pageResults.length} ${pageLabel} between ${formatSize(passThreshold)}–${formatSize(failThreshold)} chars (max ${formatSize(max)})`;
82
+ }
83
+ else {
84
+ message = `${failBucket} of ${pageResults.length} ${pageLabel} exceed ${formatSize(failThreshold)} chars (max ${formatSize(max)})`;
85
+ }
3
86
  return {
4
- id: 'page-size-markdown',
5
- category: 'page-size',
6
- status: 'skip',
7
- message: 'Not yet implemented',
87
+ id,
88
+ category,
89
+ status: overallStatus,
90
+ message,
91
+ details: {
92
+ totalPages: pageResults.length,
93
+ testedPages: pageResults.length,
94
+ sampled,
95
+ median,
96
+ max,
97
+ passBucket,
98
+ warnBucket,
99
+ failBucket,
100
+ thresholds: { pass: passThreshold, fail: failThreshold },
101
+ pageResults,
102
+ },
8
103
  };
9
104
  }
10
105
  registerCheck({
@@ -1 +1 @@
1
- {"version":3,"file":"page-size-markdown.js","sourceRoot":"","sources":["../../../src/checks/page-size/page-size-markdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAG/C,KAAK,UAAU,KAAK,CAAC,IAAkB;IACrC,OAAO;QACL,EAAE,EAAE,oBAAoB;QACxB,QAAQ,EAAE,WAAW;QACrB,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,qBAAqB;KAC/B,CAAC;AACJ,CAAC;AAED,aAAa,CAAC;IACZ,EAAE,EAAE,oBAAoB;IACxB,QAAQ,EAAE,WAAW;IACrB,WAAW,EAAE,iDAAiD;IAC9D,SAAS,EAAE,CAAC,CAAC,sBAAsB,EAAE,qBAAqB,CAAC,CAAC;IAC5D,GAAG,EAAE,KAAK;CACX,CAAC,CAAC"}
1
+ {"version":3,"file":"page-size-markdown.js","sourceRoot":"","sources":["../../../src/checks/page-size/page-size-markdown.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,111 @@
1
1
  import { registerCheck } from '../registry.js';
2
- async function check(_ctx) {
2
+ import { discoverAndSamplePages } from '../../helpers/get-page-urls.js';
3
+ /** Generate a sibling URL that almost certainly doesn't exist. */
4
+ function makeBadUrl(pageUrl) {
5
+ const u = new URL(pageUrl);
6
+ u.hash = ''; // strip fragment — servers don't see it anyway
7
+ u.pathname = u.pathname.replace(/\/?$/, '-afdocs-nonexistent-8f3a');
8
+ return u.toString();
9
+ }
10
+ const SOFT_404_PATTERNS = /not\s*found|page\s*not\s*found|404|does\s*not\s*exist/i;
11
+ async function check(ctx) {
12
+ const id = 'http-status-codes';
13
+ const category = 'url-stability';
14
+ const { urls: pageUrls, totalPages, sampled, warnings } = await discoverAndSamplePages(ctx);
15
+ const results = [];
16
+ const concurrency = ctx.options.maxConcurrency;
17
+ for (let i = 0; i < pageUrls.length; i += concurrency) {
18
+ const batch = pageUrls.slice(i, i + concurrency);
19
+ const batchResults = await Promise.all(batch.map(async (url) => {
20
+ const testUrl = makeBadUrl(url);
21
+ try {
22
+ // Follow redirects so we classify based on the final response.
23
+ // A redirect chain ending in 404 is correct; one ending in 200 is a soft 404.
24
+ const response = await ctx.http.fetch(testUrl);
25
+ const status = response.status;
26
+ const redirected = response.redirected || response.url !== testUrl;
27
+ const finalUrl = redirected ? response.url : undefined;
28
+ if (status >= 400) {
29
+ return { url, testUrl, status, classification: 'correct-error', redirected, finalUrl };
30
+ }
31
+ // Status 200 (or other 2xx/3xx) — possible soft 404
32
+ let bodyHint;
33
+ try {
34
+ const body = await response.text();
35
+ if (SOFT_404_PATTERNS.test(body.slice(0, 5000))) {
36
+ bodyHint = 'Body contains "not found" / "404" text';
37
+ }
38
+ }
39
+ catch {
40
+ // ignore body read errors
41
+ }
42
+ return {
43
+ url,
44
+ testUrl,
45
+ status,
46
+ classification: 'soft-404',
47
+ redirected,
48
+ finalUrl,
49
+ bodyHint,
50
+ };
51
+ }
52
+ catch (err) {
53
+ return {
54
+ url,
55
+ testUrl,
56
+ status: null,
57
+ classification: 'fetch-error',
58
+ error: err instanceof Error ? err.message : String(err),
59
+ };
60
+ }
61
+ }));
62
+ results.push(...batchResults);
63
+ }
64
+ const tested = results.filter((r) => r.classification !== 'fetch-error');
65
+ const fetchErrors = results.filter((r) => r.classification === 'fetch-error').length;
66
+ const soft404s = results.filter((r) => r.classification === 'soft-404');
67
+ const correctErrors = results.filter((r) => r.classification === 'correct-error');
68
+ if (tested.length === 0) {
69
+ return {
70
+ id,
71
+ category,
72
+ status: 'fail',
73
+ message: `Could not test any URLs${fetchErrors > 0 ? `; ${fetchErrors} failed to fetch` : ''}`,
74
+ details: {
75
+ totalPages,
76
+ testedPages: results.length,
77
+ sampled,
78
+ fetchErrors,
79
+ pageResults: results,
80
+ discoveryWarnings: warnings,
81
+ },
82
+ };
83
+ }
84
+ const status = soft404s.length > 0 ? 'fail' : 'pass';
85
+ const pageLabel = sampled ? 'sampled pages' : 'pages';
86
+ const suffix = fetchErrors > 0 ? `; ${fetchErrors} failed to fetch` : '';
87
+ let message;
88
+ if (status === 'pass') {
89
+ message = `All ${tested.length} ${pageLabel} return proper error codes for bad URLs${suffix}`;
90
+ }
91
+ else {
92
+ message = `${soft404s.length} of ${tested.length} ${pageLabel} return 200 for non-existent URLs (soft 404)${suffix}`;
93
+ }
3
94
  return {
4
- id: 'http-status-codes',
5
- category: 'url-stability',
6
- status: 'skip',
7
- message: 'Not yet implemented',
95
+ id,
96
+ category,
97
+ status,
98
+ message,
99
+ details: {
100
+ totalPages,
101
+ testedPages: results.length,
102
+ sampled,
103
+ soft404Count: soft404s.length,
104
+ correctErrorCount: correctErrors.length,
105
+ fetchErrors,
106
+ pageResults: results,
107
+ discoveryWarnings: warnings,
108
+ },
8
109
  };
9
110
  }
10
111
  registerCheck({
@@ -1 +1 @@
1
- {"version":3,"file":"http-status-codes.js","sourceRoot":"","sources":["../../../src/checks/url-stability/http-status-codes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAG/C,KAAK,UAAU,KAAK,CAAC,IAAkB;IACrC,OAAO;QACL,EAAE,EAAE,mBAAmB;QACvB,QAAQ,EAAE,eAAe;QACzB,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,qBAAqB;KAC/B,CAAC;AACJ,CAAC;AAED,aAAa,CAAC;IACZ,EAAE,EAAE,mBAAmB;IACvB,QAAQ,EAAE,eAAe;IACzB,WAAW,EAAE,sDAAsD;IACnE,SAAS,EAAE,EAAE;IACb,GAAG,EAAE,KAAK;CACX,CAAC,CAAC"}
1
+ {"version":3,"file":"http-status-codes.js","sourceRoot":"","sources":["../../../src/checks/url-stability/http-status-codes.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/check.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMzC,OAAO,uBAAuB,CAAC;AAE/B,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAkC3D"}
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/check.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMzC,OAAO,uBAAuB,CAAC;AAE/B,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA4C3D"}
@@ -14,8 +14,14 @@ export function registerCheckCommand(program) {
14
14
  .option('--max-links <n>', 'Maximum links to test', '50')
15
15
  .option('--pass-threshold <n>', 'Pass threshold in characters', '50000')
16
16
  .option('--fail-threshold <n>', 'Fail threshold in characters', '100000')
17
+ .option('-v, --verbose', 'Show per-page details for checks with issues')
17
18
  .action(async (url, opts) => {
18
19
  const checkIds = opts.checks ? opts.checks.split(',').map((s) => s.trim()) : undefined;
20
+ const isText = opts.format !== 'json';
21
+ if (isText) {
22
+ const domain = new URL(url).hostname;
23
+ process.stderr.write(`Running checks on ${domain}...\n`);
24
+ }
19
25
  const report = await runChecks(url, {
20
26
  checkIds,
21
27
  maxConcurrency: parseInt(opts.maxConcurrency, 10),
@@ -26,7 +32,9 @@ export function registerCheckCommand(program) {
26
32
  fail: parseInt(opts.failThreshold, 10),
27
33
  },
28
34
  });
29
- const output = opts.format === 'json' ? formatJson(report) : formatText(report);
35
+ const output = opts.format === 'json'
36
+ ? formatJson(report)
37
+ : formatText(report, { verbose: !!opts.verbose });
30
38
  process.stdout.write(output + '\n');
31
39
  // Exit 1 if any check failed
32
40
  const hasFailure = report.results.some((r) => r.status === 'fail');
@@ -1 +1 @@
1
- {"version":3,"file":"check.js","sourceRoot":"","sources":["../../../src/cli/commands/check.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,mCAAmC;AACnC,OAAO,uBAAuB,CAAC;AAE/B,MAAM,UAAU,oBAAoB,CAAC,OAAgB;IACnD,OAAO;SACJ,OAAO,CAAC,aAAa,CAAC;SACtB,WAAW,CAAC,uDAAuD,CAAC;SACpE,MAAM,CAAC,uBAAuB,EAAE,6BAA6B,EAAE,MAAM,CAAC;SACtE,MAAM,CAAC,uBAAuB,EAAE,0CAA0C,CAAC;SAC3E,MAAM,CAAC,uBAAuB,EAAE,6BAA6B,EAAE,GAAG,CAAC;SACnE,MAAM,CAAC,sBAAsB,EAAE,8BAA8B,EAAE,KAAK,CAAC;SACrE,MAAM,CAAC,iBAAiB,EAAE,uBAAuB,EAAE,IAAI,CAAC;SACxD,MAAM,CAAC,sBAAsB,EAAE,8BAA8B,EAAE,OAAO,CAAC;SACvE,MAAM,CAAC,sBAAsB,EAAE,8BAA8B,EAAE,QAAQ,CAAC;SACxE,MAAM,CAAC,KAAK,EAAE,GAAW,EAAE,IAA4B,EAAE,EAAE;QAC1D,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAEvF,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE;YAClC,QAAQ;YACR,cAAc,EAAE,QAAQ,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC;YACjD,YAAY,EAAE,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;YAC7C,cAAc,EAAE,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;YAC3C,UAAU,EAAE;gBACV,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC;gBACtC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC;aACvC;SACF,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAChF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;QAEpC,6BAA6B;QAC7B,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;QACnE,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
1
+ {"version":3,"file":"check.js","sourceRoot":"","sources":["../../../src/cli/commands/check.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,mCAAmC;AACnC,OAAO,uBAAuB,CAAC;AAE/B,MAAM,UAAU,oBAAoB,CAAC,OAAgB;IACnD,OAAO;SACJ,OAAO,CAAC,aAAa,CAAC;SACtB,WAAW,CAAC,uDAAuD,CAAC;SACpE,MAAM,CAAC,uBAAuB,EAAE,6BAA6B,EAAE,MAAM,CAAC;SACtE,MAAM,CAAC,uBAAuB,EAAE,0CAA0C,CAAC;SAC3E,MAAM,CAAC,uBAAuB,EAAE,6BAA6B,EAAE,GAAG,CAAC;SACnE,MAAM,CAAC,sBAAsB,EAAE,8BAA8B,EAAE,KAAK,CAAC;SACrE,MAAM,CAAC,iBAAiB,EAAE,uBAAuB,EAAE,IAAI,CAAC;SACxD,MAAM,CAAC,sBAAsB,EAAE,8BAA8B,EAAE,OAAO,CAAC;SACvE,MAAM,CAAC,sBAAsB,EAAE,8BAA8B,EAAE,QAAQ,CAAC;SACxE,MAAM,CAAC,eAAe,EAAE,8CAA8C,CAAC;SACvE,MAAM,CAAC,KAAK,EAAE,GAAW,EAAE,IAA4B,EAAE,EAAE;QAC1D,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACvF,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC;QAEtC,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;YACrC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,qBAAqB,MAAM,OAAO,CAAC,CAAC;QAC3D,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE;YAClC,QAAQ;YACR,cAAc,EAAE,QAAQ,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC;YACjD,YAAY,EAAE,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;YAC7C,cAAc,EAAE,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;YAC3C,UAAU,EAAE;gBACV,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC;gBACtC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC;aACvC;SACF,CAAC,CAAC;QAEH,MAAM,MAAM,GACV,IAAI,CAAC,MAAM,KAAK,MAAM;YACpB,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC;YACpB,CAAC,CAAC,UAAU,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QACtD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;QAEpC,6BAA6B;QAC7B,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;QACnE,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -1,3 +1,6 @@
1
1
  import type { ReportResult } from '../../types.js';
2
- export declare function formatText(report: ReportResult): string;
2
+ export interface FormatTextOptions {
3
+ verbose?: boolean;
4
+ }
5
+ export declare function formatText(report: ReportResult, options?: FormatTextOptions): string;
3
6
  //# sourceMappingURL=text.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/cli/formatters/text.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAe,MAAM,gBAAgB,CAAC;AAwBhE,wBAAgB,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAqCvD"}
1
+ {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/cli/formatters/text.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAe,MAAM,gBAAgB,CAAC;AAgIhE,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAyCpF"}
@@ -13,12 +13,102 @@ const STATUS_COLORS = {
13
13
  skip: chalk.gray,
14
14
  error: chalk.red,
15
15
  };
16
+ function formatSize(chars) {
17
+ if (chars >= 1000)
18
+ return `${Math.round(chars / 1000)}K chars`;
19
+ return `${chars} chars`;
20
+ }
21
+ const DETAIL_FORMATTERS = {
22
+ 'page-size-html': (details) => {
23
+ const pages = details.pageResults;
24
+ if (!pages)
25
+ return [];
26
+ return pages
27
+ .filter((p) => p.status !== 'pass')
28
+ .map((p) => {
29
+ const size = formatSize(p.convertedCharacters);
30
+ return formatDetailLine(p.status, p.url, size);
31
+ });
32
+ },
33
+ 'page-size-markdown': (details) => {
34
+ const pages = details.pageResults;
35
+ if (!pages)
36
+ return [];
37
+ return pages
38
+ .filter((p) => p.status !== 'pass')
39
+ .map((p) => {
40
+ const size = formatSize(p.characters);
41
+ const displayUrl = p.mdUrl ?? p.url;
42
+ return formatDetailLine(p.status, displayUrl, size);
43
+ });
44
+ },
45
+ 'content-start-position': (details) => {
46
+ const pages = details.pageResults;
47
+ if (!pages)
48
+ return [];
49
+ return pages
50
+ .filter((p) => p.status !== 'pass')
51
+ .map((p) => {
52
+ const pct = `${p.contentStartPercent}%`;
53
+ return formatDetailLine(p.status, p.url, pct);
54
+ });
55
+ },
56
+ 'markdown-url-support': (details) => {
57
+ const pages = details.pageResults;
58
+ if (!pages)
59
+ return [];
60
+ return pages
61
+ .filter((p) => p.status !== 'pass')
62
+ .map((p) => formatDetailLine(p.status, p.url, 'no .md URL found'));
63
+ },
64
+ 'content-negotiation': (details) => {
65
+ const pages = details.pageResults;
66
+ if (!pages)
67
+ return [];
68
+ return pages
69
+ .filter((p) => p.status !== 'pass')
70
+ .map((p) => {
71
+ const classification = p.classification ?? '';
72
+ return formatDetailLine(p.status, p.url, classification);
73
+ });
74
+ },
75
+ 'llms-txt-links-resolve': (details) => {
76
+ const broken = details.broken;
77
+ if (!broken)
78
+ return [];
79
+ return broken.map((b) => {
80
+ const info = b.error ?? `HTTP ${b.status}`;
81
+ return formatDetailLine('fail', b.url, info);
82
+ });
83
+ },
84
+ };
85
+ function formatDetailLine(status, url, metric) {
86
+ const icon = STATUS_ICONS[status] ?? STATUS_ICONS.warn;
87
+ return ` ${icon} ${url} ${chalk.dim(metric)}`;
88
+ }
16
89
  function formatResult(result) {
17
90
  const icon = STATUS_ICONS[result.status] ?? '?';
18
91
  const color = STATUS_COLORS[result.status] ?? ((s) => s);
19
92
  return ` ${icon} ${color(result.id)}: ${result.message}`;
20
93
  }
21
- export function formatText(report) {
94
+ function formatVerboseDetails(result) {
95
+ if (!result.details)
96
+ return [];
97
+ const lines = [];
98
+ const formatter = DETAIL_FORMATTERS[result.id];
99
+ if (formatter) {
100
+ lines.push(...formatter(result.details));
101
+ }
102
+ const warnings = result.details.discoveryWarnings;
103
+ if (warnings && warnings.length > 0) {
104
+ for (const w of warnings) {
105
+ lines.push(` ${chalk.yellow('⚠')} ${chalk.dim(w)}`);
106
+ }
107
+ }
108
+ return lines;
109
+ }
110
+ export function formatText(report, options) {
111
+ const verbose = options?.verbose ?? false;
22
112
  const lines = [];
23
113
  lines.push('');
24
114
  lines.push(chalk.bold(`Agent-Friendly Docs Check: ${report.url}`));
@@ -35,6 +125,9 @@ export function formatText(report) {
35
125
  lines.push(chalk.bold.underline(category));
36
126
  for (const result of results) {
37
127
  lines.push(formatResult(result));
128
+ if (verbose) {
129
+ lines.push(...formatVerboseDetails(result));
130
+ }
38
131
  }
39
132
  lines.push('');
40
133
  }
@@ -1 +1 @@
1
- {"version":3,"file":"text.js","sourceRoot":"","sources":["../../../src/cli/formatters/text.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"text.js","sourceRoot":"","sources":["../../../src/cli/formatters/text.ts"],"names":[],"mappings":"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"}
@@ -29,8 +29,14 @@ export declare const CATEGORIES: readonly [{
29
29
  readonly id: "observability";
30
30
  readonly name: "Observability and Content Health";
31
31
  readonly order: 7;
32
+ }, {
33
+ readonly id: "authentication";
34
+ readonly name: "Authentication and Access";
35
+ readonly order: 8;
32
36
  }];
33
37
  export declare const CATEGORY_ORDER: Record<string, number>;
34
38
  /** Link resolution threshold: warn if > 90% resolve, fail if <= 90%. */
35
39
  export declare const LINK_RESOLVE_THRESHOLD = 0.9;
40
+ /** Maximum number of URLs to collect from sitemaps before stopping. */
41
+ export declare const MAX_SITEMAP_URLS = 500;
36
42
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE/D,eAAO,MAAM,kBAAkB,EAAE,cAGhC,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,YAM7B,CAAC;AAEF,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAQb,CAAC;AAEX,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAEjD,CAAC;AAEF,wEAAwE;AACxE,eAAO,MAAM,sBAAsB,MAAM,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE/D,eAAO,MAAM,kBAAkB,EAAE,cAGhC,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,YAM7B,CAAC;AAEF,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EASb,CAAC;AAEX,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAEjD,CAAC;AAEF,wEAAwE;AACxE,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C,uEAAuE;AACvE,eAAO,MAAM,gBAAgB,MAAM,CAAC"}
package/dist/constants.js CHANGED
@@ -17,8 +17,11 @@ export const CATEGORIES = [
17
17
  { id: 'url-stability', name: 'URL Stability and Redirects', order: 5 },
18
18
  { id: 'agent-discoverability', name: 'Agent Discoverability Directives', order: 6 },
19
19
  { id: 'observability', name: 'Observability and Content Health', order: 7 },
20
+ { id: 'authentication', name: 'Authentication and Access', order: 8 },
20
21
  ];
21
22
  export const CATEGORY_ORDER = Object.fromEntries(CATEGORIES.map((c) => [c.id, c.order]));
22
23
  /** Link resolution threshold: warn if > 90% resolve, fail if <= 90%. */
23
24
  export const LINK_RESOLVE_THRESHOLD = 0.9;
25
+ /** Maximum number of URLs to collect from sitemaps before stopping. */
26
+ export const MAX_SITEMAP_URLS = 500;
24
27
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,kBAAkB,GAAmB;IAChD,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,OAAO;CACd,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAiB;IAC3C,cAAc,EAAE,CAAC;IACjB,YAAY,EAAE,GAAG;IACjB,cAAc,EAAE,MAAM;IACtB,cAAc,EAAE,EAAE;IAClB,UAAU,EAAE,kBAAkB;CAC/B,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE;IAC9C,EAAE,EAAE,EAAE,uBAAuB,EAAE,IAAI,EAAE,uBAAuB,EAAE,KAAK,EAAE,CAAC,EAAE;IACxE,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,+BAA+B,EAAE,KAAK,EAAE,CAAC,EAAE;IACpE,EAAE,EAAE,EAAE,mBAAmB,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,CAAC,EAAE;IAChE,EAAE,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,6BAA6B,EAAE,KAAK,EAAE,CAAC,EAAE;IACtE,EAAE,EAAE,EAAE,uBAAuB,EAAE,IAAI,EAAE,kCAAkC,EAAE,KAAK,EAAE,CAAC,EAAE;IACnF,EAAE,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,kCAAkC,EAAE,KAAK,EAAE,CAAC,EAAE;CACnE,CAAC;AAEX,MAAM,CAAC,MAAM,cAAc,GAA2B,MAAM,CAAC,WAAW,CACtE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CACvC,CAAC;AAEF,wEAAwE;AACxE,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,kBAAkB,GAAmB;IAChD,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,OAAO;CACd,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAiB;IAC3C,cAAc,EAAE,CAAC;IACjB,YAAY,EAAE,GAAG;IACjB,cAAc,EAAE,MAAM;IACtB,cAAc,EAAE,EAAE;IAClB,UAAU,EAAE,kBAAkB;CAC/B,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE;IAC9C,EAAE,EAAE,EAAE,uBAAuB,EAAE,IAAI,EAAE,uBAAuB,EAAE,KAAK,EAAE,CAAC,EAAE;IACxE,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,+BAA+B,EAAE,KAAK,EAAE,CAAC,EAAE;IACpE,EAAE,EAAE,EAAE,mBAAmB,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,CAAC,EAAE;IAChE,EAAE,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,6BAA6B,EAAE,KAAK,EAAE,CAAC,EAAE;IACtE,EAAE,EAAE,EAAE,uBAAuB,EAAE,IAAI,EAAE,kCAAkC,EAAE,KAAK,EAAE,CAAC,EAAE;IACnF,EAAE,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,kCAAkC,EAAE,KAAK,EAAE,CAAC,EAAE;IAC3E,EAAE,EAAE,EAAE,gBAAgB,EAAE,IAAI,EAAE,2BAA2B,EAAE,KAAK,EAAE,CAAC,EAAE;CAC7D,CAAC;AAEX,MAAM,CAAC,MAAM,cAAc,GAA2B,MAAM,CAAC,WAAW,CACtE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CACvC,CAAC;AAEF,wEAAwE;AACxE,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAE1C,uEAAuE;AACvE,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Returns true if the body looks like HTML (contains DOCTYPE, <html>, <head>, or <body> tags).
3
+ */
4
+ export declare function looksLikeHtml(body: string): boolean;
5
+ /**
6
+ * Returns true if the body looks like markdown content (has headings, links, or code fences)
7
+ * and does NOT look like HTML.
8
+ */
9
+ export declare function looksLikeMarkdown(body: string): boolean;
10
+ //# sourceMappingURL=detect-markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-markdown.d.ts","sourceRoot":"","sources":["../../src/helpers/detect-markdown.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGnD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAUvD"}
@@ -0,0 +1,29 @@
1
+ const HTML_PATTERNS = [/<!doctype\s/i, /<html[\s>]/i, /<head[\s>]/i, /<body[\s>]/i];
2
+ const MD_HEADING = /^#{1,6}\s+\S/m;
3
+ const MD_LINK = /\[[^\]]+\]\([^)]+\)/;
4
+ const MD_CODE_FENCE = /^```/m;
5
+ /**
6
+ * Returns true if the body looks like HTML (contains DOCTYPE, <html>, <head>, or <body> tags).
7
+ */
8
+ export function looksLikeHtml(body) {
9
+ const sample = body.slice(0, 2000);
10
+ return HTML_PATTERNS.some((p) => p.test(sample));
11
+ }
12
+ /**
13
+ * Returns true if the body looks like markdown content (has headings, links, or code fences)
14
+ * and does NOT look like HTML.
15
+ */
16
+ export function looksLikeMarkdown(body) {
17
+ if (looksLikeHtml(body))
18
+ return false;
19
+ const sample = body.slice(0, 5000);
20
+ let signals = 0;
21
+ if (MD_HEADING.test(sample))
22
+ signals++;
23
+ if (MD_LINK.test(sample))
24
+ signals++;
25
+ if (MD_CODE_FENCE.test(sample))
26
+ signals++;
27
+ return signals >= 1;
28
+ }
29
+ //# sourceMappingURL=detect-markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-markdown.js","sourceRoot":"","sources":["../../src/helpers/detect-markdown.ts"],"names":[],"mappings":"AAAA,MAAM,aAAa,GAAG,CAAC,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC;AAEpF,MAAM,UAAU,GAAG,eAAe,CAAC;AACnC,MAAM,OAAO,GAAG,qBAAqB,CAAC;AACtC,MAAM,aAAa,GAAG,OAAO,CAAC;AAE9B;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IACnC,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AACnD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,IAAI,aAAa,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAEtC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IACnC,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,CAAC;IACvC,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,CAAC;IACpC,IAAI,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,CAAC;IAE1C,OAAO,OAAO,IAAI,CAAC,CAAC;AACtB,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { CheckContext } from '../types.js';
2
+ export interface MarkdownPage {
3
+ url: string;
4
+ content: string;
5
+ source: string;
6
+ }
7
+ export type MarkdownContentResult = {
8
+ mode: 'cached';
9
+ pages: MarkdownPage[];
10
+ depPassed: boolean;
11
+ } | {
12
+ mode: 'standalone';
13
+ pages: MarkdownPage[];
14
+ };
15
+ /**
16
+ * Get markdown content for analysis, either from dependency cache or by fetching directly.
17
+ *
18
+ * When markdown-url-support or content-negotiation have already run, reads from
19
+ * ctx.pageCache (fast). Otherwise, discovers pages and probes for markdown itself.
20
+ * Always includes llms.txt content when available.
21
+ */
22
+ export declare function getMarkdownContent(ctx: CheckContext): Promise<MarkdownContentResult>;
23
+ //# sourceMappingURL=get-markdown-content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-markdown-content.d.ts","sourceRoot":"","sources":["../../src/helpers/get-markdown-content.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAkB,MAAM,aAAa,CAAC;AAEhE,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,qBAAqB,GAC7B;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,YAAY,EAAE,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,GAC7D;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,YAAY,EAAE,CAAA;CAAE,CAAC;AAElD;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAmB1F"}