@wire-dsl/exporters 0.0.2

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/LICENSE ADDED
@@ -0,0 +1,36 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 WireDSL Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ ---
24
+
25
+ ## Third-Party Components & Assets
26
+
27
+ ### Feather Icons
28
+
29
+ This project includes icons from Feather Icons (https://feathericons.com), created by Cole Bemis and contributors.
30
+
31
+ - **License**: MIT License
32
+ - **Repository**: https://github.com/feathericons/feather
33
+ - **Location in project**: `packages/core/src/renderer/icons/`
34
+ - **Full details**: See `packages/core/src/renderer/icons/ICONS-LICENSE.md`
35
+
36
+ Feather Icons are used under the terms of the MIT License, which is fully compatible with this project's MIT License.
package/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # @wire-dsl/exporters
2
+
3
+ Node.js exporters for Wire-DSL. Provides file I/O functions to export wireframes as SVG, PNG, and PDF files. **Node.js only - depends on sharp, pdfkit.**
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @wire-dsl/exporters @wire-dsl/engine
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import { exportSVG, exportPNG, exportMultipagePDF } from '@wire-dsl/exporters';
15
+ import { parseWire, generateIR, computeLayout } from '@wire-dsl/engine';
16
+
17
+ // Parse and layout your wireframe
18
+ const ast = parseWire(wireCode);
19
+ const ir = generateIR(ast);
20
+ const layout = computeLayout(ir);
21
+
22
+ // Export to file
23
+ await exportSVG(ir, layout, 'output.svg');
24
+ await exportPNG(ir, layout, 'output.png');
25
+ await exportMultipagePDF(ir, layout, 'output.pdf');
26
+ ```
27
+
28
+ ## Functions
29
+
30
+ ### exportSVG(ir, layout, outputPath)
31
+ Export wireframe as SVG file.
32
+
33
+ ```typescript
34
+ import { exportSVG } from '@wire-dsl/exporters';
35
+
36
+ await exportSVG(ir, layout, 'wireframe.svg');
37
+ // → wireframe.svg (scalable vector)
38
+ ```
39
+
40
+ ### exportPNG(ir, layout, outputPath)
41
+ Export wireframe as PNG image (uses sharp).
42
+
43
+ ```typescript
44
+ import { exportPNG } from '@wire-dsl/exporters';
45
+
46
+ await exportPNG(ir, layout, 'wireframe.png');
47
+ // → wireframe.png (1920x1080 PNG)
48
+ ```
49
+
50
+ ### exportMultipagePDF(ir, layout, outputPath)
51
+ Export all screens as multipage PDF document (uses pdfkit).
52
+
53
+ ```typescript
54
+ import { exportMultipagePDF } from '@wire-dsl/exporters';
55
+
56
+ await exportMultipagePDF(ir, layout, 'wireframe.pdf');
57
+ // → wireframe.pdf (one page per screen)
58
+ ```
59
+
60
+ ## Dependencies
61
+
62
+ - `@wire-dsl/engine` - Core parsing and layout
63
+ - `pdfkit` - PDF file generation
64
+ - `sharp` - PNG image processing (native bindings)
65
+ - `svg-to-pdfkit` - SVG to PDF rendering
66
+
67
+ ## Configuration
68
+
69
+ All export functions use sensible defaults:
70
+
71
+ - **SVG**: Preserve colors, no optimization
72
+ - **PNG**: 1920x1080, 72 DPI (web standard)
73
+ - **PDF**: A4 size, embedded fonts, multipage
74
+
75
+ ## License
76
+
77
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ exportMultipagePDF: () => exportMultipagePDF,
34
+ exportPNG: () => exportPNG,
35
+ exportSVG: () => exportSVG,
36
+ extractSVGDimensions: () => extractSVGDimensions,
37
+ hexToRgba: () => hexToRgba,
38
+ preprocessSVGColors: () => preprocessSVGColors,
39
+ version: () => version
40
+ });
41
+ module.exports = __toCommonJS(index_exports);
42
+
43
+ // src/svg.ts
44
+ var import_promises = require("fs/promises");
45
+ async function exportSVG(svg, outputPath) {
46
+ const path2 = require("path");
47
+ const outputDir = path2.dirname(outputPath);
48
+ await (0, import_promises.mkdir)(outputDir, { recursive: true }).catch(() => {
49
+ });
50
+ await (0, import_promises.writeFile)(outputPath, svg, "utf8");
51
+ }
52
+
53
+ // src/png.ts
54
+ var import_sharp = __toESM(require("sharp"), 1);
55
+ async function exportPNG(svg, outputPath, width, height) {
56
+ const buffer = Buffer.from(svg);
57
+ let operation = (0, import_sharp.default)(buffer);
58
+ if (width && height) {
59
+ operation = operation.resize(width, height);
60
+ }
61
+ await operation.png().toFile(outputPath);
62
+ }
63
+
64
+ // src/pdf.ts
65
+ var import_promises2 = require("fs/promises");
66
+ var import_fs = require("fs");
67
+ var import_path = __toESM(require("path"), 1);
68
+ var import_pdfkit = __toESM(require("pdfkit"), 1);
69
+ var import_svg_to_pdfkit = __toESM(require("svg-to-pdfkit"), 1);
70
+
71
+ // src/helpers.ts
72
+ function extractSVGDimensions(svgString) {
73
+ const widthMatch = svgString.match(/width="(\d+(?:\.\d+)?)/);
74
+ const heightMatch = svgString.match(/height="(\d+(?:\.\d+)?)/);
75
+ return {
76
+ width: widthMatch ? parseFloat(widthMatch[1]) : 800,
77
+ height: heightMatch ? parseFloat(heightMatch[1]) : 600
78
+ };
79
+ }
80
+ function hexToRgba(hex) {
81
+ if (hex.length === 9) {
82
+ const r = parseInt(hex.slice(1, 3), 16);
83
+ const g = parseInt(hex.slice(3, 5), 16);
84
+ const b = parseInt(hex.slice(5, 7), 16);
85
+ const a = parseInt(hex.slice(7, 9), 16) / 255;
86
+ return `rgba(${r},${g},${b},${a.toFixed(2)})`;
87
+ }
88
+ return hex;
89
+ }
90
+ function preprocessSVGColors(svg) {
91
+ return svg.replace(/#[0-9A-Fa-f]{8}\b/g, (match) => hexToRgba(match));
92
+ }
93
+
94
+ // src/pdf.ts
95
+ async function exportMultipagePDF(svgs, outputPath) {
96
+ return new Promise(async (resolve, reject) => {
97
+ const outputDir = import_path.default.dirname(outputPath);
98
+ try {
99
+ await (0, import_promises2.mkdir)(outputDir, { recursive: true });
100
+ } catch (error) {
101
+ }
102
+ const pagesWithActualDimensions = svgs.map((page) => {
103
+ const processedSvg = preprocessSVGColors(page.svg);
104
+ const actualDims = extractSVGDimensions(processedSvg);
105
+ return {
106
+ ...page,
107
+ svg: processedSvg,
108
+ actualWidth: actualDims.width,
109
+ actualHeight: actualDims.height
110
+ };
111
+ });
112
+ const firstPage = pagesWithActualDimensions[0];
113
+ const doc = new import_pdfkit.default({
114
+ size: [firstPage.actualWidth, firstPage.actualHeight],
115
+ margin: 0
116
+ });
117
+ const stream = (0, import_fs.createWriteStream)(outputPath);
118
+ doc.pipe(stream);
119
+ pagesWithActualDimensions.forEach((page, index) => {
120
+ if (index > 0) {
121
+ doc.addPage({
122
+ size: [page.actualWidth, page.actualHeight],
123
+ margin: 0
124
+ });
125
+ }
126
+ try {
127
+ (0, import_svg_to_pdfkit.default)(doc, page.svg, 0, 0, {
128
+ width: page.actualWidth,
129
+ height: page.actualHeight,
130
+ assumePt: true
131
+ });
132
+ } catch (error) {
133
+ console.error(`Error rendering page ${page.name}:`, error);
134
+ }
135
+ });
136
+ doc.end();
137
+ stream.on("finish", () => resolve());
138
+ stream.on("error", (err) => reject(err));
139
+ });
140
+ }
141
+
142
+ // src/index.ts
143
+ var version = "0.1.6";
144
+ // Annotate the CommonJS export names for ESM import in node:
145
+ 0 && (module.exports = {
146
+ exportMultipagePDF,
147
+ exportPNG,
148
+ exportSVG,
149
+ extractSVGDimensions,
150
+ hexToRgba,
151
+ preprocessSVGColors,
152
+ version
153
+ });
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Save SVG string to file
3
+ * @param svg SVG string content
4
+ * @param outputPath Path where to save the file
5
+ */
6
+ declare function exportSVG(svg: string, outputPath: string): Promise<void>;
7
+
8
+ /**
9
+ * Export SVG to PNG using sharp
10
+ * @param svg SVG string content
11
+ * @param outputPath Path where to save the PNG file
12
+ * @param width Optional image width (defaults from SVG if not provided)
13
+ * @param height Optional image height (defaults from SVG if not provided)
14
+ */
15
+ declare function exportPNG(svg: string, outputPath: string, width?: number, height?: number): Promise<void>;
16
+
17
+ /**
18
+ * Export multiple SVGs as a single multipage PDF
19
+ * Each SVG becomes a page in the PDF with its own dimensions
20
+ * @param svgs Array of SVG objects with svg content, width, height, and name
21
+ * @param outputPath Path where to save the PDF file
22
+ */
23
+ declare function exportMultipagePDF(svgs: Array<{
24
+ svg: string;
25
+ width: number;
26
+ height: number;
27
+ name: string;
28
+ }>, outputPath: string): Promise<void>;
29
+
30
+ /**
31
+ * Helper functions for SVG and PDF processing
32
+ */
33
+ /**
34
+ * Extract actual width and height from rendered SVG string
35
+ * The SVG renderer may produce dynamic heights, so we extract actual dimensions
36
+ */
37
+ declare function extractSVGDimensions(svgString: string): {
38
+ width: number;
39
+ height: number;
40
+ };
41
+ /**
42
+ * Convert hex color with opacity (e.g., #3B82F615) to rgba format
43
+ * This helps svg-to-pdfkit render colors with transparency correctly
44
+ */
45
+ declare function hexToRgba(hex: string): string;
46
+ /**
47
+ * Preprocess SVG to convert hex colors with opacity to rgba format
48
+ * This ensures svg-to-pdfkit renders them correctly
49
+ */
50
+ declare function preprocessSVGColors(svg: string): string;
51
+
52
+ declare const version = "0.1.6";
53
+
54
+ export { exportMultipagePDF, exportPNG, exportSVG, extractSVGDimensions, hexToRgba, preprocessSVGColors, version };
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Save SVG string to file
3
+ * @param svg SVG string content
4
+ * @param outputPath Path where to save the file
5
+ */
6
+ declare function exportSVG(svg: string, outputPath: string): Promise<void>;
7
+
8
+ /**
9
+ * Export SVG to PNG using sharp
10
+ * @param svg SVG string content
11
+ * @param outputPath Path where to save the PNG file
12
+ * @param width Optional image width (defaults from SVG if not provided)
13
+ * @param height Optional image height (defaults from SVG if not provided)
14
+ */
15
+ declare function exportPNG(svg: string, outputPath: string, width?: number, height?: number): Promise<void>;
16
+
17
+ /**
18
+ * Export multiple SVGs as a single multipage PDF
19
+ * Each SVG becomes a page in the PDF with its own dimensions
20
+ * @param svgs Array of SVG objects with svg content, width, height, and name
21
+ * @param outputPath Path where to save the PDF file
22
+ */
23
+ declare function exportMultipagePDF(svgs: Array<{
24
+ svg: string;
25
+ width: number;
26
+ height: number;
27
+ name: string;
28
+ }>, outputPath: string): Promise<void>;
29
+
30
+ /**
31
+ * Helper functions for SVG and PDF processing
32
+ */
33
+ /**
34
+ * Extract actual width and height from rendered SVG string
35
+ * The SVG renderer may produce dynamic heights, so we extract actual dimensions
36
+ */
37
+ declare function extractSVGDimensions(svgString: string): {
38
+ width: number;
39
+ height: number;
40
+ };
41
+ /**
42
+ * Convert hex color with opacity (e.g., #3B82F615) to rgba format
43
+ * This helps svg-to-pdfkit render colors with transparency correctly
44
+ */
45
+ declare function hexToRgba(hex: string): string;
46
+ /**
47
+ * Preprocess SVG to convert hex colors with opacity to rgba format
48
+ * This ensures svg-to-pdfkit renders them correctly
49
+ */
50
+ declare function preprocessSVGColors(svg: string): string;
51
+
52
+ declare const version = "0.1.6";
53
+
54
+ export { exportMultipagePDF, exportPNG, exportSVG, extractSVGDimensions, hexToRgba, preprocessSVGColors, version };
package/dist/index.js ADDED
@@ -0,0 +1,117 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/svg.ts
9
+ import { writeFile, mkdir } from "fs/promises";
10
+ async function exportSVG(svg, outputPath) {
11
+ const path2 = __require("path");
12
+ const outputDir = path2.dirname(outputPath);
13
+ await mkdir(outputDir, { recursive: true }).catch(() => {
14
+ });
15
+ await writeFile(outputPath, svg, "utf8");
16
+ }
17
+
18
+ // src/png.ts
19
+ import sharp from "sharp";
20
+ async function exportPNG(svg, outputPath, width, height) {
21
+ const buffer = Buffer.from(svg);
22
+ let operation = sharp(buffer);
23
+ if (width && height) {
24
+ operation = operation.resize(width, height);
25
+ }
26
+ await operation.png().toFile(outputPath);
27
+ }
28
+
29
+ // src/pdf.ts
30
+ import { mkdir as mkdir2 } from "fs/promises";
31
+ import { createWriteStream } from "fs";
32
+ import path from "path";
33
+ import PDFDocument from "pdfkit";
34
+ import SVGtoPDF from "svg-to-pdfkit";
35
+
36
+ // src/helpers.ts
37
+ function extractSVGDimensions(svgString) {
38
+ const widthMatch = svgString.match(/width="(\d+(?:\.\d+)?)/);
39
+ const heightMatch = svgString.match(/height="(\d+(?:\.\d+)?)/);
40
+ return {
41
+ width: widthMatch ? parseFloat(widthMatch[1]) : 800,
42
+ height: heightMatch ? parseFloat(heightMatch[1]) : 600
43
+ };
44
+ }
45
+ function hexToRgba(hex) {
46
+ if (hex.length === 9) {
47
+ const r = parseInt(hex.slice(1, 3), 16);
48
+ const g = parseInt(hex.slice(3, 5), 16);
49
+ const b = parseInt(hex.slice(5, 7), 16);
50
+ const a = parseInt(hex.slice(7, 9), 16) / 255;
51
+ return `rgba(${r},${g},${b},${a.toFixed(2)})`;
52
+ }
53
+ return hex;
54
+ }
55
+ function preprocessSVGColors(svg) {
56
+ return svg.replace(/#[0-9A-Fa-f]{8}\b/g, (match) => hexToRgba(match));
57
+ }
58
+
59
+ // src/pdf.ts
60
+ async function exportMultipagePDF(svgs, outputPath) {
61
+ return new Promise(async (resolve, reject) => {
62
+ const outputDir = path.dirname(outputPath);
63
+ try {
64
+ await mkdir2(outputDir, { recursive: true });
65
+ } catch (error) {
66
+ }
67
+ const pagesWithActualDimensions = svgs.map((page) => {
68
+ const processedSvg = preprocessSVGColors(page.svg);
69
+ const actualDims = extractSVGDimensions(processedSvg);
70
+ return {
71
+ ...page,
72
+ svg: processedSvg,
73
+ actualWidth: actualDims.width,
74
+ actualHeight: actualDims.height
75
+ };
76
+ });
77
+ const firstPage = pagesWithActualDimensions[0];
78
+ const doc = new PDFDocument({
79
+ size: [firstPage.actualWidth, firstPage.actualHeight],
80
+ margin: 0
81
+ });
82
+ const stream = createWriteStream(outputPath);
83
+ doc.pipe(stream);
84
+ pagesWithActualDimensions.forEach((page, index) => {
85
+ if (index > 0) {
86
+ doc.addPage({
87
+ size: [page.actualWidth, page.actualHeight],
88
+ margin: 0
89
+ });
90
+ }
91
+ try {
92
+ SVGtoPDF(doc, page.svg, 0, 0, {
93
+ width: page.actualWidth,
94
+ height: page.actualHeight,
95
+ assumePt: true
96
+ });
97
+ } catch (error) {
98
+ console.error(`Error rendering page ${page.name}:`, error);
99
+ }
100
+ });
101
+ doc.end();
102
+ stream.on("finish", () => resolve());
103
+ stream.on("error", (err) => reject(err));
104
+ });
105
+ }
106
+
107
+ // src/index.ts
108
+ var version = "0.1.6";
109
+ export {
110
+ exportMultipagePDF,
111
+ exportPNG,
112
+ exportSVG,
113
+ extractSVGDimensions,
114
+ hexToRgba,
115
+ preprocessSVGColors,
116
+ version
117
+ };
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@wire-dsl/exporters",
3
+ "version": "0.0.2",
4
+ "description": "WireDSL exporters - SVG, PNG, and PDF file export functions (Node.js only)",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./dist/index.d.ts",
9
+ "import": "./dist/index.js",
10
+ "require": "./dist/index.cjs"
11
+ }
12
+ },
13
+ "main": "./dist/index.cjs",
14
+ "module": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "keywords": [
20
+ "wireframe",
21
+ "dsl",
22
+ "export",
23
+ "svg",
24
+ "png",
25
+ "pdf",
26
+ "svg-to-pdf"
27
+ ],
28
+ "author": "WireDSL Contributors",
29
+ "license": "MIT",
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "dependencies": {
34
+ "pdfkit": "0.17.2",
35
+ "sharp": "0.34.5",
36
+ "svg-to-pdfkit": "0.1.8",
37
+ "@wire-dsl/engine": "0.0.2"
38
+ },
39
+ "devDependencies": {
40
+ "@types/node": "25.2.0",
41
+ "@typescript-eslint/eslint-plugin": "8.54.0",
42
+ "@typescript-eslint/parser": "8.54.0",
43
+ "eslint": "9.39.2",
44
+ "tsup": "8.5.1",
45
+ "typescript": "5.9.3",
46
+ "vitest": "4.0.18"
47
+ },
48
+ "engines": {
49
+ "node": ">=20.0.0"
50
+ },
51
+ "scripts": {
52
+ "dev": "tsup --watch",
53
+ "build": "tsup src/index.ts --format cjs,esm --dts",
54
+ "test": "vitest",
55
+ "test:watch": "vitest --watch",
56
+ "test:ui": "vitest --ui",
57
+ "type-check": "tsc --noEmit",
58
+ "lint": "eslint src --ext .ts",
59
+ "lint:fix": "eslint src --ext .ts --fix"
60
+ }
61
+ }