feat(packages): support cli:omit markers for llm-only doc content (#1466)

This commit is contained in:
Darius Cepulis
2026-04-24 14:56:44 -05:00
committed by GitHub
parent 89594292d4
commit 85e28a5920
6 changed files with 85 additions and 8 deletions
+3 -3
View File
@@ -6,7 +6,7 @@ import { getConfigValue } from '../utils/config.js';
import { docExistsInAnyFramework, readBundledDoc, readLlmsTxt } from '../utils/docs.js';
import { formatInstallationCode } from '../utils/format.js';
import { mapRawSkin, type PartialInstallFlags, promptFramework, promptInstallOptions } from '../utils/prompts.js';
import { replaceMarker } from '../utils/replace.js';
import { replaceMarker, stripOmitMarkers } from '../utils/replace.js';
interface ParsedFlags {
framework?: string;
@@ -178,7 +178,7 @@ export async function handleDocs(flags: ParsedFlags, positionals: string[]): Pro
}
const generated = formatInstallationCode(opts);
const output = replaceMarker(markdown, 'installation', generated);
const output = stripOmitMarkers(replaceMarker(markdown, 'installation', generated));
printVersionHeader();
console.log(output);
return;
@@ -186,5 +186,5 @@ export async function handleDocs(flags: ParsedFlags, positionals: string[]): Pro
// Regular doc: print as-is
printVersionHeader();
console.log(markdown);
console.log(stripOmitMarkers(markdown));
}
@@ -6,6 +6,10 @@ const INSTALLATION_DOC = `# Installation
Intro paragraph.
<!-- cli:omit installation -->
Run the CLI to generate install code.
<!-- /cli:omit installation -->
<!-- cli:replace installation -->
Placeholder for CLI-generated code.
<!-- /cli:replace installation -->
@@ -205,6 +209,8 @@ describe('handleDocs', () => {
expect(out).toContain('## HTML');
expect(out).toContain('<video-player>');
expect(out).not.toContain('<!-- cli:replace');
expect(out).not.toContain('<!-- cli:omit');
expect(out).not.toContain('Run the CLI to generate install code');
expect(out).toContain('Intro paragraph');
expect(out).toContain('## Next steps');
});
+5
View File
@@ -2,3 +2,8 @@ export function replaceMarker(markdown: string, id: string, replacement: string)
const re = new RegExp(`<!-- cli:replace ${id} -->\\n[\\s\\S]*?\\n<!-- /cli:replace ${id} -->`);
return markdown.replace(re, () => replacement);
}
export function stripOmitMarkers(markdown: string): string {
const re = /\n?<!-- cli:omit \S+ -->\n[\s\S]*?\n<!-- \/cli:omit \S+ -->\n?/g;
return markdown.replace(re, '\n');
}
+55 -1
View File
@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest';
import { replaceMarker } from '../replace.js';
import { replaceMarker, stripOmitMarkers } from '../replace.js';
describe('replaceMarker', () => {
it('replaces content between markers', () => {
@@ -63,3 +63,57 @@ end`;
expect(result).toBe('start\nsingle line\nend');
});
});
describe('stripOmitMarkers', () => {
it('removes content between omit markers', () => {
const markdown = `# Title
<!-- cli:omit installation -->
CLI-only hint
<!-- /cli:omit installation -->
## Footer`;
const result = stripOmitMarkers(markdown);
expect(result).not.toContain('CLI-only hint');
expect(result).not.toContain('cli:omit');
expect(result).toContain('# Title');
expect(result).toContain('## Footer');
});
it('returns unchanged markdown when no markers are present', () => {
const markdown = '# Title\n\nSome content';
expect(stripOmitMarkers(markdown)).toBe(markdown);
});
it('removes multiple omit blocks with different ids', () => {
const markdown = `before
<!-- cli:omit one -->
alpha
<!-- /cli:omit one -->
middle
<!-- cli:omit two -->
beta
<!-- /cli:omit two -->
after`;
const result = stripOmitMarkers(markdown);
expect(result).not.toContain('alpha');
expect(result).not.toContain('beta');
expect(result).toContain('before');
expect(result).toContain('middle');
expect(result).toContain('after');
});
it('handles multiline content inside an omit block', () => {
const markdown = `start
<!-- cli:omit multi -->
line 1
line 2
line 3
<!-- /cli:omit multi -->
end`;
expect(stripOmitMarkers(markdown)).toBe('start\nend');
});
});
+9
View File
@@ -49,6 +49,15 @@ export default function llmsMarkdown(): AstroIntegration {
},
});
// Wrap [data-cli-omit] content with text markers the CLI strips from its output
turndown.addRule('cli-omit', {
filter: (node) => node.nodeType === 1 && (node as Element).getAttribute('data-cli-omit') !== null,
replacement: (content, node) => {
const id = (node as Element).getAttribute('data-cli-omit');
return `\n<!-- cli:omit ${id} -->\n${content}\n<!-- /cli:omit ${id} -->\n`;
},
});
// Track all docs and blog pages for llms.txt index
const docsPages: PageEntry[] = [];
const blogPages: PageEntry[] = [];
@@ -32,9 +32,9 @@ Video.js is an **HTML video player built on custom elements** &mdash; lightweigh
</FrameworkCase>
<LLMCase>
<div data-cli-replace="installation">
<div data-cli-omit="installation">
Run `npx @videojs/cli docs how-to/installation` interactively, or pass all flags:
The code examples in this guide can be tailored to your use case. Run `npx @videojs/cli docs how-to/installation` interactively, or pass all flags:
```bash
npx @videojs/cli docs how-to/installation \
@@ -45,7 +45,6 @@ npx @videojs/cli docs how-to/installation \
--source-url <url> \
--install-method <cdn|npm|pnpm|yarn|bun>
```
</div>
</LLMCase>
@@ -81,6 +80,10 @@ Video.js supports a wide range of file types and hosting services. It's easy to
<RendererPicker client:idle />
</ContentWidth>
</HumanCase>
<div data-cli-replace="installation" class="contents">
## Install Video.js
<FrameworkCase frameworks={["html"]}>
@@ -142,7 +145,7 @@ Add it to your components folder in a new file.
</ContentWidth>
</FrameworkCase>
</HumanCase>
</div>
## CSP