@growthbeaker/vscode-help-docs 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,183 @@
1
+ # vscode-help-docs
2
+
3
+ A reusable package that turns a folder of markdown files into a navigable, themed help viewer panel inside VS Code.
4
+
5
+ ## Why
6
+
7
+ VS Code extensions that ship user-facing docs have three unsatisfying options: open an external browser (loses context), use the built-in markdown preview (no sidebar, no branding), or build a custom webview from scratch. This package eliminates that repeated work.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install vscode-help-docs
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ```typescript
18
+ import { createHelpPanel } from "vscode-help-docs";
19
+
20
+ // In your extension's activate()
21
+ const cmd = vscode.commands.registerCommand("myExtension.openHelp", () => {
22
+ createHelpPanel({
23
+ contentRoot: path.join(context.extensionPath, "help"),
24
+ extensionContext: context,
25
+ title: "My Extension Help",
26
+ });
27
+ });
28
+
29
+ context.subscriptions.push(cmd);
30
+ ```
31
+
32
+ Register the command in your `package.json`:
33
+
34
+ ```json
35
+ {
36
+ "contributes": {
37
+ "commands": [{
38
+ "command": "myExtension.openHelp",
39
+ "title": "Open Help"
40
+ }]
41
+ }
42
+ }
43
+ ```
44
+
45
+ ## Writing Content
46
+
47
+ ### Markdown files
48
+
49
+ Each `.md` file uses YAML frontmatter for metadata:
50
+
51
+ ```markdown
52
+ ---
53
+ title: Getting Started
54
+ order: 1
55
+ hidden: false
56
+ ---
57
+
58
+ # Getting Started
59
+
60
+ Your content here...
61
+ ```
62
+
63
+ | Field | Type | Default | Description |
64
+ |-------|------|---------|-------------|
65
+ | `title` | string | Filename (title-cased) | Display name in the nav sidebar |
66
+ | `order` | number | Alphabetical | Sort position within its folder |
67
+ | `hidden` | boolean | `false` | If `true`, excluded from nav tree |
68
+
69
+ ### Folder metadata
70
+
71
+ Each folder can contain an optional `_meta.json`:
72
+
73
+ ```json
74
+ {
75
+ "title": "User Guide",
76
+ "order": 1,
77
+ "collapsed": false
78
+ }
79
+ ```
80
+
81
+ ### Example content tree
82
+
83
+ ```
84
+ help/
85
+ getting-started/
86
+ _meta.json → { "title": "Getting Started", "order": 1 }
87
+ 01-installation.md
88
+ 02-first-project.md
89
+ features/
90
+ _meta.json → { "title": "Features", "order": 2 }
91
+ overview.md
92
+ troubleshooting/
93
+ _meta.json → { "title": "Troubleshooting", "order": 3 }
94
+ common-issues.md
95
+ faq.md
96
+ ```
97
+
98
+ ## Configuration
99
+
100
+ ```typescript
101
+ createHelpPanel({
102
+ // Required
103
+ contentRoot: string, // Absolute path to your docs folder
104
+ extensionContext: ExtensionContext,
105
+
106
+ // Optional
107
+ title: "Help", // Panel tab title
108
+ viewColumn: ViewColumn.One, // Which editor column
109
+ defaultPage: "intro.md", // Page shown on open (default: first by sort order)
110
+ enableAnchors: true, // Anchor link scrolling
111
+ enableMermaid: false, // Mermaid diagram rendering (see below)
112
+ metaFilename: "_meta.json", // Folder metadata filename
113
+ customCss: "", // Inline CSS to inject
114
+ customCssPath: "", // Path to a CSS file to inject
115
+ });
116
+ ```
117
+
118
+ ## API
119
+
120
+ ```typescript
121
+ const help = createHelpPanel(config);
122
+
123
+ help.navigateTo("features/overview.md"); // Navigate programmatically
124
+ help.refresh(); // Rebuild nav tree
125
+ help.dispose(); // Close the panel
126
+ ```
127
+
128
+ Calling `createHelpPanel` with the same `contentRoot` when a panel is already open reveals the existing panel (singleton behavior).
129
+
130
+ ## Mermaid Diagrams
131
+
132
+ Enable Mermaid diagram rendering for fenced ` ```mermaid ` code blocks:
133
+
134
+ ```typescript
135
+ createHelpPanel({
136
+ // ...
137
+ enableMermaid: true,
138
+ });
139
+ ```
140
+
141
+ Supports flowcharts, sequence diagrams, class diagrams, state diagrams, pie charts, git graphs, and more.
142
+
143
+ **Note:** Enabling Mermaid adds `'unsafe-inline'` to the webview's `style-src` CSP directive (Mermaid injects inline styles into SVGs). When disabled, the strict CSP is preserved.
144
+
145
+ ## Theming
146
+
147
+ The viewer automatically adapts to the active VS Code theme (Light, Dark, High Contrast) using CSS custom properties. Override styles with `customCss` or `customCssPath`.
148
+
149
+ ## Error Handling
150
+
151
+ The package handles common content authoring mistakes gracefully:
152
+
153
+ - **Malformed YAML frontmatter** — file still appears in nav using defaults, warning logged
154
+ - **Invalid field types** (e.g., `order: "five"`) — invalid fields fall back to defaults, valid fields preserved
155
+ - **Malformed `_meta.json`** — folder uses defaults, siblings unaffected
156
+ - **Circular symlinks** — detected and skipped, rest of tree built normally
157
+ - **Excessive nesting** (>20 levels) — truncated with warning
158
+ - **Broken internal links** — stays on current page, shows error message, logs diagnostic
159
+ - **Missing anchors** — navigates to page, scrolls to top, shows notification
160
+
161
+ ## Links
162
+
163
+ Internal links navigate within the viewer, external links open in the system browser:
164
+
165
+ ```markdown
166
+ [Installation](../getting-started/installation.md) <!-- internal -->
167
+ [With anchor](../features/overview.md#configuration) <!-- internal + anchor -->
168
+ [VS Code](https://code.visualstudio.com) <!-- external -->
169
+ ```
170
+
171
+ ## Dependencies
172
+
173
+ | Package | Purpose |
174
+ |---------|---------|
175
+ | `markdown-it` | Markdown rendering |
176
+ | `gray-matter` | Frontmatter parsing |
177
+ | `mermaid` | Diagram rendering (used when `enableMermaid: true`) |
178
+
179
+ Optional: `markdown-it-anchor` for heading anchor IDs.
180
+
181
+ ## License
182
+
183
+ MIT
@@ -0,0 +1,4 @@
1
+ import * as vscode from 'vscode';
2
+ export declare function activate(context: vscode.ExtensionContext): void;
3
+ export declare function deactivate(): void;
4
+ //# sourceMappingURL=extension.d.ts.map
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.activate = activate;
37
+ exports.deactivate = deactivate;
38
+ const vscode = __importStar(require("vscode"));
39
+ const path = __importStar(require("path"));
40
+ const help_panel_1 = require("./help-panel");
41
+ function activate(context) {
42
+ const cmd = vscode.commands.registerCommand('helpDocs.open', () => {
43
+ (0, help_panel_1.createHelpPanel)({
44
+ contentRoot: path.join(context.extensionPath, 'test-help'),
45
+ extensionContext: context,
46
+ title: 'Help Docs',
47
+ defaultPage: 'getting-started/01-installation.md',
48
+ enableMermaid: true,
49
+ });
50
+ });
51
+ context.subscriptions.push(cmd);
52
+ }
53
+ function deactivate() { }
54
+ //# sourceMappingURL=extension.js.map
@@ -0,0 +1,62 @@
1
+ import * as vscode from 'vscode';
2
+ import { HelpViewerConfig, IHelpPanel, WebviewToExtensionMessage } from './types';
3
+ /**
4
+ * Create (or reveal) a Help Viewer panel.
5
+ * Singleton behavior: if a panel already exists for the same contentRoot, it is revealed.
6
+ */
7
+ export declare function createHelpPanel(config: HelpViewerConfig): IHelpPanel;
8
+ /**
9
+ * HelpPanel class implementing the Help Viewer webview panel.
10
+ *
11
+ * Implements:
12
+ * - screen:help-viewer-panel
13
+ * - flow:broken-internal-link-handler (AC 1.5.4 / nv00001)
14
+ * - flow:anchor-navigation-handler (AC 1.5.5 / nv00002)
15
+ */
16
+ export declare class HelpPanel implements IHelpPanel {
17
+ readonly panel: vscode.WebviewPanel;
18
+ private readonly config;
19
+ private readonly outputChannel;
20
+ private navTree;
21
+ private currentPage;
22
+ constructor(config: HelpViewerConfig);
23
+ private initialize;
24
+ /**
25
+ * Handle messages from the webview.
26
+ *
27
+ * Implements:
28
+ * - flow:broken-internal-link-handler (navigateTo with missing file)
29
+ * - flow:anchor-navigation-handler (navigateToAnchor with missing anchor)
30
+ */
31
+ handleWebviewMessage(message: WebviewToExtensionMessage): void;
32
+ /**
33
+ * Navigate to a documentation page.
34
+ *
35
+ * AC 1.5.4 (nv00001): If the target file does not exist:
36
+ * - Do not navigate away from current page
37
+ * - Display non-blocking error message
38
+ * - Log warning to output channel with target path and source document
39
+ * - No crash/reload
40
+ */
41
+ navigateTo(relativePath: string): void;
42
+ /**
43
+ * Handle anchor navigation.
44
+ *
45
+ * AC 1.5.5 (nv00002): If the anchor is not found:
46
+ * - Still navigate to target page (if specified)
47
+ * - Scroll to top when anchor not found
48
+ * - Display non-blocking notification
49
+ * - No crash/reload
50
+ */
51
+ private handleAnchorNavigation;
52
+ /** Refresh the nav tree and re-render current page */
53
+ refresh(): Promise<void>;
54
+ /** Dispose the panel */
55
+ dispose(): void;
56
+ /** Get the current page path (for testing) */
57
+ getCurrentPage(): string | null;
58
+ private postMessage;
59
+ private findFirstPage;
60
+ private getWebviewHtml;
61
+ }
62
+ //# sourceMappingURL=help-panel.d.ts.map
@@ -0,0 +1,272 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.HelpPanel = void 0;
37
+ exports.createHelpPanel = createHelpPanel;
38
+ const vscode = __importStar(require("vscode"));
39
+ const fs = __importStar(require("fs"));
40
+ const path = __importStar(require("path"));
41
+ const crypto = __importStar(require("crypto"));
42
+ const nav_tree_1 = require("./nav-tree");
43
+ const markdown_renderer_1 = require("./markdown-renderer");
44
+ /** Map of contentRoot -> active HelpPanel for singleton behavior */
45
+ const activePanels = new Map();
46
+ /**
47
+ * Create (or reveal) a Help Viewer panel.
48
+ * Singleton behavior: if a panel already exists for the same contentRoot, it is revealed.
49
+ */
50
+ function createHelpPanel(config) {
51
+ const existing = activePanels.get(config.contentRoot);
52
+ if (existing && existing.panel) {
53
+ existing.panel.reveal(config.viewColumn ?? vscode.ViewColumn.One);
54
+ return existing;
55
+ }
56
+ const panel = new HelpPanel(config);
57
+ activePanels.set(config.contentRoot, panel);
58
+ return panel;
59
+ }
60
+ /**
61
+ * HelpPanel class implementing the Help Viewer webview panel.
62
+ *
63
+ * Implements:
64
+ * - screen:help-viewer-panel
65
+ * - flow:broken-internal-link-handler (AC 1.5.4 / nv00001)
66
+ * - flow:anchor-navigation-handler (AC 1.5.5 / nv00002)
67
+ */
68
+ class HelpPanel {
69
+ constructor(config) {
70
+ this.navTree = [];
71
+ this.currentPage = null;
72
+ this.config = config;
73
+ this.outputChannel = vscode.window.createOutputChannel('Help Docs');
74
+ this.panel = vscode.window.createWebviewPanel('helpViewer', config.title ?? 'Help', config.viewColumn ?? vscode.ViewColumn.One, {
75
+ enableScripts: true,
76
+ localResourceRoots: [
77
+ vscode.Uri.file(config.contentRoot),
78
+ vscode.Uri.file(path.join(config.extensionContext.extensionPath, 'node_modules', 'vscode-help-docs', 'src', 'webview')),
79
+ vscode.Uri.file(path.join(__dirname, '..', 'src', 'webview')),
80
+ // Allow loading mermaid.js from node_modules
81
+ vscode.Uri.file(path.join(__dirname, '..', 'node_modules', 'mermaid', 'dist')),
82
+ ],
83
+ });
84
+ this.panel.onDidDispose(() => {
85
+ activePanels.delete(config.contentRoot);
86
+ this.outputChannel.dispose();
87
+ });
88
+ this.panel.webview.onDidReceiveMessage((message) => this.handleWebviewMessage(message));
89
+ this.initialize();
90
+ }
91
+ async initialize() {
92
+ this.navTree = await (0, nav_tree_1.buildNavTree)(this.config.contentRoot, {
93
+ metaFilename: this.config.metaFilename,
94
+ });
95
+ this.panel.webview.html = this.getWebviewHtml();
96
+ // Navigate to default page or first page
97
+ const defaultPage = this.config.defaultPage ?? this.findFirstPage(this.navTree);
98
+ if (defaultPage) {
99
+ this.navigateTo(defaultPage);
100
+ }
101
+ }
102
+ /**
103
+ * Handle messages from the webview.
104
+ *
105
+ * Implements:
106
+ * - flow:broken-internal-link-handler (navigateTo with missing file)
107
+ * - flow:anchor-navigation-handler (navigateToAnchor with missing anchor)
108
+ */
109
+ handleWebviewMessage(message) {
110
+ switch (message.type) {
111
+ case 'navigateTo':
112
+ this.navigateTo(message.path);
113
+ break;
114
+ case 'navigateToAnchor':
115
+ this.handleAnchorNavigation(message.path, message.anchor);
116
+ break;
117
+ case 'openExternal':
118
+ vscode.env.openExternal(vscode.Uri.parse(message.url));
119
+ break;
120
+ case 'ready':
121
+ this.postMessage({ type: 'navTree', tree: this.navTree });
122
+ break;
123
+ }
124
+ }
125
+ /**
126
+ * Navigate to a documentation page.
127
+ *
128
+ * AC 1.5.4 (nv00001): If the target file does not exist:
129
+ * - Do not navigate away from current page
130
+ * - Display non-blocking error message
131
+ * - Log warning to output channel with target path and source document
132
+ * - No crash/reload
133
+ */
134
+ navigateTo(relativePath) {
135
+ const fullPath = path.join(this.config.contentRoot, relativePath);
136
+ // AC 1.5.4: Check if file exists
137
+ if (!fs.existsSync(fullPath)) {
138
+ // Display error message to user via webview
139
+ this.postMessage({
140
+ type: 'error',
141
+ message: `Page not found: \`${relativePath}\``,
142
+ });
143
+ // Log diagnostic warning to output channel
144
+ this.outputChannel.appendLine(`[WARN] Broken internal link to "${relativePath}" from "${this.currentPage ?? '(none)'}"`);
145
+ // Do NOT update currentPage — stay on current page
146
+ return;
147
+ }
148
+ try {
149
+ const rawContent = fs.readFileSync(fullPath, 'utf-8');
150
+ const { frontmatter, content } = (0, markdown_renderer_1.parseFrontmatter)(fullPath, rawContent);
151
+ const html = (0, markdown_renderer_1.renderMarkdown)(content, this.config.enableMermaid);
152
+ const title = frontmatter.title ?? path.basename(relativePath, '.md');
153
+ this.currentPage = relativePath;
154
+ this.postMessage({ type: 'contentLoaded', html, title, path: relativePath });
155
+ }
156
+ catch (error) {
157
+ const errorMessage = error instanceof Error ? error.message : String(error);
158
+ this.postMessage({
159
+ type: 'error',
160
+ message: `Error loading page: ${errorMessage}`,
161
+ });
162
+ }
163
+ }
164
+ /**
165
+ * Handle anchor navigation.
166
+ *
167
+ * AC 1.5.5 (nv00002): If the anchor is not found:
168
+ * - Still navigate to target page (if specified)
169
+ * - Scroll to top when anchor not found
170
+ * - Display non-blocking notification
171
+ * - No crash/reload
172
+ */
173
+ handleAnchorNavigation(pagePath, anchor) {
174
+ // If a page path is provided, navigate to it first
175
+ if (pagePath) {
176
+ this.navigateTo(pagePath);
177
+ }
178
+ // Send anchor scroll command to webview
179
+ // The webview will report back if the anchor is not found
180
+ this.postMessage({ type: 'scrollToAnchor', anchor });
181
+ }
182
+ /** Refresh the nav tree and re-render current page */
183
+ async refresh() {
184
+ this.navTree = await (0, nav_tree_1.buildNavTree)(this.config.contentRoot, {
185
+ metaFilename: this.config.metaFilename,
186
+ });
187
+ this.postMessage({ type: 'navTree', tree: this.navTree });
188
+ if (this.currentPage) {
189
+ this.navigateTo(this.currentPage);
190
+ }
191
+ }
192
+ /** Dispose the panel */
193
+ dispose() {
194
+ this.panel.dispose();
195
+ }
196
+ /** Get the current page path (for testing) */
197
+ getCurrentPage() {
198
+ return this.currentPage;
199
+ }
200
+ postMessage(message) {
201
+ this.panel.webview.postMessage(message);
202
+ }
203
+ findFirstPage(nodes) {
204
+ for (const node of nodes) {
205
+ if (node.type === 'page') {
206
+ return node.path;
207
+ }
208
+ if (node.children) {
209
+ const found = this.findFirstPage(node.children);
210
+ if (found)
211
+ return found;
212
+ }
213
+ }
214
+ return null;
215
+ }
216
+ getWebviewHtml() {
217
+ const nonce = crypto.randomBytes(16).toString('hex');
218
+ const cspSource = this.panel.webview.cspSource;
219
+ const enableMermaid = this.config.enableMermaid ?? false;
220
+ const styleUri = this.panel.webview.asWebviewUri(vscode.Uri.file(path.join(__dirname, '..', 'src', 'webview', 'styles.css')));
221
+ const scriptUri = this.panel.webview.asWebviewUri(vscode.Uri.file(path.join(__dirname, '..', 'src', 'webview', 'main.js')));
222
+ // Mermaid injects inline styles into SVGs, so we need 'unsafe-inline' in style-src when enabled
223
+ const styleSrc = enableMermaid
224
+ ? `${cspSource} 'nonce-${nonce}' 'unsafe-inline'`
225
+ : `${cspSource} 'nonce-${nonce}'`;
226
+ let mermaidScript = '';
227
+ if (enableMermaid) {
228
+ try {
229
+ const mermaidPath = require.resolve('mermaid/dist/mermaid.min.js');
230
+ const mermaidUri = this.panel.webview.asWebviewUri(vscode.Uri.file(mermaidPath));
231
+ mermaidScript = `<script nonce="${nonce}" src="${mermaidUri}"></script>`;
232
+ }
233
+ catch {
234
+ // mermaid not installed — skip silently
235
+ }
236
+ }
237
+ let customStyles = '';
238
+ if (this.config.customCss) {
239
+ customStyles += `<style nonce="${nonce}">${this.config.customCss}</style>`;
240
+ }
241
+ if (this.config.customCssPath) {
242
+ const customCssUri = this.panel.webview.asWebviewUri(vscode.Uri.file(this.config.customCssPath));
243
+ customStyles += `<link rel="stylesheet" href="${customCssUri}">`;
244
+ }
245
+ return `<!DOCTYPE html>
246
+ <html lang="en">
247
+ <head>
248
+ <meta charset="UTF-8">
249
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
250
+ <meta http-equiv="Content-Security-Policy"
251
+ content="default-src 'none'; style-src ${styleSrc}; script-src 'nonce-${nonce}'; img-src ${cspSource} https:;">
252
+ <link rel="stylesheet" href="${styleUri}">
253
+ ${customStyles}
254
+ <title>${this.config.title ?? 'Help'}</title>
255
+ </head>
256
+ <body>
257
+ <div class="help-viewer">
258
+ <nav class="nav-sidebar" id="nav-sidebar"></nav>
259
+ <main class="content-pane" id="content-pane">
260
+ <div class="error-banner" id="error-banner" style="display:none;"></div>
261
+ <div class="notification-toast" id="notification-toast" style="display:none;"></div>
262
+ <article id="content-body"></article>
263
+ </main>
264
+ </div>
265
+ ${mermaidScript}
266
+ <script nonce="${nonce}" src="${scriptUri}"></script>
267
+ </body>
268
+ </html>`;
269
+ }
270
+ }
271
+ exports.HelpPanel = HelpPanel;
272
+ //# sourceMappingURL=help-panel.js.map
@@ -0,0 +1,3 @@
1
+ export { createHelpPanel } from './help-panel';
2
+ export type { HelpViewerConfig, NavNode, IHelpPanel as HelpPanel, Frontmatter, FolderMeta, } from './types';
3
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createHelpPanel = void 0;
4
+ var help_panel_1 = require("./help-panel");
5
+ Object.defineProperty(exports, "createHelpPanel", { enumerable: true, get: function () { return help_panel_1.createHelpPanel; } });
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,27 @@
1
+ import { Frontmatter } from './types';
2
+ /**
3
+ * Parse frontmatter from a markdown file with graceful error handling.
4
+ *
5
+ * Implements:
6
+ * - AC 1.8.2: Malformed YAML Frontmatter Graceful Degradation
7
+ * - AC 1.8.3: Frontmatter Field Type Validation
8
+ */
9
+ export declare function parseFrontmatter(filePath: string, rawContent: string): {
10
+ frontmatter: Frontmatter;
11
+ content: string;
12
+ };
13
+ /**
14
+ * Validate frontmatter field types, logging warnings for invalid types.
15
+ *
16
+ * Implements AC 1.8.3: Frontmatter Field Type Validation
17
+ */
18
+ export declare function validateFrontmatterFields(filePath: string, data: Record<string, unknown>): Frontmatter;
19
+ /** Render markdown content to HTML */
20
+ export declare function renderMarkdown(content: string, enableMermaid?: boolean): string;
21
+ /**
22
+ * Convert a filename to a title-cased display name.
23
+ * Strips .md extension, replaces hyphens/underscores with spaces,
24
+ * removes leading numeric prefixes (e.g., "01-"), and title-cases each word.
25
+ */
26
+ export declare function titleCaseFilename(filename: string): string;
27
+ //# sourceMappingURL=markdown-renderer.d.ts.map