@wireweave/markdown-plugin 1.0.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,273 @@
1
+ <p align="center">
2
+ <img src="logo.svg" width="128" height="128" alt="Wireweave Markdown">
3
+ </p>
4
+
5
+ <h1 align="center">@wireweave/markdown-plugin</h1>
6
+
7
+ <p align="center">Markdown plugins to embed Wireweave diagrams in your documentation</p>
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @wireweave/markdown-plugin
13
+ # or
14
+ pnpm add @wireweave/markdown-plugin
15
+ # or
16
+ yarn add @wireweave/markdown-plugin
17
+ ```
18
+
19
+ ## Supported Libraries
20
+
21
+ - **markdown-it** - Most popular Markdown parser
22
+ - **marked** - Fast Markdown compiler
23
+ - **remarkable** - Markdown parser with CommonMark support
24
+
25
+ ## Quick Start
26
+
27
+ ### markdown-it
28
+
29
+ ```typescript
30
+ import MarkdownIt from 'markdown-it';
31
+ import { markdownItWireframe } from '@wireweave/markdown-plugin';
32
+
33
+ const md = new MarkdownIt();
34
+ md.use(markdownItWireframe, {
35
+ format: 'svg-img', // or 'html', 'svg'
36
+ });
37
+
38
+ const html = md.render(`
39
+ # My Documentation
40
+
41
+ \`\`\`wireframe
42
+ page {
43
+ card p=4 {
44
+ title "Login"
45
+ input "Email" type=email
46
+ input "Password" type=password
47
+ button "Sign In" primary
48
+ }
49
+ }
50
+ \`\`\`
51
+ `);
52
+ ```
53
+
54
+ ### marked
55
+
56
+ ```typescript
57
+ import { marked } from 'marked';
58
+ import { markedWireframe } from '@wireweave/markdown-plugin';
59
+
60
+ marked.use(markedWireframe({
61
+ format: 'svg-img',
62
+ }));
63
+
64
+ const html = marked.parse(`
65
+ # Documentation
66
+
67
+ \`\`\`wireframe
68
+ page { button "Click me" primary }
69
+ \`\`\`
70
+ `);
71
+ ```
72
+
73
+ ### remarkable
74
+
75
+ ```typescript
76
+ import { Remarkable } from 'remarkable';
77
+ import { remarkableWireframe } from '@wireweave/markdown-plugin';
78
+
79
+ const md = new Remarkable();
80
+ remarkableWireframe(md, {
81
+ format: 'svg-img',
82
+ });
83
+
84
+ const html = md.render(`
85
+ \`\`\`wireframe
86
+ page { card { text "Hello" } }
87
+ \`\`\`
88
+ `);
89
+ ```
90
+
91
+ ## Options
92
+
93
+ All plugins accept the same options:
94
+
95
+ | Option | Type | Default | Description |
96
+ |--------|------|---------|-------------|
97
+ | `format` | `'html' \| 'svg' \| 'svg-img'` | `'svg-img'` | Output format |
98
+ | `containerClass` | `string` | `'wireframe-container'` | CSS class for wrapper div |
99
+ | `errorHandling` | `'code' \| 'error' \| 'both'` | `'both'` | How to handle parse errors |
100
+
101
+ ### Output Formats
102
+
103
+ - **`svg-img`** (default): Base64-encoded SVG in an `<img>` tag. Best for compatibility.
104
+ - **`svg`**: Inline SVG. Allows CSS styling but may conflict with page styles.
105
+ - **`html`**: Full HTML/CSS rendering. Interactive but may conflict with page styles.
106
+
107
+ ### Error Handling
108
+
109
+ - **`both`** (default): Shows both error message and original code
110
+ - **`error`**: Shows only the error message
111
+ - **`code`**: Shows only the original code
112
+
113
+ ## Standalone Rendering
114
+
115
+ You can also use the `renderWireframe` function directly:
116
+
117
+ ```typescript
118
+ import { renderWireframe } from '@wireweave/markdown-plugin';
119
+
120
+ const html = renderWireframe(`
121
+ page { button "Click" primary }
122
+ `, {
123
+ format: 'svg',
124
+ containerClass: 'my-wireframe',
125
+ });
126
+ ```
127
+
128
+ ## Styling
129
+
130
+ Add CSS to style the wireframe containers:
131
+
132
+ ```css
133
+ .wireframe-container {
134
+ margin: 1rem 0;
135
+ border: 1px solid #e0e0e0;
136
+ border-radius: 4px;
137
+ overflow: hidden;
138
+ }
139
+
140
+ .wireframe-container img {
141
+ display: block;
142
+ max-width: 100%;
143
+ height: auto;
144
+ }
145
+
146
+ .wireframe-error {
147
+ color: #d32f2f;
148
+ background: #ffebee;
149
+ padding: 1rem;
150
+ margin: 0;
151
+ }
152
+
153
+ .wireframe-source {
154
+ background: #f5f5f5;
155
+ padding: 1rem;
156
+ margin: 0;
157
+ overflow-x: auto;
158
+ }
159
+ ```
160
+
161
+ ## Integration Examples
162
+
163
+ ### VitePress / VuePress
164
+
165
+ ```typescript
166
+ // .vitepress/config.ts
167
+ import { markdownItWireframe } from '@wireweave/markdown-plugin';
168
+
169
+ export default {
170
+ markdown: {
171
+ config: (md) => {
172
+ md.use(markdownItWireframe);
173
+ },
174
+ },
175
+ };
176
+ ```
177
+
178
+ ### Docusaurus
179
+
180
+ ```javascript
181
+ // docusaurus.config.js
182
+ const { markdownItWireframe } = require('@wireweave/markdown-plugin');
183
+
184
+ module.exports = {
185
+ presets: [
186
+ [
187
+ '@docusaurus/preset-classic',
188
+ {
189
+ docs: {
190
+ remarkPlugins: [],
191
+ rehypePlugins: [],
192
+ },
193
+ },
194
+ ],
195
+ ],
196
+ // For markdown-it based setup
197
+ };
198
+ ```
199
+
200
+ ### Astro
201
+
202
+ ```typescript
203
+ // astro.config.mjs
204
+ import { markdownItWireframe } from '@wireweave/markdown-plugin';
205
+
206
+ export default {
207
+ markdown: {
208
+ remarkPlugins: [],
209
+ rehypePlugins: [],
210
+ // For markdown-it integration
211
+ },
212
+ };
213
+ ```
214
+
215
+ ## API Reference
216
+
217
+ ### `markdownItWireframe(md, options?)`
218
+
219
+ Plugin for markdown-it.
220
+
221
+ ```typescript
222
+ import type MarkdownIt from 'markdown-it';
223
+ import type { WireframePluginOptions } from '@wireweave/markdown-plugin';
224
+
225
+ function markdownItWireframe(
226
+ md: MarkdownIt,
227
+ options?: WireframePluginOptions
228
+ ): void;
229
+ ```
230
+
231
+ ### `markedWireframe(options?)`
232
+
233
+ Extension for marked.
234
+
235
+ ```typescript
236
+ import type { MarkedExtension } from 'marked';
237
+ import type { WireframePluginOptions } from '@wireweave/markdown-plugin';
238
+
239
+ function markedWireframe(
240
+ options?: WireframePluginOptions
241
+ ): MarkedExtension;
242
+ ```
243
+
244
+ ### `remarkableWireframe(md, options?)`
245
+
246
+ Plugin for remarkable.
247
+
248
+ ```typescript
249
+ import type { Remarkable } from 'remarkable';
250
+ import type { WireframePluginOptions } from '@wireweave/markdown-plugin';
251
+
252
+ function remarkableWireframe(
253
+ md: Remarkable,
254
+ options?: WireframePluginOptions
255
+ ): void;
256
+ ```
257
+
258
+ ### `renderWireframe(code, options?)`
259
+
260
+ Standalone render function.
261
+
262
+ ```typescript
263
+ import type { WireframePluginOptions } from '@wireweave/markdown-plugin';
264
+
265
+ function renderWireframe(
266
+ code: string,
267
+ options?: WireframePluginOptions
268
+ ): string;
269
+ ```
270
+
271
+ ## License
272
+
273
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ markdownItWireframe: () => markdownItWireframe,
24
+ markedWireframe: () => markedWireframe,
25
+ remarkableWireframe: () => remarkableWireframe,
26
+ renderWireframe: () => renderWireframe
27
+ });
28
+ module.exports = __toCommonJS(src_exports);
29
+ var import_core = require("@wireweave/core");
30
+
31
+ // src/markdown-it.ts
32
+ function markdownItWireframe(md, options = {}) {
33
+ const defaultFence = md.renderer.rules.fence;
34
+ md.renderer.rules.fence = (tokens, idx, opts, env, self) => {
35
+ const token = tokens[idx];
36
+ const info = token.info.trim();
37
+ if (info === "wireframe" || info === "wf") {
38
+ return renderWireframe(token.content, options);
39
+ }
40
+ if (defaultFence) {
41
+ return defaultFence(tokens, idx, opts, env, self);
42
+ }
43
+ return `<pre><code class="language-${info}">${md.utils.escapeHtml(token.content)}</code></pre>`;
44
+ };
45
+ }
46
+
47
+ // src/marked.ts
48
+ function markedWireframe(options = {}) {
49
+ return {
50
+ renderer: {
51
+ code(token) {
52
+ if (token.lang === "wireframe" || token.lang === "wf") {
53
+ return renderWireframe(token.text, options);
54
+ }
55
+ return false;
56
+ }
57
+ }
58
+ };
59
+ }
60
+
61
+ // src/remarkable.ts
62
+ function escapeHtml(text) {
63
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
64
+ }
65
+ function remarkableWireframe(options = {}) {
66
+ return (md) => {
67
+ const rules = md.renderer.rules;
68
+ rules.fence = (tokens, idx, _opts, _env) => {
69
+ const token = tokens[idx];
70
+ const lang = token.params || "";
71
+ if (lang === "wireframe" || lang === "wf") {
72
+ return renderWireframe(token.content, options);
73
+ }
74
+ const langClass = lang ? ` class="language-${escapeHtml(lang)}"` : "";
75
+ return `<pre><code${langClass}>${escapeHtml(token.content)}</code></pre>
76
+ `;
77
+ };
78
+ };
79
+ }
80
+
81
+ // src/index.ts
82
+ var defaultOptions = {
83
+ format: "svg-img",
84
+ theme: "light",
85
+ containerClass: "wireframe-container",
86
+ errorHandling: "both",
87
+ containerWidth: 0,
88
+ // 0 means no scaling
89
+ maxScale: 1
90
+ };
91
+ function renderWireframe(code, options = {}) {
92
+ const opts = { ...defaultOptions, ...options };
93
+ try {
94
+ const doc = (0, import_core.parse)(code);
95
+ switch (opts.format) {
96
+ case "html": {
97
+ const { html, css } = (0, import_core.render)(doc, { theme: opts.theme });
98
+ return `
99
+ <div class="${opts.containerClass}">
100
+ <style>${css}</style>
101
+ ${html}
102
+ </div>
103
+ `.trim();
104
+ }
105
+ case "html-preview": {
106
+ const { html, css } = (0, import_core.render)(doc, { theme: opts.theme });
107
+ const firstPage = doc.children[0];
108
+ const viewport = (0, import_core.resolveViewport)(firstPage?.viewport, firstPage?.device);
109
+ const previewHtml = (0, import_core.wrapInPreviewContainer)(html, viewport, {
110
+ darkMode: opts.theme === "dark",
111
+ containerWidth: opts.containerWidth > 0 ? opts.containerWidth : void 0
112
+ });
113
+ return `
114
+ <div class="${opts.containerClass}">
115
+ <style>${css}</style>
116
+ ${previewHtml}
117
+ </div>
118
+ `.trim();
119
+ }
120
+ case "svg": {
121
+ const { svg } = (0, import_core.renderToSvg)(doc);
122
+ return `<div class="${opts.containerClass}">${svg}</div>`;
123
+ }
124
+ case "svg-img":
125
+ default: {
126
+ const { svg } = (0, import_core.renderToSvg)(doc);
127
+ const base64 = typeof Buffer !== "undefined" ? Buffer.from(svg).toString("base64") : btoa(svg);
128
+ return `
129
+ <div class="${opts.containerClass}">
130
+ <img src="data:image/svg+xml;base64,${base64}" alt="Wireframe" />
131
+ </div>
132
+ `.trim();
133
+ }
134
+ }
135
+ } catch (error) {
136
+ return renderError(code, error, opts);
137
+ }
138
+ }
139
+ function renderError(code, error, options) {
140
+ const errorHtml = `<pre class="wireframe-error">${escapeHtml2(error.message)}</pre>`;
141
+ const codeHtml = `<pre class="wireframe-source"><code>${escapeHtml2(code)}</code></pre>`;
142
+ switch (options.errorHandling) {
143
+ case "code":
144
+ return codeHtml;
145
+ case "error":
146
+ return errorHtml;
147
+ case "both":
148
+ default:
149
+ return `<div class="${options.containerClass} wireframe-error-container">${errorHtml}${codeHtml}</div>`;
150
+ }
151
+ }
152
+ function escapeHtml2(text) {
153
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
154
+ }
155
+ // Annotate the CommonJS export names for ESM import in node:
156
+ 0 && (module.exports = {
157
+ markdownItWireframe,
158
+ markedWireframe,
159
+ remarkableWireframe,
160
+ renderWireframe
161
+ });
162
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/markdown-it.ts","../src/marked.ts","../src/remarkable.ts"],"sourcesContent":["/**\n * @wireweave/markdown-plugin\n *\n * Markdown plugins for wireweave\n */\n\nimport {\n parse,\n render,\n renderToSvg,\n resolveViewport,\n wrapInPreviewContainer,\n} from '@wireweave/core';\n\nexport interface WireframePluginOptions {\n /**\n * Output format\n * - 'html': HTML/CSS rendering (inline styles)\n * - 'html-preview': HTML with preview container (supports scaling)\n * - 'svg': SVG image\n * - 'svg-img': base64 encoded img tag\n */\n format?: 'html' | 'html-preview' | 'svg' | 'svg-img';\n\n /**\n * Theme for rendering\n * - 'light': Light theme\n * - 'dark': Dark theme\n */\n theme?: 'light' | 'dark';\n\n /**\n * Container class for wrapping SVG/HTML\n */\n containerClass?: string;\n\n /**\n * Error handling mode\n * - 'code': Show original code\n * - 'error': Show error message\n * - 'both': Show both\n */\n errorHandling?: 'code' | 'error' | 'both';\n\n /**\n * Container width for preview scaling (in pixels)\n * When set, the wireframe will be scaled to fit this width\n */\n containerWidth?: number;\n\n /**\n * Maximum scale factor (default: 1)\n * Prevents the preview from being scaled up beyond this value\n */\n maxScale?: number;\n}\n\nconst defaultOptions: Required<WireframePluginOptions> = {\n format: 'svg-img',\n theme: 'light',\n containerClass: 'wireframe-container',\n errorHandling: 'both',\n containerWidth: 0, // 0 means no scaling\n maxScale: 1,\n};\n\n/**\n * Render wireframe code to output format\n */\nexport function renderWireframe(\n code: string,\n options: WireframePluginOptions = {}\n): string {\n const opts = { ...defaultOptions, ...options };\n\n try {\n const doc = parse(code);\n\n switch (opts.format) {\n case 'html': {\n const { html, css } = render(doc, { theme: opts.theme });\n return `\n <div class=\"${opts.containerClass}\">\n <style>${css}</style>\n ${html}\n </div>\n `.trim();\n }\n\n case 'html-preview': {\n const { html, css } = render(doc, { theme: opts.theme });\n const firstPage = doc.children[0];\n const viewport = resolveViewport(firstPage?.viewport, firstPage?.device);\n\n const previewHtml = wrapInPreviewContainer(html, viewport, {\n darkMode: opts.theme === 'dark',\n containerWidth: opts.containerWidth > 0 ? opts.containerWidth : undefined,\n });\n\n return `\n <div class=\"${opts.containerClass}\">\n <style>${css}</style>\n ${previewHtml}\n </div>\n `.trim();\n }\n\n case 'svg': {\n const { svg } = renderToSvg(doc);\n return `<div class=\"${opts.containerClass}\">${svg}</div>`;\n }\n\n case 'svg-img':\n default: {\n const { svg } = renderToSvg(doc);\n // Use btoa for browser compatibility, Buffer for Node.js\n const base64 =\n typeof Buffer !== 'undefined'\n ? Buffer.from(svg).toString('base64')\n : btoa(svg);\n return `\n <div class=\"${opts.containerClass}\">\n <img src=\"data:image/svg+xml;base64,${base64}\" alt=\"Wireframe\" />\n </div>\n `.trim();\n }\n }\n } catch (error) {\n return renderError(code, error as Error, opts);\n }\n}\n\nfunction renderError(\n code: string,\n error: Error,\n options: Required<WireframePluginOptions>\n): string {\n const errorHtml = `<pre class=\"wireframe-error\">${escapeHtml(error.message)}</pre>`;\n const codeHtml = `<pre class=\"wireframe-source\"><code>${escapeHtml(code)}</code></pre>`;\n\n switch (options.errorHandling) {\n case 'code':\n return codeHtml;\n case 'error':\n return errorHtml;\n case 'both':\n default:\n return `<div class=\"${options.containerClass} wireframe-error-container\">${errorHtml}${codeHtml}</div>`;\n }\n}\n\nfunction escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#039;');\n}\n\nexport { markdownItWireframe } from './markdown-it';\nexport { markedWireframe } from './marked';\nexport { remarkableWireframe } from './remarkable';\n","/**\n * markdown-it plugin for wireweave\n */\n\nimport type MarkdownIt from 'markdown-it';\nimport { renderWireframe, WireframePluginOptions } from './index';\n\n/**\n * markdown-it plugin\n *\n * @example\n * ```typescript\n * import MarkdownIt from 'markdown-it';\n * import { markdownItWireframe } from '@wireweave/markdown-plugin/markdown-it';\n *\n * const md = new MarkdownIt();\n * md.use(markdownItWireframe, { format: 'svg' });\n *\n * const html = md.render('```wireframe\\npage { text \"Hello\" }\\n```');\n * ```\n */\nexport function markdownItWireframe(\n md: MarkdownIt,\n options: WireframePluginOptions = {}\n): void {\n const defaultFence = md.renderer.rules.fence;\n\n md.renderer.rules.fence = (tokens, idx, opts, env, self) => {\n const token = tokens[idx];\n const info = token.info.trim();\n\n if (info === 'wireframe' || info === 'wf') {\n return renderWireframe(token.content, options);\n }\n\n // Use default renderer for other code blocks\n if (defaultFence) {\n return defaultFence(tokens, idx, opts, env, self);\n }\n\n return `<pre><code class=\"language-${info}\">${md.utils.escapeHtml(token.content)}</code></pre>`;\n };\n}\n","/**\n * marked extension for wireweave\n */\n\nimport type { MarkedExtension, Tokens } from 'marked';\nimport { renderWireframe, WireframePluginOptions } from './index';\n\n/**\n * marked extension\n *\n * @example\n * ```typescript\n * import { marked } from 'marked';\n * import { markedWireframe } from '@wireweave/markdown-plugin/marked';\n *\n * marked.use(markedWireframe({ format: 'svg' }));\n *\n * const html = marked.parse('```wireframe\\npage { text \"Hello\" }\\n```');\n * ```\n */\nexport function markedWireframe(\n options: WireframePluginOptions = {}\n): MarkedExtension {\n return {\n renderer: {\n code(token: Tokens.Code): string | false {\n if (token.lang === 'wireframe' || token.lang === 'wf') {\n return renderWireframe(token.text, options);\n }\n return false; // Use default renderer\n },\n },\n };\n}\n","/**\n * remarkable plugin for wireweave\n */\n\nimport { renderWireframe, WireframePluginOptions } from './index';\n\n// Type declarations for remarkable (no @types/remarkable available)\ninterface RemarkableToken {\n type: string;\n params: string;\n content: string;\n}\n\ninterface RemarkableRenderer {\n rules: {\n fence: (\n tokens: RemarkableToken[],\n idx: number,\n options: Record<string, unknown>,\n env: Record<string, unknown>\n ) => string;\n };\n}\n\ninterface RemarkableUtils {\n escapeHtml: (text: string) => string;\n}\n\ninterface Remarkable {\n renderer: RemarkableRenderer;\n utils: RemarkableUtils;\n}\n\n/**\n * remarkable plugin\n *\n * @example\n * ```typescript\n * import { Remarkable } from 'remarkable';\n * import { remarkableWireframe } from '@wireweave/markdown-plugin/remarkable';\n *\n * const md = new Remarkable();\n * md.use(remarkableWireframe({ format: 'svg' }));\n *\n * const html = md.render('```wireframe\\npage { text \"Hello\" }\\n```');\n * ```\n */\n/**\n * Escape HTML entities\n */\nfunction escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;');\n}\n\nexport function remarkableWireframe(\n options: WireframePluginOptions = {}\n): (md: Remarkable) => void {\n return (md: Remarkable) => {\n const rules = md.renderer.rules;\n\n // Override fence rule completely\n rules.fence = (\n tokens: RemarkableToken[],\n idx: number,\n _opts: Record<string, unknown>,\n _env: Record<string, unknown>\n ): string => {\n const token = tokens[idx];\n const lang = token.params || '';\n\n if (lang === 'wireframe' || lang === 'wf') {\n return renderWireframe(token.content, options);\n }\n\n // Render other code blocks with syntax highlighting class\n const langClass = lang ? ` class=\"language-${escapeHtml(lang)}\"` : '';\n return `<pre><code${langClass}>${escapeHtml(token.content)}</code></pre>\\n`;\n };\n };\n}\n"],"mappings":"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","names":["escapeHtml"]}
@@ -0,0 +1,3 @@
1
+ export { W as WireframePluginOptions, markdownItWireframe, m as markedWireframe, r as remarkableWireframe, a as renderWireframe } from './markdown-it.cjs';
2
+ import 'markdown-it';
3
+ import 'marked';
@@ -0,0 +1,3 @@
1
+ export { W as WireframePluginOptions, markdownItWireframe, m as markedWireframe, r as remarkableWireframe, a as renderWireframe } from './markdown-it.js';
2
+ import 'markdown-it';
3
+ import 'marked';
package/dist/index.js ADDED
@@ -0,0 +1,140 @@
1
+ // src/index.ts
2
+ import {
3
+ parse,
4
+ render,
5
+ renderToSvg,
6
+ resolveViewport,
7
+ wrapInPreviewContainer
8
+ } from "@wireweave/core";
9
+
10
+ // src/markdown-it.ts
11
+ function markdownItWireframe(md, options = {}) {
12
+ const defaultFence = md.renderer.rules.fence;
13
+ md.renderer.rules.fence = (tokens, idx, opts, env, self) => {
14
+ const token = tokens[idx];
15
+ const info = token.info.trim();
16
+ if (info === "wireframe" || info === "wf") {
17
+ return renderWireframe(token.content, options);
18
+ }
19
+ if (defaultFence) {
20
+ return defaultFence(tokens, idx, opts, env, self);
21
+ }
22
+ return `<pre><code class="language-${info}">${md.utils.escapeHtml(token.content)}</code></pre>`;
23
+ };
24
+ }
25
+
26
+ // src/marked.ts
27
+ function markedWireframe(options = {}) {
28
+ return {
29
+ renderer: {
30
+ code(token) {
31
+ if (token.lang === "wireframe" || token.lang === "wf") {
32
+ return renderWireframe(token.text, options);
33
+ }
34
+ return false;
35
+ }
36
+ }
37
+ };
38
+ }
39
+
40
+ // src/remarkable.ts
41
+ function escapeHtml(text) {
42
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
43
+ }
44
+ function remarkableWireframe(options = {}) {
45
+ return (md) => {
46
+ const rules = md.renderer.rules;
47
+ rules.fence = (tokens, idx, _opts, _env) => {
48
+ const token = tokens[idx];
49
+ const lang = token.params || "";
50
+ if (lang === "wireframe" || lang === "wf") {
51
+ return renderWireframe(token.content, options);
52
+ }
53
+ const langClass = lang ? ` class="language-${escapeHtml(lang)}"` : "";
54
+ return `<pre><code${langClass}>${escapeHtml(token.content)}</code></pre>
55
+ `;
56
+ };
57
+ };
58
+ }
59
+
60
+ // src/index.ts
61
+ var defaultOptions = {
62
+ format: "svg-img",
63
+ theme: "light",
64
+ containerClass: "wireframe-container",
65
+ errorHandling: "both",
66
+ containerWidth: 0,
67
+ // 0 means no scaling
68
+ maxScale: 1
69
+ };
70
+ function renderWireframe(code, options = {}) {
71
+ const opts = { ...defaultOptions, ...options };
72
+ try {
73
+ const doc = parse(code);
74
+ switch (opts.format) {
75
+ case "html": {
76
+ const { html, css } = render(doc, { theme: opts.theme });
77
+ return `
78
+ <div class="${opts.containerClass}">
79
+ <style>${css}</style>
80
+ ${html}
81
+ </div>
82
+ `.trim();
83
+ }
84
+ case "html-preview": {
85
+ const { html, css } = render(doc, { theme: opts.theme });
86
+ const firstPage = doc.children[0];
87
+ const viewport = resolveViewport(firstPage?.viewport, firstPage?.device);
88
+ const previewHtml = wrapInPreviewContainer(html, viewport, {
89
+ darkMode: opts.theme === "dark",
90
+ containerWidth: opts.containerWidth > 0 ? opts.containerWidth : void 0
91
+ });
92
+ return `
93
+ <div class="${opts.containerClass}">
94
+ <style>${css}</style>
95
+ ${previewHtml}
96
+ </div>
97
+ `.trim();
98
+ }
99
+ case "svg": {
100
+ const { svg } = renderToSvg(doc);
101
+ return `<div class="${opts.containerClass}">${svg}</div>`;
102
+ }
103
+ case "svg-img":
104
+ default: {
105
+ const { svg } = renderToSvg(doc);
106
+ const base64 = typeof Buffer !== "undefined" ? Buffer.from(svg).toString("base64") : btoa(svg);
107
+ return `
108
+ <div class="${opts.containerClass}">
109
+ <img src="data:image/svg+xml;base64,${base64}" alt="Wireframe" />
110
+ </div>
111
+ `.trim();
112
+ }
113
+ }
114
+ } catch (error) {
115
+ return renderError(code, error, opts);
116
+ }
117
+ }
118
+ function renderError(code, error, options) {
119
+ const errorHtml = `<pre class="wireframe-error">${escapeHtml2(error.message)}</pre>`;
120
+ const codeHtml = `<pre class="wireframe-source"><code>${escapeHtml2(code)}</code></pre>`;
121
+ switch (options.errorHandling) {
122
+ case "code":
123
+ return codeHtml;
124
+ case "error":
125
+ return errorHtml;
126
+ case "both":
127
+ default:
128
+ return `<div class="${options.containerClass} wireframe-error-container">${errorHtml}${codeHtml}</div>`;
129
+ }
130
+ }
131
+ function escapeHtml2(text) {
132
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
133
+ }
134
+ export {
135
+ markdownItWireframe,
136
+ markedWireframe,
137
+ remarkableWireframe,
138
+ renderWireframe
139
+ };
140
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/markdown-it.ts","../src/marked.ts","../src/remarkable.ts"],"sourcesContent":["/**\n * @wireweave/markdown-plugin\n *\n * Markdown plugins for wireweave\n */\n\nimport {\n parse,\n render,\n renderToSvg,\n resolveViewport,\n wrapInPreviewContainer,\n} from '@wireweave/core';\n\nexport interface WireframePluginOptions {\n /**\n * Output format\n * - 'html': HTML/CSS rendering (inline styles)\n * - 'html-preview': HTML with preview container (supports scaling)\n * - 'svg': SVG image\n * - 'svg-img': base64 encoded img tag\n */\n format?: 'html' | 'html-preview' | 'svg' | 'svg-img';\n\n /**\n * Theme for rendering\n * - 'light': Light theme\n * - 'dark': Dark theme\n */\n theme?: 'light' | 'dark';\n\n /**\n * Container class for wrapping SVG/HTML\n */\n containerClass?: string;\n\n /**\n * Error handling mode\n * - 'code': Show original code\n * - 'error': Show error message\n * - 'both': Show both\n */\n errorHandling?: 'code' | 'error' | 'both';\n\n /**\n * Container width for preview scaling (in pixels)\n * When set, the wireframe will be scaled to fit this width\n */\n containerWidth?: number;\n\n /**\n * Maximum scale factor (default: 1)\n * Prevents the preview from being scaled up beyond this value\n */\n maxScale?: number;\n}\n\nconst defaultOptions: Required<WireframePluginOptions> = {\n format: 'svg-img',\n theme: 'light',\n containerClass: 'wireframe-container',\n errorHandling: 'both',\n containerWidth: 0, // 0 means no scaling\n maxScale: 1,\n};\n\n/**\n * Render wireframe code to output format\n */\nexport function renderWireframe(\n code: string,\n options: WireframePluginOptions = {}\n): string {\n const opts = { ...defaultOptions, ...options };\n\n try {\n const doc = parse(code);\n\n switch (opts.format) {\n case 'html': {\n const { html, css } = render(doc, { theme: opts.theme });\n return `\n <div class=\"${opts.containerClass}\">\n <style>${css}</style>\n ${html}\n </div>\n `.trim();\n }\n\n case 'html-preview': {\n const { html, css } = render(doc, { theme: opts.theme });\n const firstPage = doc.children[0];\n const viewport = resolveViewport(firstPage?.viewport, firstPage?.device);\n\n const previewHtml = wrapInPreviewContainer(html, viewport, {\n darkMode: opts.theme === 'dark',\n containerWidth: opts.containerWidth > 0 ? opts.containerWidth : undefined,\n });\n\n return `\n <div class=\"${opts.containerClass}\">\n <style>${css}</style>\n ${previewHtml}\n </div>\n `.trim();\n }\n\n case 'svg': {\n const { svg } = renderToSvg(doc);\n return `<div class=\"${opts.containerClass}\">${svg}</div>`;\n }\n\n case 'svg-img':\n default: {\n const { svg } = renderToSvg(doc);\n // Use btoa for browser compatibility, Buffer for Node.js\n const base64 =\n typeof Buffer !== 'undefined'\n ? Buffer.from(svg).toString('base64')\n : btoa(svg);\n return `\n <div class=\"${opts.containerClass}\">\n <img src=\"data:image/svg+xml;base64,${base64}\" alt=\"Wireframe\" />\n </div>\n `.trim();\n }\n }\n } catch (error) {\n return renderError(code, error as Error, opts);\n }\n}\n\nfunction renderError(\n code: string,\n error: Error,\n options: Required<WireframePluginOptions>\n): string {\n const errorHtml = `<pre class=\"wireframe-error\">${escapeHtml(error.message)}</pre>`;\n const codeHtml = `<pre class=\"wireframe-source\"><code>${escapeHtml(code)}</code></pre>`;\n\n switch (options.errorHandling) {\n case 'code':\n return codeHtml;\n case 'error':\n return errorHtml;\n case 'both':\n default:\n return `<div class=\"${options.containerClass} wireframe-error-container\">${errorHtml}${codeHtml}</div>`;\n }\n}\n\nfunction escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#039;');\n}\n\nexport { markdownItWireframe } from './markdown-it';\nexport { markedWireframe } from './marked';\nexport { remarkableWireframe } from './remarkable';\n","/**\n * markdown-it plugin for wireweave\n */\n\nimport type MarkdownIt from 'markdown-it';\nimport { renderWireframe, WireframePluginOptions } from './index';\n\n/**\n * markdown-it plugin\n *\n * @example\n * ```typescript\n * import MarkdownIt from 'markdown-it';\n * import { markdownItWireframe } from '@wireweave/markdown-plugin/markdown-it';\n *\n * const md = new MarkdownIt();\n * md.use(markdownItWireframe, { format: 'svg' });\n *\n * const html = md.render('```wireframe\\npage { text \"Hello\" }\\n```');\n * ```\n */\nexport function markdownItWireframe(\n md: MarkdownIt,\n options: WireframePluginOptions = {}\n): void {\n const defaultFence = md.renderer.rules.fence;\n\n md.renderer.rules.fence = (tokens, idx, opts, env, self) => {\n const token = tokens[idx];\n const info = token.info.trim();\n\n if (info === 'wireframe' || info === 'wf') {\n return renderWireframe(token.content, options);\n }\n\n // Use default renderer for other code blocks\n if (defaultFence) {\n return defaultFence(tokens, idx, opts, env, self);\n }\n\n return `<pre><code class=\"language-${info}\">${md.utils.escapeHtml(token.content)}</code></pre>`;\n };\n}\n","/**\n * marked extension for wireweave\n */\n\nimport type { MarkedExtension, Tokens } from 'marked';\nimport { renderWireframe, WireframePluginOptions } from './index';\n\n/**\n * marked extension\n *\n * @example\n * ```typescript\n * import { marked } from 'marked';\n * import { markedWireframe } from '@wireweave/markdown-plugin/marked';\n *\n * marked.use(markedWireframe({ format: 'svg' }));\n *\n * const html = marked.parse('```wireframe\\npage { text \"Hello\" }\\n```');\n * ```\n */\nexport function markedWireframe(\n options: WireframePluginOptions = {}\n): MarkedExtension {\n return {\n renderer: {\n code(token: Tokens.Code): string | false {\n if (token.lang === 'wireframe' || token.lang === 'wf') {\n return renderWireframe(token.text, options);\n }\n return false; // Use default renderer\n },\n },\n };\n}\n","/**\n * remarkable plugin for wireweave\n */\n\nimport { renderWireframe, WireframePluginOptions } from './index';\n\n// Type declarations for remarkable (no @types/remarkable available)\ninterface RemarkableToken {\n type: string;\n params: string;\n content: string;\n}\n\ninterface RemarkableRenderer {\n rules: {\n fence: (\n tokens: RemarkableToken[],\n idx: number,\n options: Record<string, unknown>,\n env: Record<string, unknown>\n ) => string;\n };\n}\n\ninterface RemarkableUtils {\n escapeHtml: (text: string) => string;\n}\n\ninterface Remarkable {\n renderer: RemarkableRenderer;\n utils: RemarkableUtils;\n}\n\n/**\n * remarkable plugin\n *\n * @example\n * ```typescript\n * import { Remarkable } from 'remarkable';\n * import { remarkableWireframe } from '@wireweave/markdown-plugin/remarkable';\n *\n * const md = new Remarkable();\n * md.use(remarkableWireframe({ format: 'svg' }));\n *\n * const html = md.render('```wireframe\\npage { text \"Hello\" }\\n```');\n * ```\n */\n/**\n * Escape HTML entities\n */\nfunction escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;');\n}\n\nexport function remarkableWireframe(\n options: WireframePluginOptions = {}\n): (md: Remarkable) => void {\n return (md: Remarkable) => {\n const rules = md.renderer.rules;\n\n // Override fence rule completely\n rules.fence = (\n tokens: RemarkableToken[],\n idx: number,\n _opts: Record<string, unknown>,\n _env: Record<string, unknown>\n ): string => {\n const token = tokens[idx];\n const lang = token.params || '';\n\n if (lang === 'wireframe' || lang === 'wf') {\n return renderWireframe(token.content, options);\n }\n\n // Render other code blocks with syntax highlighting class\n const langClass = lang ? ` class=\"language-${escapeHtml(lang)}\"` : '';\n return `<pre><code${langClass}>${escapeHtml(token.content)}</code></pre>\\n`;\n };\n };\n}\n"],"mappings":"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","names":["escapeHtml"]}