@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 +183 -0
- package/dist/extension.d.ts +4 -0
- package/dist/extension.js +54 -0
- package/dist/help-panel.d.ts +62 -0
- package/dist/help-panel.js +272 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +6 -0
- package/dist/markdown-renderer.d.ts +27 -0
- package/dist/markdown-renderer.js +139 -0
- package/dist/nav-tree.d.ts +19 -0
- package/dist/nav-tree.js +215 -0
- package/dist/types.d.ts +95 -0
- package/dist/types.js +3 -0
- package/package.json +63 -0
- package/src/webview/main.js +312 -0
- package/src/webview/styles.css +256 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.parseFrontmatter = parseFrontmatter;
|
|
7
|
+
exports.validateFrontmatterFields = validateFrontmatterFields;
|
|
8
|
+
exports.renderMarkdown = renderMarkdown;
|
|
9
|
+
exports.titleCaseFilename = titleCaseFilename;
|
|
10
|
+
const gray_matter_1 = __importDefault(require("gray-matter"));
|
|
11
|
+
const markdown_it_1 = __importDefault(require("markdown-it"));
|
|
12
|
+
function createMarkdownIt(enableMermaid) {
|
|
13
|
+
const instance = new markdown_it_1.default({
|
|
14
|
+
html: false,
|
|
15
|
+
linkify: true,
|
|
16
|
+
typographer: true,
|
|
17
|
+
});
|
|
18
|
+
// Try to load markdown-it-anchor if available
|
|
19
|
+
try {
|
|
20
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
21
|
+
const anchor = require('markdown-it-anchor');
|
|
22
|
+
instance.use(anchor);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// markdown-it-anchor is optional
|
|
26
|
+
}
|
|
27
|
+
if (enableMermaid) {
|
|
28
|
+
applyMermaidPlugin(instance);
|
|
29
|
+
}
|
|
30
|
+
return instance;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* markdown-it plugin: converts ```mermaid code blocks into
|
|
34
|
+
* <div class="mermaid"> containers for client-side rendering.
|
|
35
|
+
*/
|
|
36
|
+
function applyMermaidPlugin(md) {
|
|
37
|
+
const defaultFence = md.renderer.rules.fence.bind(md.renderer.rules);
|
|
38
|
+
md.renderer.rules.fence = (tokens, idx, options, env, self) => {
|
|
39
|
+
const token = tokens[idx];
|
|
40
|
+
if (token.info.trim().toLowerCase() === 'mermaid') {
|
|
41
|
+
// Wrap diagram source in a div that mermaid.js will find and render
|
|
42
|
+
const escaped = md.utils.escapeHtml(token.content);
|
|
43
|
+
return `<div class="mermaid">${escaped}</div>\n`;
|
|
44
|
+
}
|
|
45
|
+
return defaultFence(tokens, idx, options, env, self);
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
// Default instance (no mermaid)
|
|
49
|
+
const md = createMarkdownIt(false);
|
|
50
|
+
// Mermaid-enabled instance (created lazily)
|
|
51
|
+
let mdMermaid = null;
|
|
52
|
+
/**
|
|
53
|
+
* Parse frontmatter from a markdown file with graceful error handling.
|
|
54
|
+
*
|
|
55
|
+
* Implements:
|
|
56
|
+
* - AC 1.8.2: Malformed YAML Frontmatter Graceful Degradation
|
|
57
|
+
* - AC 1.8.3: Frontmatter Field Type Validation
|
|
58
|
+
*/
|
|
59
|
+
function parseFrontmatter(filePath, rawContent) {
|
|
60
|
+
try {
|
|
61
|
+
const result = (0, gray_matter_1.default)(rawContent);
|
|
62
|
+
const frontmatter = validateFrontmatterFields(filePath, result.data);
|
|
63
|
+
return { frontmatter, content: result.content };
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
// AC 1.8.2: Malformed YAML — apply defaults, strip frontmatter, log warning
|
|
67
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
68
|
+
console.warn(`Malformed frontmatter in ${filePath}: ${errorMessage}`);
|
|
69
|
+
// Strip the malformed frontmatter block from content
|
|
70
|
+
const content = stripFrontmatter(rawContent);
|
|
71
|
+
return { frontmatter: {}, content };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Validate frontmatter field types, logging warnings for invalid types.
|
|
76
|
+
*
|
|
77
|
+
* Implements AC 1.8.3: Frontmatter Field Type Validation
|
|
78
|
+
*/
|
|
79
|
+
function validateFrontmatterFields(filePath, data) {
|
|
80
|
+
const result = {};
|
|
81
|
+
const invalidFields = [];
|
|
82
|
+
if ('title' in data) {
|
|
83
|
+
if (typeof data.title === 'string') {
|
|
84
|
+
result.title = data.title;
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
invalidFields.push(`title (expected string, got ${typeof data.title})`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if ('order' in data) {
|
|
91
|
+
if (typeof data.order === 'number' && !isNaN(data.order)) {
|
|
92
|
+
result.order = data.order;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
invalidFields.push(`order (expected number, got ${typeof data.order})`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if ('hidden' in data) {
|
|
99
|
+
if (typeof data.hidden === 'boolean') {
|
|
100
|
+
result.hidden = data.hidden;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
invalidFields.push(`hidden (expected boolean, got ${typeof data.hidden})`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (invalidFields.length > 0) {
|
|
107
|
+
console.warn(`Invalid frontmatter field types in ${filePath}: ${invalidFields.join(', ')}`);
|
|
108
|
+
}
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
/** Render markdown content to HTML */
|
|
112
|
+
function renderMarkdown(content, enableMermaid = false) {
|
|
113
|
+
if (enableMermaid) {
|
|
114
|
+
if (!mdMermaid) {
|
|
115
|
+
mdMermaid = createMarkdownIt(true);
|
|
116
|
+
}
|
|
117
|
+
return mdMermaid.render(content);
|
|
118
|
+
}
|
|
119
|
+
return md.render(content);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Convert a filename to a title-cased display name.
|
|
123
|
+
* Strips .md extension, replaces hyphens/underscores with spaces,
|
|
124
|
+
* removes leading numeric prefixes (e.g., "01-"), and title-cases each word.
|
|
125
|
+
*/
|
|
126
|
+
function titleCaseFilename(filename) {
|
|
127
|
+
return filename
|
|
128
|
+
.replace(/\.md$/i, '')
|
|
129
|
+
.replace(/^\d+-/, '')
|
|
130
|
+
.replace(/[-_]/g, ' ')
|
|
131
|
+
.replace(/\b\w/g, (char) => char.toUpperCase())
|
|
132
|
+
.trim();
|
|
133
|
+
}
|
|
134
|
+
/** Strip a frontmatter block from raw markdown content */
|
|
135
|
+
function stripFrontmatter(rawContent) {
|
|
136
|
+
// Match opening --- through closing --- (or end of leading block)
|
|
137
|
+
return rawContent.replace(/^---[\s\S]*?(?:---\s*\n|---\s*$)/, '').trim();
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=markdown-renderer.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { NavNode, FolderMeta } from './types';
|
|
2
|
+
export interface BuildNavTreeOptions {
|
|
3
|
+
metaFilename?: string;
|
|
4
|
+
maxDepth?: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Build a navigation tree from a documentation folder structure.
|
|
8
|
+
*
|
|
9
|
+
* Implements: flow:navigation-tree-construction
|
|
10
|
+
* Covers: AC 1.2.3 (malformed _meta.json), AC 1.2.4 (circular symlinks, depth limits)
|
|
11
|
+
*/
|
|
12
|
+
export declare function buildNavTree(contentRoot: string, options?: BuildNavTreeOptions): Promise<NavNode[]>;
|
|
13
|
+
/**
|
|
14
|
+
* Parse a folder's _meta.json file with graceful error handling.
|
|
15
|
+
*
|
|
16
|
+
* Implements AC 1.2.3: Graceful Handling of Malformed _meta.json Files
|
|
17
|
+
*/
|
|
18
|
+
export declare function parseFolderMeta(dirPath: string, metaFilename?: string): FolderMeta;
|
|
19
|
+
//# sourceMappingURL=nav-tree.d.ts.map
|
package/dist/nav-tree.js
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
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.buildNavTree = buildNavTree;
|
|
37
|
+
exports.parseFolderMeta = parseFolderMeta;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const markdown_renderer_1 = require("./markdown-renderer");
|
|
41
|
+
const DEFAULT_MAX_DEPTH = 20;
|
|
42
|
+
const DEFAULT_META_FILENAME = '_meta.json';
|
|
43
|
+
/**
|
|
44
|
+
* Build a navigation tree from a documentation folder structure.
|
|
45
|
+
*
|
|
46
|
+
* Implements: flow:navigation-tree-construction
|
|
47
|
+
* Covers: AC 1.2.3 (malformed _meta.json), AC 1.2.4 (circular symlinks, depth limits)
|
|
48
|
+
*/
|
|
49
|
+
async function buildNavTree(contentRoot, options) {
|
|
50
|
+
const metaFilename = options?.metaFilename ?? DEFAULT_META_FILENAME;
|
|
51
|
+
const maxDepth = options?.maxDepth ?? DEFAULT_MAX_DEPTH;
|
|
52
|
+
const visitedRealPaths = new Set();
|
|
53
|
+
return scanDirectory(contentRoot, contentRoot, metaFilename, 0, maxDepth, visitedRealPaths);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Recursively scan a directory to build NavNode children.
|
|
57
|
+
*/
|
|
58
|
+
async function scanDirectory(dirPath, contentRoot, metaFilename, depth, maxDepth, visitedRealPaths) {
|
|
59
|
+
// AC 1.2.4: Check max depth
|
|
60
|
+
if (depth > maxDepth) {
|
|
61
|
+
console.warn(`Max nesting depth (${maxDepth}) exceeded at ${dirPath}, skipping`);
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
// AC 1.2.4: Check circular symlinks
|
|
65
|
+
try {
|
|
66
|
+
const realPath = fs.realpathSync(dirPath);
|
|
67
|
+
if (visitedRealPaths.has(realPath)) {
|
|
68
|
+
const stats = fs.lstatSync(dirPath);
|
|
69
|
+
if (stats.isSymbolicLink()) {
|
|
70
|
+
console.warn(`Circular symlink detected at ${dirPath} (points to ${realPath}), skipping`);
|
|
71
|
+
}
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
visitedRealPaths.add(realPath);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// If we can't stat the directory, skip it
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
let entries;
|
|
81
|
+
try {
|
|
82
|
+
entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return [];
|
|
86
|
+
}
|
|
87
|
+
const nodes = [];
|
|
88
|
+
for (const entry of entries) {
|
|
89
|
+
// Skip hidden and meta entries
|
|
90
|
+
if (entry.name.startsWith('_') || entry.name.startsWith('.')) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const entryPath = path.join(dirPath, entry.name);
|
|
94
|
+
const relativePath = path.relative(contentRoot, entryPath);
|
|
95
|
+
if (entry.isDirectory() || entry.isSymbolicLink()) {
|
|
96
|
+
// Check if symlink points to a directory
|
|
97
|
+
if (entry.isSymbolicLink()) {
|
|
98
|
+
try {
|
|
99
|
+
const targetStats = fs.statSync(entryPath);
|
|
100
|
+
if (!targetStats.isDirectory()) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Recurse into subdirectory
|
|
109
|
+
const childVisited = new Set(visitedRealPaths);
|
|
110
|
+
const children = await scanDirectory(entryPath, contentRoot, metaFilename, depth + 1, maxDepth, childVisited);
|
|
111
|
+
// Skip empty folders (no page children)
|
|
112
|
+
if (children.length === 0) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
// Read folder metadata
|
|
116
|
+
const meta = parseFolderMeta(entryPath, metaFilename);
|
|
117
|
+
nodes.push({
|
|
118
|
+
type: 'folder',
|
|
119
|
+
title: meta.title ?? (0, markdown_renderer_1.titleCaseFilename)(entry.name),
|
|
120
|
+
order: meta.order ?? Infinity,
|
|
121
|
+
path: relativePath,
|
|
122
|
+
children,
|
|
123
|
+
collapsed: meta.collapsed ?? false,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
else if (entry.name.endsWith('.md')) {
|
|
127
|
+
// Parse markdown file
|
|
128
|
+
try {
|
|
129
|
+
const rawContent = fs.readFileSync(entryPath, 'utf-8');
|
|
130
|
+
const { frontmatter } = (0, markdown_renderer_1.parseFrontmatter)(entryPath, rawContent);
|
|
131
|
+
// Skip hidden files
|
|
132
|
+
if (frontmatter.hidden === true) {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
nodes.push({
|
|
136
|
+
type: 'page',
|
|
137
|
+
title: frontmatter.title ?? (0, markdown_renderer_1.titleCaseFilename)(entry.name),
|
|
138
|
+
order: frontmatter.order ?? Infinity,
|
|
139
|
+
path: relativePath,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// If we can't read the file, skip it
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// Sort: by order ascending, then by title alphabetically
|
|
149
|
+
nodes.sort((a, b) => {
|
|
150
|
+
if (a.order !== b.order) {
|
|
151
|
+
return a.order - b.order;
|
|
152
|
+
}
|
|
153
|
+
return a.title.localeCompare(b.title);
|
|
154
|
+
});
|
|
155
|
+
return nodes;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Parse a folder's _meta.json file with graceful error handling.
|
|
159
|
+
*
|
|
160
|
+
* Implements AC 1.2.3: Graceful Handling of Malformed _meta.json Files
|
|
161
|
+
*/
|
|
162
|
+
function parseFolderMeta(dirPath, metaFilename = DEFAULT_META_FILENAME) {
|
|
163
|
+
const metaPath = path.join(dirPath, metaFilename);
|
|
164
|
+
if (!fs.existsSync(metaPath)) {
|
|
165
|
+
return {};
|
|
166
|
+
}
|
|
167
|
+
let rawContent;
|
|
168
|
+
try {
|
|
169
|
+
rawContent = fs.readFileSync(metaPath, 'utf-8');
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
return {};
|
|
173
|
+
}
|
|
174
|
+
let data;
|
|
175
|
+
try {
|
|
176
|
+
data = JSON.parse(rawContent);
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
180
|
+
console.warn(`Malformed ${metaFilename} at ${dirPath}: ${errorMessage}`);
|
|
181
|
+
return {};
|
|
182
|
+
}
|
|
183
|
+
// Validate field types (same pattern as frontmatter validation)
|
|
184
|
+
const result = {};
|
|
185
|
+
const invalidFields = [];
|
|
186
|
+
if ('title' in data) {
|
|
187
|
+
if (typeof data.title === 'string') {
|
|
188
|
+
result.title = data.title;
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
invalidFields.push('title');
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if ('order' in data) {
|
|
195
|
+
if (typeof data.order === 'number' && !isNaN(data.order)) {
|
|
196
|
+
result.order = data.order;
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
invalidFields.push('order');
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if ('collapsed' in data) {
|
|
203
|
+
if (typeof data.collapsed === 'boolean') {
|
|
204
|
+
result.collapsed = data.collapsed;
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
invalidFields.push('collapsed');
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
if (invalidFields.length > 0) {
|
|
211
|
+
console.warn(`Invalid field types in ${metaPath}: ${invalidFields.join(', ')}`);
|
|
212
|
+
}
|
|
213
|
+
return result;
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=nav-tree.js.map
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import * as vscode from 'vscode';
|
|
2
|
+
/** Configuration for creating a Help Viewer panel */
|
|
3
|
+
export interface HelpViewerConfig {
|
|
4
|
+
/** Absolute path to the root folder containing markdown docs */
|
|
5
|
+
contentRoot: string;
|
|
6
|
+
/** Extension context (needed for webview URI resolution) */
|
|
7
|
+
extensionContext: vscode.ExtensionContext;
|
|
8
|
+
/** Panel title shown in the VS Code tab */
|
|
9
|
+
title?: string;
|
|
10
|
+
/** Column to open the panel in */
|
|
11
|
+
viewColumn?: vscode.ViewColumn;
|
|
12
|
+
/** Optional CSS to inject (appended after base theme styles) */
|
|
13
|
+
customCss?: string;
|
|
14
|
+
/** Optional path to a CSS file to inject */
|
|
15
|
+
customCssPath?: string;
|
|
16
|
+
/** Enable anchor link scrolling within documents */
|
|
17
|
+
enableAnchors?: boolean;
|
|
18
|
+
/** Enable Mermaid diagram rendering in code blocks */
|
|
19
|
+
enableMermaid?: boolean;
|
|
20
|
+
/** Folder metadata filename */
|
|
21
|
+
metaFilename?: string;
|
|
22
|
+
/** Default page to show on open (relative path from contentRoot) */
|
|
23
|
+
defaultPage?: string;
|
|
24
|
+
}
|
|
25
|
+
/** A node in the navigation tree */
|
|
26
|
+
export interface NavNode {
|
|
27
|
+
type: 'folder' | 'page';
|
|
28
|
+
title: string;
|
|
29
|
+
order: number;
|
|
30
|
+
/** Relative path from contentRoot */
|
|
31
|
+
path: string;
|
|
32
|
+
/** Child nodes (folders only) */
|
|
33
|
+
children?: NavNode[];
|
|
34
|
+
/** Initial collapsed state (folders only) */
|
|
35
|
+
collapsed?: boolean;
|
|
36
|
+
}
|
|
37
|
+
/** YAML frontmatter metadata from a markdown file */
|
|
38
|
+
export interface Frontmatter {
|
|
39
|
+
title?: string;
|
|
40
|
+
order?: number;
|
|
41
|
+
hidden?: boolean;
|
|
42
|
+
}
|
|
43
|
+
/** Metadata from a folder's _meta.json file */
|
|
44
|
+
export interface FolderMeta {
|
|
45
|
+
title?: string;
|
|
46
|
+
order?: number;
|
|
47
|
+
collapsed?: boolean;
|
|
48
|
+
}
|
|
49
|
+
/** Public API handle returned by createHelpPanel */
|
|
50
|
+
export interface IHelpPanel {
|
|
51
|
+
/** The underlying VS Code WebviewPanel */
|
|
52
|
+
readonly panel: vscode.WebviewPanel;
|
|
53
|
+
/** Navigate to a specific doc page (relative path from contentRoot) */
|
|
54
|
+
navigateTo(relativePath: string): void;
|
|
55
|
+
/** Refresh the nav tree (e.g., after docs are updated) */
|
|
56
|
+
refresh(): void;
|
|
57
|
+
/** Dispose the panel */
|
|
58
|
+
dispose(): void;
|
|
59
|
+
}
|
|
60
|
+
/** Messages sent between extension host and webview */
|
|
61
|
+
export type ExtensionToWebviewMessage = {
|
|
62
|
+
type: 'contentLoaded';
|
|
63
|
+
html: string;
|
|
64
|
+
title: string;
|
|
65
|
+
path: string;
|
|
66
|
+
} | {
|
|
67
|
+
type: 'navTree';
|
|
68
|
+
tree: NavNode[];
|
|
69
|
+
} | {
|
|
70
|
+
type: 'error';
|
|
71
|
+
message: string;
|
|
72
|
+
} | {
|
|
73
|
+
type: 'anchorNotFound';
|
|
74
|
+
anchor: string;
|
|
75
|
+
} | {
|
|
76
|
+
type: 'scrollToAnchor';
|
|
77
|
+
anchor: string;
|
|
78
|
+
} | {
|
|
79
|
+
type: 'scrollToTop';
|
|
80
|
+
};
|
|
81
|
+
/** Messages sent from webview to extension host */
|
|
82
|
+
export type WebviewToExtensionMessage = {
|
|
83
|
+
type: 'navigateTo';
|
|
84
|
+
path: string;
|
|
85
|
+
} | {
|
|
86
|
+
type: 'navigateToAnchor';
|
|
87
|
+
path?: string;
|
|
88
|
+
anchor: string;
|
|
89
|
+
} | {
|
|
90
|
+
type: 'openExternal';
|
|
91
|
+
url: string;
|
|
92
|
+
} | {
|
|
93
|
+
type: 'ready';
|
|
94
|
+
};
|
|
95
|
+
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@growthbeaker/vscode-help-docs",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A reusable VS Code webview panel that renders a folder of markdown files with a navigation sidebar",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"vscode",
|
|
9
|
+
"webview",
|
|
10
|
+
"help",
|
|
11
|
+
"documentation",
|
|
12
|
+
"markdown",
|
|
13
|
+
"navigation"
|
|
14
|
+
],
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/growth-beaker/vscode-help-docs.git"
|
|
18
|
+
},
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/growth-beaker/vscode-help-docs/issues"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://github.com/growth-beaker/vscode-help-docs#readme",
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc",
|
|
25
|
+
"prepublishOnly": "npm run build",
|
|
26
|
+
"test": "vitest run",
|
|
27
|
+
"test:watch": "vitest",
|
|
28
|
+
"test:coverage": "vitest run --coverage"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist/**/*.js",
|
|
32
|
+
"dist/**/*.d.ts",
|
|
33
|
+
"src/webview/**",
|
|
34
|
+
"README.md"
|
|
35
|
+
],
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"gray-matter": "^4.0.3",
|
|
38
|
+
"markdown-it": "^14.1.0",
|
|
39
|
+
"mermaid": "^11.14.0"
|
|
40
|
+
},
|
|
41
|
+
"optionalDependencies": {
|
|
42
|
+
"markdown-it-anchor": "^9.2.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/markdown-it": "^14.1.2",
|
|
46
|
+
"@types/node": "^25.5.0",
|
|
47
|
+
"@types/vscode": "^1.85.0",
|
|
48
|
+
"typescript": "^5.4.0",
|
|
49
|
+
"vitest": "^2.1.0"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"vscode": "^1.85.0"
|
|
53
|
+
},
|
|
54
|
+
"peerDependenciesMeta": {
|
|
55
|
+
"vscode": {
|
|
56
|
+
"optional": true
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"engines": {
|
|
60
|
+
"vscode": "^1.85.0"
|
|
61
|
+
},
|
|
62
|
+
"license": "MIT"
|
|
63
|
+
}
|