Skip to content

Commit b6bd5ce

Browse files
author
jdv
committed
preprocessor success
1 parent 957c071 commit b6bd5ce

4 files changed

Lines changed: 108 additions & 133 deletions

File tree

crowdsec-docs/docusaurus.config.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { themes } from "prism-react-renderer";
66
import tailwindPlugin from "./plugins/tailwind-config";
77
import { ctiApiSidebar, guidesSideBar, remediationSideBar } from "./sidebarsUnversioned";
88

9-
const extractPlugin = require('./plugins/remark-extract/extract-plugin');
9+
const extractPreprocessor = require("./plugins/extract-preprocessor");
1010

1111
const generateCurrentAndNextRedirects = (s) => [
1212
{
@@ -222,6 +222,7 @@ const config: Config = {
222222
admonitions: true,
223223
headingIds: true,
224224
},
225+
preprocessor:extractPreprocessor
225226
},
226227
stylesheets: [
227228
{
@@ -292,10 +293,7 @@ const config: Config = {
292293
current: {
293294
path: "/next",
294295
},
295-
},
296-
remarkPlugins: [
297-
[extractPlugin, {paths: ['./unversioned']}],
298-
]
296+
}
299297
},
300298
blog: {
301299
showReadingTime: true,
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
const fs = require('fs');
2+
const path = require('path');
3+
4+
// --- CONFIGURATION ---
5+
// The directories to scan for snippets
6+
const DOCS_DIRS = ['./docs', './unversioned'];
7+
// ---------------------
8+
9+
const snippetRegistry = new Map();
10+
let isIndexed = false;
11+
12+
// Helper: Recursively find all .md/.mdx files
13+
const getAllFiles = (dirPath, arrayOfFiles = []) => {
14+
if (!fs.existsSync(dirPath)) return arrayOfFiles;
15+
16+
const files = fs.readdirSync(dirPath);
17+
files.forEach((file) => {
18+
const fullPath = path.join(dirPath, file);
19+
if (fs.statSync(fullPath).isDirectory()) {
20+
getAllFiles(fullPath, arrayOfFiles);
21+
} else if (file.endsWith('.md') || file.endsWith('.mdx')) {
22+
arrayOfFiles.push(fullPath);
23+
}
24+
});
25+
return arrayOfFiles;
26+
};
27+
28+
// Helper: Extract Doc ID from Frontmatter
29+
const getDocId = (content, filename) => {
30+
const idMatch = content.match(/^---\s+[\s\S]*?\nid:\s*(.*?)\s*[\n\r]/m);
31+
if (idMatch && idMatch[1]) {
32+
return idMatch[1].replace(/['"]/g, '').trim();
33+
}
34+
return filename;
35+
};
36+
37+
// --- CORE LOGIC ---
38+
const buildIndex = () => {
39+
if (isIndexed) return;
40+
console.log('[ExtractPreprocessor] ⚡ Indexing snippets via Regex...');
41+
42+
const allFiles = [];
43+
DOCS_DIRS.forEach(dir => getAllFiles(path.resolve(process.cwd(), dir), allFiles));
44+
45+
let count = 0;
46+
47+
// Regex to find: <div data-extract="ID"> CONTENT </div>
48+
// We use [\s\S]*? to match content across multiple lines (lazy match)
49+
const extractRegex = /<div\s+data-extract=["']([^"']+)["'][^>]*>([\s\S]*?)<\/div>/g;
50+
51+
allFiles.forEach(filePath => {
52+
try {
53+
const content = fs.readFileSync(filePath, 'utf8');
54+
const filename = path.basename(filePath, path.extname(filePath));
55+
const docId = getDocId(content, filename);
56+
57+
let match;
58+
// Loop through all matches in the file
59+
while ((match = extractRegex.exec(content)) !== null) {
60+
let [fullTag, extractId, snippetContent] = match;
61+
62+
// Clean up the content (optional: trim leading/trailing newlines)
63+
snippetContent = snippetContent.replace(/^\n+|\n+$/g, '');
64+
65+
// Generate Key: "docId:snippetId"
66+
// If the ID already has a colon, assume user provided full ID
67+
const key = extractId.includes(':') ? extractId : `${docId}:${extractId}`;
68+
69+
snippetRegistry.set(key, snippetContent);
70+
console.log(`[ExtractPreprocessor] ⚡ Indexed snippet: ${key}`);
71+
count++;
72+
}
73+
} catch (e) {
74+
console.warn(`[ExtractPreprocessor] Failed to read ${filePath}`);
75+
}
76+
});
77+
78+
isIndexed = true;
79+
console.log(`[ExtractPreprocessor] ⚡ Indexed ${count} snippets.`);
80+
};
81+
82+
// This function is called by Docusaurus for EVERY markdown file
83+
const preprocessor = ({ filePath, fileContent }) => {
84+
// 1. Ensure Index exists (runs once)
85+
buildIndex();
86+
87+
// 2. Regex to find: <div data-extract-copy="ID" />
88+
// Matches <div data-extract-copy="xyz"></div> OR <div data-extract-copy="xyz" />
89+
const copyRegex = /<div\s+data-extract-copy=["']([^"']+)["']\s*\/?>\s*(?:<\/div>)?/g;
90+
91+
// 3. Replace with content
92+
return fileContent.replace(copyRegex, (match, requestedId) => {
93+
if (snippetRegistry.has(requestedId)) {
94+
// Return the stored snippet content
95+
return snippetRegistry.get(requestedId);
96+
} else {
97+
console.error(`[ExtractPreprocessor] ❌ Snippet not found: "${requestedId}" in ${path.basename(filePath)}`);
98+
// Return an error message in the UI so you see it
99+
return `> **Error: Snippet "${requestedId}" not found.**`;
100+
}
101+
});
102+
};
103+
104+
module.exports = preprocessor;

crowdsec-docs/plugins/remark-extract/extract-plugin.js

Lines changed: 0 additions & 126 deletions
This file was deleted.

crowdsec-docs/unversioned/troubleshooting/intro.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,5 @@ When using `cscli` to list your parsers, scenarios and collections, some might a
9393
See [CAPI documentation](/docs/next/central_api/intro).
9494

9595
### stack Health issues list
96-
YEP:
9796

98-
<div data-extract-copy="stackhealth_issues_list"></div>
97+
<div data-extract-copy="console_issues:stackhealth_issues_list"></div>

0 commit comments

Comments
 (0)