@ahmedrowaihi/pdf-forge-core 1.0.0 → 1.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/dist/browser/index.d.mts +19 -0
- package/dist/browser/index.d.mts.map +1 -1
- package/dist/browser/index.d.ts +19 -0
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/edge/index.d.mts +19 -0
- package/dist/edge/index.d.mts.map +1 -1
- package/dist/edge/index.d.ts +19 -0
- package/dist/edge/index.d.ts.map +1 -1
- package/dist/node/index.d.mts +19 -0
- package/dist/node/index.d.mts.map +1 -1
- package/dist/node/index.d.ts +19 -0
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +160 -3
- package/dist/node/index.mjs +158 -3
- package/dist/node/index.mjs.map +1 -1
- package/package.json +3 -2
package/dist/browser/index.d.mts
CHANGED
|
@@ -7,6 +7,25 @@ type Options = {
|
|
|
7
7
|
* @see {@link pretty}
|
|
8
8
|
*/
|
|
9
9
|
pretty?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Bundle static assets (fonts, images) as base64 data URIs in the HTML.
|
|
12
|
+
* When enabled, scans the specified static directory and embeds assets.
|
|
13
|
+
* Only available in Node.js environment.
|
|
14
|
+
*/
|
|
15
|
+
bundleAssets?: boolean | {
|
|
16
|
+
/**
|
|
17
|
+
* Path to the static directory containing assets (fonts, images, etc.)
|
|
18
|
+
* Can be absolute or relative to process.cwd()
|
|
19
|
+
*/
|
|
20
|
+
staticDir: string;
|
|
21
|
+
/**
|
|
22
|
+
* Optional fallback static directory for shared assets.
|
|
23
|
+
* If an asset is not found in staticDir, it will be looked up in fallbackStaticDir.
|
|
24
|
+
* Useful when multiple templates share common assets (fonts, logos, etc.)
|
|
25
|
+
* Can be absolute or relative to process.cwd()
|
|
26
|
+
*/
|
|
27
|
+
fallbackStaticDir?: string;
|
|
28
|
+
};
|
|
10
29
|
} & ({
|
|
11
30
|
/**
|
|
12
31
|
* @see {@link toPlainText}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/shared/options.ts","../../src/shared/utils/pretty.ts","../../src/shared/utils/to-plain-text.ts","../../src/browser/render.tsx"],"sourcesContent":[],"mappings":";;;;KAIY,OAAA;;;AAAZ;;;;AC0FA;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/shared/options.ts","../../src/shared/utils/pretty.ts","../../src/shared/utils/to-plain-text.ts","../../src/browser/render.tsx"],"sourcesContent":[],"mappings":";;;;KAIY,OAAA;;;AAAZ;;;;AC0FA;;;;ICxFa;AASb;;;;ICVa;;;;;;;;;;;;;;;;;;;;;;;;sBH2Ca;;;;cC8Cb,gCAAgC,cAAY;;;cCxF5C,oBAAoB;iBASjB,WAAA,yBAAoC;;;cCVvC,eAAsB,KAAA,CAAM,qBAAqB,YAAO"}
|
package/dist/browser/index.d.ts
CHANGED
|
@@ -7,6 +7,25 @@ type Options = {
|
|
|
7
7
|
* @see {@link pretty}
|
|
8
8
|
*/
|
|
9
9
|
pretty?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Bundle static assets (fonts, images) as base64 data URIs in the HTML.
|
|
12
|
+
* When enabled, scans the specified static directory and embeds assets.
|
|
13
|
+
* Only available in Node.js environment.
|
|
14
|
+
*/
|
|
15
|
+
bundleAssets?: boolean | {
|
|
16
|
+
/**
|
|
17
|
+
* Path to the static directory containing assets (fonts, images, etc.)
|
|
18
|
+
* Can be absolute or relative to process.cwd()
|
|
19
|
+
*/
|
|
20
|
+
staticDir: string;
|
|
21
|
+
/**
|
|
22
|
+
* Optional fallback static directory for shared assets.
|
|
23
|
+
* If an asset is not found in staticDir, it will be looked up in fallbackStaticDir.
|
|
24
|
+
* Useful when multiple templates share common assets (fonts, logos, etc.)
|
|
25
|
+
* Can be absolute or relative to process.cwd()
|
|
26
|
+
*/
|
|
27
|
+
fallbackStaticDir?: string;
|
|
28
|
+
};
|
|
10
29
|
} & ({
|
|
11
30
|
/**
|
|
12
31
|
* @see {@link toPlainText}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/shared/options.ts","../../src/shared/utils/pretty.ts","../../src/shared/utils/to-plain-text.ts","../../src/browser/render.tsx"],"sourcesContent":[],"mappings":";;;;KAIY,OAAA;;;AAAZ;;;;AC0FA;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/shared/options.ts","../../src/shared/utils/pretty.ts","../../src/shared/utils/to-plain-text.ts","../../src/browser/render.tsx"],"sourcesContent":[],"mappings":";;;;KAIY,OAAA;;;AAAZ;;;;AC0FA;;;;ICxFa;AASb;;;;ICVa;;;;;;;;;;;;;;;;;;;;;;;;sBH2Ca;;;;cC8Cb,gCAAgC,cAAY;;;cCxF5C,oBAAoB;iBASjB,WAAA,yBAAoC;;;cCVvC,eAAsB,KAAA,CAAM,qBAAqB,YAAO"}
|
package/dist/edge/index.d.mts
CHANGED
|
@@ -7,6 +7,25 @@ type Options = {
|
|
|
7
7
|
* @see {@link pretty}
|
|
8
8
|
*/
|
|
9
9
|
pretty?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Bundle static assets (fonts, images) as base64 data URIs in the HTML.
|
|
12
|
+
* When enabled, scans the specified static directory and embeds assets.
|
|
13
|
+
* Only available in Node.js environment.
|
|
14
|
+
*/
|
|
15
|
+
bundleAssets?: boolean | {
|
|
16
|
+
/**
|
|
17
|
+
* Path to the static directory containing assets (fonts, images, etc.)
|
|
18
|
+
* Can be absolute or relative to process.cwd()
|
|
19
|
+
*/
|
|
20
|
+
staticDir: string;
|
|
21
|
+
/**
|
|
22
|
+
* Optional fallback static directory for shared assets.
|
|
23
|
+
* If an asset is not found in staticDir, it will be looked up in fallbackStaticDir.
|
|
24
|
+
* Useful when multiple templates share common assets (fonts, logos, etc.)
|
|
25
|
+
* Can be absolute or relative to process.cwd()
|
|
26
|
+
*/
|
|
27
|
+
fallbackStaticDir?: string;
|
|
28
|
+
};
|
|
10
29
|
} & ({
|
|
11
30
|
/**
|
|
12
31
|
* @see {@link toPlainText}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/shared/options.ts","../../src/shared/utils/pretty.ts","../../src/shared/utils/to-plain-text.ts","../../src/edge/render.tsx"],"sourcesContent":[],"mappings":";;;;KAIY,OAAA;;;AAAZ;;;;AC0FA;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/shared/options.ts","../../src/shared/utils/pretty.ts","../../src/shared/utils/to-plain-text.ts","../../src/edge/render.tsx"],"sourcesContent":[],"mappings":";;;;KAIY,OAAA;;;AAAZ;;;;AC0FA;;;;ICxFa;AASb;;;;ICRa;;;;;;;;;;;;;;;;;;;;;;;;sBHyCa;;;;cC8Cb,gCAAgC,cAAY;;;cCxF5C,oBAAoB;iBASjB,WAAA,yBAAoC;;;cCRvC,kBACF,KAAA,CAAM,wBACL,YAAO"}
|
package/dist/edge/index.d.ts
CHANGED
|
@@ -7,6 +7,25 @@ type Options = {
|
|
|
7
7
|
* @see {@link pretty}
|
|
8
8
|
*/
|
|
9
9
|
pretty?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Bundle static assets (fonts, images) as base64 data URIs in the HTML.
|
|
12
|
+
* When enabled, scans the specified static directory and embeds assets.
|
|
13
|
+
* Only available in Node.js environment.
|
|
14
|
+
*/
|
|
15
|
+
bundleAssets?: boolean | {
|
|
16
|
+
/**
|
|
17
|
+
* Path to the static directory containing assets (fonts, images, etc.)
|
|
18
|
+
* Can be absolute or relative to process.cwd()
|
|
19
|
+
*/
|
|
20
|
+
staticDir: string;
|
|
21
|
+
/**
|
|
22
|
+
* Optional fallback static directory for shared assets.
|
|
23
|
+
* If an asset is not found in staticDir, it will be looked up in fallbackStaticDir.
|
|
24
|
+
* Useful when multiple templates share common assets (fonts, logos, etc.)
|
|
25
|
+
* Can be absolute or relative to process.cwd()
|
|
26
|
+
*/
|
|
27
|
+
fallbackStaticDir?: string;
|
|
28
|
+
};
|
|
10
29
|
} & ({
|
|
11
30
|
/**
|
|
12
31
|
* @see {@link toPlainText}
|
package/dist/edge/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/shared/options.ts","../../src/shared/utils/pretty.ts","../../src/shared/utils/to-plain-text.ts","../../src/edge/render.tsx"],"sourcesContent":[],"mappings":";;;;KAIY,OAAA;;;AAAZ;;;;AC0FA;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/shared/options.ts","../../src/shared/utils/pretty.ts","../../src/shared/utils/to-plain-text.ts","../../src/edge/render.tsx"],"sourcesContent":[],"mappings":";;;;KAIY,OAAA;;;AAAZ;;;;AC0FA;;;;ICxFa;AASb;;;;ICRa;;;;;;;;;;;;;;;;;;;;;;;;sBHyCa;;;;cC8Cb,gCAAgC,cAAY;;;cCxF5C,oBAAoB;iBASjB,WAAA,yBAAoC;;;cCRvC,kBACF,KAAA,CAAM,wBACL,YAAO"}
|
package/dist/node/index.d.mts
CHANGED
|
@@ -7,6 +7,25 @@ type Options = {
|
|
|
7
7
|
* @see {@link pretty}
|
|
8
8
|
*/
|
|
9
9
|
pretty?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Bundle static assets (fonts, images) as base64 data URIs in the HTML.
|
|
12
|
+
* When enabled, scans the specified static directory and embeds assets.
|
|
13
|
+
* Only available in Node.js environment.
|
|
14
|
+
*/
|
|
15
|
+
bundleAssets?: boolean | {
|
|
16
|
+
/**
|
|
17
|
+
* Path to the static directory containing assets (fonts, images, etc.)
|
|
18
|
+
* Can be absolute or relative to process.cwd()
|
|
19
|
+
*/
|
|
20
|
+
staticDir: string;
|
|
21
|
+
/**
|
|
22
|
+
* Optional fallback static directory for shared assets.
|
|
23
|
+
* If an asset is not found in staticDir, it will be looked up in fallbackStaticDir.
|
|
24
|
+
* Useful when multiple templates share common assets (fonts, logos, etc.)
|
|
25
|
+
* Can be absolute or relative to process.cwd()
|
|
26
|
+
*/
|
|
27
|
+
fallbackStaticDir?: string;
|
|
28
|
+
};
|
|
10
29
|
} & ({
|
|
11
30
|
/**
|
|
12
31
|
* @see {@link toPlainText}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/shared/options.ts","../../src/shared/utils/pretty.ts","../../src/shared/utils/to-plain-text.ts","../../src/node/render.tsx"],"sourcesContent":[],"mappings":";;;;KAIY,OAAA;;;AAAZ;;;;AC0FA;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/shared/options.ts","../../src/shared/utils/pretty.ts","../../src/shared/utils/to-plain-text.ts","../../src/node/render.tsx"],"sourcesContent":[],"mappings":";;;;KAIY,OAAA;;;AAAZ;;;;AC0FA;;;;ICxFa;AASb;;;;ICJa;;;;;;;;;;;;;;;;;;;;;;;;sBHqCa;;;;cC8Cb,gCAAgC,cAAY;;;cCxF5C,oBAAoB;iBASjB,WAAA,yBAAoC;;;cCJvC,eAAsB,KAAA,CAAM,qBAAqB,YAAO"}
|
package/dist/node/index.d.ts
CHANGED
|
@@ -7,6 +7,25 @@ type Options = {
|
|
|
7
7
|
* @see {@link pretty}
|
|
8
8
|
*/
|
|
9
9
|
pretty?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Bundle static assets (fonts, images) as base64 data URIs in the HTML.
|
|
12
|
+
* When enabled, scans the specified static directory and embeds assets.
|
|
13
|
+
* Only available in Node.js environment.
|
|
14
|
+
*/
|
|
15
|
+
bundleAssets?: boolean | {
|
|
16
|
+
/**
|
|
17
|
+
* Path to the static directory containing assets (fonts, images, etc.)
|
|
18
|
+
* Can be absolute or relative to process.cwd()
|
|
19
|
+
*/
|
|
20
|
+
staticDir: string;
|
|
21
|
+
/**
|
|
22
|
+
* Optional fallback static directory for shared assets.
|
|
23
|
+
* If an asset is not found in staticDir, it will be looked up in fallbackStaticDir.
|
|
24
|
+
* Useful when multiple templates share common assets (fonts, logos, etc.)
|
|
25
|
+
* Can be absolute or relative to process.cwd()
|
|
26
|
+
*/
|
|
27
|
+
fallbackStaticDir?: string;
|
|
28
|
+
};
|
|
10
29
|
} & ({
|
|
11
30
|
/**
|
|
12
31
|
* @see {@link toPlainText}
|
package/dist/node/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/shared/options.ts","../../src/shared/utils/pretty.ts","../../src/shared/utils/to-plain-text.ts","../../src/node/render.tsx"],"sourcesContent":[],"mappings":";;;;KAIY,OAAA;;;AAAZ;;;;AC0FA;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/shared/options.ts","../../src/shared/utils/pretty.ts","../../src/shared/utils/to-plain-text.ts","../../src/node/render.tsx"],"sourcesContent":[],"mappings":";;;;KAIY,OAAA;;;AAAZ;;;;AC0FA;;;;ICxFa;AASb;;;;ICJa;;;;;;;;;;;;;;;;;;;;;;;;sBHqCa;;;;cC8Cb,gCAAgC,cAAY;;;cCxF5C,oBAAoB;iBASjB,WAAA,yBAAoC;;;cCJvC,eAAsB,KAAA,CAAM,qBAAqB,YAAO"}
|
package/dist/node/index.js
CHANGED
|
@@ -27,8 +27,12 @@ let prettier_standalone = require("prettier/standalone");
|
|
|
27
27
|
prettier_standalone = __toESM(prettier_standalone);
|
|
28
28
|
let html_to_text = require("html-to-text");
|
|
29
29
|
html_to_text = __toESM(html_to_text);
|
|
30
|
+
let node_path = require("node:path");
|
|
31
|
+
node_path = __toESM(node_path);
|
|
30
32
|
let react = require("react");
|
|
31
33
|
react = __toESM(react);
|
|
34
|
+
let node_fs_promises = require("node:fs/promises");
|
|
35
|
+
node_fs_promises = __toESM(node_fs_promises);
|
|
32
36
|
let node_stream = require("node:stream");
|
|
33
37
|
node_stream = __toESM(node_stream);
|
|
34
38
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -62,9 +66,9 @@ function recursivelyMapDoc(doc, callback) {
|
|
|
62
66
|
const modifiedHtml = { ...prettier_plugins_html };
|
|
63
67
|
if (modifiedHtml.printers) {
|
|
64
68
|
const previousPrint = modifiedHtml.printers.html.print;
|
|
65
|
-
modifiedHtml.printers.html.print = (path, options, print, args) => {
|
|
66
|
-
const node = path.getNode();
|
|
67
|
-
const rawPrintingResult = previousPrint(path, options, print, args);
|
|
69
|
+
modifiedHtml.printers.html.print = (path$2, options, print, args) => {
|
|
70
|
+
const node = path$2.getNode();
|
|
71
|
+
const rawPrintingResult = previousPrint(path$2, options, print, args);
|
|
68
72
|
if (node.type === "ieConditionalComment") return recursivelyMapDoc(rawPrintingResult, (doc) => {
|
|
69
73
|
if (typeof doc === "object" && doc.type === "line") return doc.soft ? "" : " ";
|
|
70
74
|
return doc;
|
|
@@ -113,6 +117,149 @@ function toPlainText(html, options) {
|
|
|
113
117
|
});
|
|
114
118
|
}
|
|
115
119
|
|
|
120
|
+
//#endregion
|
|
121
|
+
//#region src/shared/utils/asset-registry.ts
|
|
122
|
+
const templateAssetCache = /* @__PURE__ */ new Map();
|
|
123
|
+
const sharedAssetCache = /* @__PURE__ */ new Map();
|
|
124
|
+
/**
|
|
125
|
+
* Recursively scan a directory and return all files with their relative paths
|
|
126
|
+
*/
|
|
127
|
+
async function scanDirectoryRecursive(dir, baseDir = dir) {
|
|
128
|
+
const files = /* @__PURE__ */ new Map();
|
|
129
|
+
try {
|
|
130
|
+
const entries = await node_fs_promises.default.readdir(dir, { withFileTypes: true });
|
|
131
|
+
for (const entry of entries) {
|
|
132
|
+
const fullPath = node_path.default.join(dir, entry.name);
|
|
133
|
+
const relativePath = node_path.default.relative(baseDir, fullPath);
|
|
134
|
+
if (entry.isDirectory()) {
|
|
135
|
+
const subFiles = await scanDirectoryRecursive(fullPath, baseDir);
|
|
136
|
+
for (const [relPath, absPath] of subFiles) files.set(relPath, absPath);
|
|
137
|
+
} else files.set(relativePath, fullPath);
|
|
138
|
+
}
|
|
139
|
+
} catch {
|
|
140
|
+
return files;
|
|
141
|
+
}
|
|
142
|
+
return files;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Load a file and convert it to base64 data URI
|
|
146
|
+
*/
|
|
147
|
+
async function loadAssetAsBase64(filePath, url) {
|
|
148
|
+
const stats = await node_fs_promises.default.stat(filePath);
|
|
149
|
+
const base64 = (await node_fs_promises.default.readFile(filePath)).toString("base64");
|
|
150
|
+
const ext = node_path.default.extname(url).toLowerCase();
|
|
151
|
+
return {
|
|
152
|
+
base64: `data:${{
|
|
153
|
+
".woff2": "font/woff2",
|
|
154
|
+
".woff": "font/woff",
|
|
155
|
+
".otf": "font/otf",
|
|
156
|
+
".ttf": "font/ttf",
|
|
157
|
+
".eot": "application/vnd.ms-fontobject",
|
|
158
|
+
".svg": "image/svg+xml",
|
|
159
|
+
".png": "image/png",
|
|
160
|
+
".jpg": "image/jpeg",
|
|
161
|
+
".jpeg": "image/jpeg",
|
|
162
|
+
".gif": "image/gif",
|
|
163
|
+
".webp": "image/webp"
|
|
164
|
+
}[ext] || "application/octet-stream"};base64,${base64}`,
|
|
165
|
+
mtime: stats.mtimeMs
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Get or build asset registry for a shared/fallback static directory
|
|
170
|
+
* This is cached separately and reused across all templates
|
|
171
|
+
*/
|
|
172
|
+
async function getSharedAssetRegistry(fallbackStaticDir) {
|
|
173
|
+
const cached = sharedAssetCache.get(fallbackStaticDir);
|
|
174
|
+
if (cached) return cached;
|
|
175
|
+
const assetMap = /* @__PURE__ */ new Map();
|
|
176
|
+
try {
|
|
177
|
+
await node_fs_promises.default.access(fallbackStaticDir);
|
|
178
|
+
const files = await scanDirectoryRecursive(fallbackStaticDir, fallbackStaticDir);
|
|
179
|
+
for (const [relativePath, absolutePath] of files) {
|
|
180
|
+
const url = `/${relativePath.replace(/\\/g, "/")}`;
|
|
181
|
+
const { base64, mtime } = await loadAssetAsBase64(absolutePath, url);
|
|
182
|
+
assetMap.set(url, {
|
|
183
|
+
base64,
|
|
184
|
+
mtime
|
|
185
|
+
});
|
|
186
|
+
if (url.startsWith("/")) assetMap.set(url.slice(1), {
|
|
187
|
+
base64,
|
|
188
|
+
mtime
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
} catch {}
|
|
192
|
+
sharedAssetCache.set(fallbackStaticDir, assetMap);
|
|
193
|
+
return assetMap;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Get or build asset registry for a static directory
|
|
197
|
+
*
|
|
198
|
+
* @param staticDir - Absolute path to the static directory
|
|
199
|
+
* @param fallbackStaticDir - Optional fallback static directory (lower priority)
|
|
200
|
+
* @returns Map of asset URLs to base64 data URIs
|
|
201
|
+
*/
|
|
202
|
+
async function getAssetRegistry(staticDir, fallbackStaticDir) {
|
|
203
|
+
const templateCached = templateAssetCache.get(staticDir);
|
|
204
|
+
let templateAssetMap;
|
|
205
|
+
if (templateCached) templateAssetMap = templateCached;
|
|
206
|
+
else {
|
|
207
|
+
templateAssetMap = /* @__PURE__ */ new Map();
|
|
208
|
+
try {
|
|
209
|
+
await node_fs_promises.default.access(staticDir);
|
|
210
|
+
const files = await scanDirectoryRecursive(staticDir, staticDir);
|
|
211
|
+
for (const [relativePath, absolutePath] of files) {
|
|
212
|
+
const url = `/${relativePath.replace(/\\/g, "/")}`;
|
|
213
|
+
const { base64, mtime } = await loadAssetAsBase64(absolutePath, url);
|
|
214
|
+
templateAssetMap.set(url, {
|
|
215
|
+
base64,
|
|
216
|
+
mtime
|
|
217
|
+
});
|
|
218
|
+
if (url.startsWith("/")) templateAssetMap.set(url.slice(1), {
|
|
219
|
+
base64,
|
|
220
|
+
mtime
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
} catch {}
|
|
224
|
+
templateAssetCache.set(staticDir, templateAssetMap);
|
|
225
|
+
}
|
|
226
|
+
const result = /* @__PURE__ */ new Map();
|
|
227
|
+
for (const [url, entry] of templateAssetMap) result.set(url, entry.base64);
|
|
228
|
+
if (fallbackStaticDir) {
|
|
229
|
+
const sharedAssetMap = await getSharedAssetRegistry(fallbackStaticDir);
|
|
230
|
+
for (const [url, entry] of sharedAssetMap) if (!result.has(url)) result.set(url, entry.base64);
|
|
231
|
+
}
|
|
232
|
+
return result;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Process HTML to replace relative asset URLs with base64 data URIs
|
|
236
|
+
*/
|
|
237
|
+
function embedAssetsInHtml(html, assetRegistry) {
|
|
238
|
+
const getBase64 = (url) => {
|
|
239
|
+
return assetRegistry.get(url) || assetRegistry.get(`/${url}`) || assetRegistry.get(url.slice(1));
|
|
240
|
+
};
|
|
241
|
+
const shouldSkip = (url) => {
|
|
242
|
+
return url.startsWith("data:") || url.startsWith("http://") || url.startsWith("https://") || url.startsWith("#") || url.startsWith("mailto:") || url.startsWith("tel:");
|
|
243
|
+
};
|
|
244
|
+
let processedHtml = html;
|
|
245
|
+
processedHtml = processedHtml.replace(/url\((['"]?)([^'")]+)\1\)/gi, (match, quote, url) => {
|
|
246
|
+
if (shouldSkip(url)) return match;
|
|
247
|
+
const base64 = getBase64(url);
|
|
248
|
+
return base64 ? `url(${quote}${base64}${quote})` : match;
|
|
249
|
+
});
|
|
250
|
+
processedHtml = processedHtml.replace(/src\s*=\s*(['"])([^'"]+)\1/gi, (match, quote, url) => {
|
|
251
|
+
if (shouldSkip(url)) return match;
|
|
252
|
+
const base64 = getBase64(url);
|
|
253
|
+
return base64 ? `src=${quote}${base64}${quote}` : match;
|
|
254
|
+
});
|
|
255
|
+
processedHtml = processedHtml.replace(/href\s*=\s*(['"])([^'"]+)\1/gi, (match, quote, url) => {
|
|
256
|
+
if (shouldSkip(url)) return match;
|
|
257
|
+
const base64 = getBase64(url);
|
|
258
|
+
return base64 ? `href=${quote}${base64}${quote}` : match;
|
|
259
|
+
});
|
|
260
|
+
return processedHtml;
|
|
261
|
+
}
|
|
262
|
+
|
|
116
263
|
//#endregion
|
|
117
264
|
//#region src/node/read-stream.ts
|
|
118
265
|
const readStream = async (stream) => {
|
|
@@ -175,6 +322,16 @@ const render = async (node, options) => {
|
|
|
175
322
|
});
|
|
176
323
|
});
|
|
177
324
|
if (options?.plainText) return toPlainText(html, options.htmlToTextOptions);
|
|
325
|
+
if (options?.bundleAssets) {
|
|
326
|
+
let staticDir;
|
|
327
|
+
let fallbackStaticDir;
|
|
328
|
+
if (typeof options.bundleAssets === "object") {
|
|
329
|
+
staticDir = options.bundleAssets.staticDir;
|
|
330
|
+
fallbackStaticDir = options.bundleAssets.fallbackStaticDir;
|
|
331
|
+
} else staticDir = node_path.default.join(process.cwd(), "static");
|
|
332
|
+
const assetRegistry = await getAssetRegistry(node_path.default.isAbsolute(staticDir) ? staticDir : node_path.default.join(process.cwd(), staticDir), fallbackStaticDir ? node_path.default.isAbsolute(fallbackStaticDir) ? fallbackStaticDir : node_path.default.join(process.cwd(), fallbackStaticDir) : void 0);
|
|
333
|
+
html = embedAssetsInHtml(html, assetRegistry);
|
|
334
|
+
}
|
|
178
335
|
const document = `<!DOCTYPE html>${html.replace(/<!DOCTYPE.*?>/, "")}`;
|
|
179
336
|
if (options?.pretty) return pretty(document);
|
|
180
337
|
return document;
|
package/dist/node/index.mjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import * as html from "prettier/plugins/html";
|
|
2
2
|
import { format } from "prettier/standalone";
|
|
3
3
|
import { convert } from "html-to-text";
|
|
4
|
+
import path from "node:path";
|
|
4
5
|
import { Suspense } from "react";
|
|
6
|
+
import fs from "node:fs/promises";
|
|
5
7
|
import { Writable } from "node:stream";
|
|
6
8
|
import { jsx } from "react/jsx-runtime";
|
|
7
9
|
|
|
@@ -33,9 +35,9 @@ function recursivelyMapDoc(doc, callback) {
|
|
|
33
35
|
const modifiedHtml = { ...html };
|
|
34
36
|
if (modifiedHtml.printers) {
|
|
35
37
|
const previousPrint = modifiedHtml.printers.html.print;
|
|
36
|
-
modifiedHtml.printers.html.print = (path, options, print, args) => {
|
|
37
|
-
const node = path.getNode();
|
|
38
|
-
const rawPrintingResult = previousPrint(path, options, print, args);
|
|
38
|
+
modifiedHtml.printers.html.print = (path$1, options, print, args) => {
|
|
39
|
+
const node = path$1.getNode();
|
|
40
|
+
const rawPrintingResult = previousPrint(path$1, options, print, args);
|
|
39
41
|
if (node.type === "ieConditionalComment") return recursivelyMapDoc(rawPrintingResult, (doc) => {
|
|
40
42
|
if (typeof doc === "object" && doc.type === "line") return doc.soft ? "" : " ";
|
|
41
43
|
return doc;
|
|
@@ -84,6 +86,149 @@ function toPlainText(html$1, options) {
|
|
|
84
86
|
});
|
|
85
87
|
}
|
|
86
88
|
|
|
89
|
+
//#endregion
|
|
90
|
+
//#region src/shared/utils/asset-registry.ts
|
|
91
|
+
const templateAssetCache = /* @__PURE__ */ new Map();
|
|
92
|
+
const sharedAssetCache = /* @__PURE__ */ new Map();
|
|
93
|
+
/**
|
|
94
|
+
* Recursively scan a directory and return all files with their relative paths
|
|
95
|
+
*/
|
|
96
|
+
async function scanDirectoryRecursive(dir, baseDir = dir) {
|
|
97
|
+
const files = /* @__PURE__ */ new Map();
|
|
98
|
+
try {
|
|
99
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
100
|
+
for (const entry of entries) {
|
|
101
|
+
const fullPath = path.join(dir, entry.name);
|
|
102
|
+
const relativePath = path.relative(baseDir, fullPath);
|
|
103
|
+
if (entry.isDirectory()) {
|
|
104
|
+
const subFiles = await scanDirectoryRecursive(fullPath, baseDir);
|
|
105
|
+
for (const [relPath, absPath] of subFiles) files.set(relPath, absPath);
|
|
106
|
+
} else files.set(relativePath, fullPath);
|
|
107
|
+
}
|
|
108
|
+
} catch {
|
|
109
|
+
return files;
|
|
110
|
+
}
|
|
111
|
+
return files;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Load a file and convert it to base64 data URI
|
|
115
|
+
*/
|
|
116
|
+
async function loadAssetAsBase64(filePath, url) {
|
|
117
|
+
const stats = await fs.stat(filePath);
|
|
118
|
+
const base64 = (await fs.readFile(filePath)).toString("base64");
|
|
119
|
+
const ext = path.extname(url).toLowerCase();
|
|
120
|
+
return {
|
|
121
|
+
base64: `data:${{
|
|
122
|
+
".woff2": "font/woff2",
|
|
123
|
+
".woff": "font/woff",
|
|
124
|
+
".otf": "font/otf",
|
|
125
|
+
".ttf": "font/ttf",
|
|
126
|
+
".eot": "application/vnd.ms-fontobject",
|
|
127
|
+
".svg": "image/svg+xml",
|
|
128
|
+
".png": "image/png",
|
|
129
|
+
".jpg": "image/jpeg",
|
|
130
|
+
".jpeg": "image/jpeg",
|
|
131
|
+
".gif": "image/gif",
|
|
132
|
+
".webp": "image/webp"
|
|
133
|
+
}[ext] || "application/octet-stream"};base64,${base64}`,
|
|
134
|
+
mtime: stats.mtimeMs
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Get or build asset registry for a shared/fallback static directory
|
|
139
|
+
* This is cached separately and reused across all templates
|
|
140
|
+
*/
|
|
141
|
+
async function getSharedAssetRegistry(fallbackStaticDir) {
|
|
142
|
+
const cached = sharedAssetCache.get(fallbackStaticDir);
|
|
143
|
+
if (cached) return cached;
|
|
144
|
+
const assetMap = /* @__PURE__ */ new Map();
|
|
145
|
+
try {
|
|
146
|
+
await fs.access(fallbackStaticDir);
|
|
147
|
+
const files = await scanDirectoryRecursive(fallbackStaticDir, fallbackStaticDir);
|
|
148
|
+
for (const [relativePath, absolutePath] of files) {
|
|
149
|
+
const url = `/${relativePath.replace(/\\/g, "/")}`;
|
|
150
|
+
const { base64, mtime } = await loadAssetAsBase64(absolutePath, url);
|
|
151
|
+
assetMap.set(url, {
|
|
152
|
+
base64,
|
|
153
|
+
mtime
|
|
154
|
+
});
|
|
155
|
+
if (url.startsWith("/")) assetMap.set(url.slice(1), {
|
|
156
|
+
base64,
|
|
157
|
+
mtime
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
} catch {}
|
|
161
|
+
sharedAssetCache.set(fallbackStaticDir, assetMap);
|
|
162
|
+
return assetMap;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Get or build asset registry for a static directory
|
|
166
|
+
*
|
|
167
|
+
* @param staticDir - Absolute path to the static directory
|
|
168
|
+
* @param fallbackStaticDir - Optional fallback static directory (lower priority)
|
|
169
|
+
* @returns Map of asset URLs to base64 data URIs
|
|
170
|
+
*/
|
|
171
|
+
async function getAssetRegistry(staticDir, fallbackStaticDir) {
|
|
172
|
+
const templateCached = templateAssetCache.get(staticDir);
|
|
173
|
+
let templateAssetMap;
|
|
174
|
+
if (templateCached) templateAssetMap = templateCached;
|
|
175
|
+
else {
|
|
176
|
+
templateAssetMap = /* @__PURE__ */ new Map();
|
|
177
|
+
try {
|
|
178
|
+
await fs.access(staticDir);
|
|
179
|
+
const files = await scanDirectoryRecursive(staticDir, staticDir);
|
|
180
|
+
for (const [relativePath, absolutePath] of files) {
|
|
181
|
+
const url = `/${relativePath.replace(/\\/g, "/")}`;
|
|
182
|
+
const { base64, mtime } = await loadAssetAsBase64(absolutePath, url);
|
|
183
|
+
templateAssetMap.set(url, {
|
|
184
|
+
base64,
|
|
185
|
+
mtime
|
|
186
|
+
});
|
|
187
|
+
if (url.startsWith("/")) templateAssetMap.set(url.slice(1), {
|
|
188
|
+
base64,
|
|
189
|
+
mtime
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
} catch {}
|
|
193
|
+
templateAssetCache.set(staticDir, templateAssetMap);
|
|
194
|
+
}
|
|
195
|
+
const result = /* @__PURE__ */ new Map();
|
|
196
|
+
for (const [url, entry] of templateAssetMap) result.set(url, entry.base64);
|
|
197
|
+
if (fallbackStaticDir) {
|
|
198
|
+
const sharedAssetMap = await getSharedAssetRegistry(fallbackStaticDir);
|
|
199
|
+
for (const [url, entry] of sharedAssetMap) if (!result.has(url)) result.set(url, entry.base64);
|
|
200
|
+
}
|
|
201
|
+
return result;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Process HTML to replace relative asset URLs with base64 data URIs
|
|
205
|
+
*/
|
|
206
|
+
function embedAssetsInHtml(html$1, assetRegistry) {
|
|
207
|
+
const getBase64 = (url) => {
|
|
208
|
+
return assetRegistry.get(url) || assetRegistry.get(`/${url}`) || assetRegistry.get(url.slice(1));
|
|
209
|
+
};
|
|
210
|
+
const shouldSkip = (url) => {
|
|
211
|
+
return url.startsWith("data:") || url.startsWith("http://") || url.startsWith("https://") || url.startsWith("#") || url.startsWith("mailto:") || url.startsWith("tel:");
|
|
212
|
+
};
|
|
213
|
+
let processedHtml = html$1;
|
|
214
|
+
processedHtml = processedHtml.replace(/url\((['"]?)([^'")]+)\1\)/gi, (match, quote, url) => {
|
|
215
|
+
if (shouldSkip(url)) return match;
|
|
216
|
+
const base64 = getBase64(url);
|
|
217
|
+
return base64 ? `url(${quote}${base64}${quote})` : match;
|
|
218
|
+
});
|
|
219
|
+
processedHtml = processedHtml.replace(/src\s*=\s*(['"])([^'"]+)\1/gi, (match, quote, url) => {
|
|
220
|
+
if (shouldSkip(url)) return match;
|
|
221
|
+
const base64 = getBase64(url);
|
|
222
|
+
return base64 ? `src=${quote}${base64}${quote}` : match;
|
|
223
|
+
});
|
|
224
|
+
processedHtml = processedHtml.replace(/href\s*=\s*(['"])([^'"]+)\1/gi, (match, quote, url) => {
|
|
225
|
+
if (shouldSkip(url)) return match;
|
|
226
|
+
const base64 = getBase64(url);
|
|
227
|
+
return base64 ? `href=${quote}${base64}${quote}` : match;
|
|
228
|
+
});
|
|
229
|
+
return processedHtml;
|
|
230
|
+
}
|
|
231
|
+
|
|
87
232
|
//#endregion
|
|
88
233
|
//#region src/node/read-stream.ts
|
|
89
234
|
const readStream = async (stream) => {
|
|
@@ -146,6 +291,16 @@ const render = async (node, options) => {
|
|
|
146
291
|
});
|
|
147
292
|
});
|
|
148
293
|
if (options?.plainText) return toPlainText(html$1, options.htmlToTextOptions);
|
|
294
|
+
if (options?.bundleAssets) {
|
|
295
|
+
let staticDir;
|
|
296
|
+
let fallbackStaticDir;
|
|
297
|
+
if (typeof options.bundleAssets === "object") {
|
|
298
|
+
staticDir = options.bundleAssets.staticDir;
|
|
299
|
+
fallbackStaticDir = options.bundleAssets.fallbackStaticDir;
|
|
300
|
+
} else staticDir = path.join(process.cwd(), "static");
|
|
301
|
+
const assetRegistry = await getAssetRegistry(path.isAbsolute(staticDir) ? staticDir : path.join(process.cwd(), staticDir), fallbackStaticDir ? path.isAbsolute(fallbackStaticDir) ? fallbackStaticDir : path.join(process.cwd(), fallbackStaticDir) : void 0);
|
|
302
|
+
html$1 = embedAssetsInHtml(html$1, assetRegistry);
|
|
303
|
+
}
|
|
149
304
|
const document = `<!DOCTYPE html>${html$1.replace(/<!DOCTYPE.*?>/, "")}`;
|
|
150
305
|
if (options?.pretty) return pretty(document);
|
|
151
306
|
return document;
|
package/dist/node/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["defaults: Options","plainTextSelectors: SelectorDefinition[]","html","html!: string","html"],"sources":["../../src/shared/utils/pretty.ts","../../src/shared/utils/to-plain-text.ts","../../src/node/read-stream.ts","../../src/node/render.tsx"],"sourcesContent":["import type { Options, Plugin } from 'prettier';\nimport type { builders } from 'prettier/doc';\nimport * as html from 'prettier/plugins/html';\nimport { format } from 'prettier/standalone';\n\ninterface HtmlNode {\n type: 'element' | 'text' | 'ieConditionalComment';\n name?: string;\n sourceSpan: {\n start: { file: unknown[]; offset: number; line: number; col: number };\n end: { file: unknown[]; offset: number; line: number; col: number };\n details: null;\n };\n parent?: HtmlNode;\n}\n\nfunction recursivelyMapDoc(\n doc: builders.Doc,\n callback: (innerDoc: string | builders.DocCommand) => builders.Doc,\n): builders.Doc {\n if (Array.isArray(doc)) {\n return doc.map((innerDoc) => recursivelyMapDoc(innerDoc, callback));\n }\n\n if (typeof doc === 'object') {\n if (doc.type === 'group') {\n return {\n ...doc,\n contents: recursivelyMapDoc(doc.contents, callback),\n expandedStates: recursivelyMapDoc(\n doc.expandedStates,\n callback,\n ) as builders.Doc[],\n };\n }\n\n if ('contents' in doc) {\n return {\n ...doc,\n contents: recursivelyMapDoc(doc.contents, callback),\n };\n }\n\n if ('parts' in doc) {\n return {\n ...doc,\n parts: recursivelyMapDoc(doc.parts, callback) as builders.Doc[],\n };\n }\n\n if (doc.type === 'if-break') {\n return {\n ...doc,\n breakContents: recursivelyMapDoc(doc.breakContents, callback),\n flatContents: recursivelyMapDoc(doc.flatContents, callback),\n };\n }\n }\n\n return callback(doc);\n}\n\nconst modifiedHtml = { ...html } as Plugin;\nif (modifiedHtml.printers) {\n const previousPrint = modifiedHtml.printers.html.print;\n modifiedHtml.printers.html.print = (path, options, print, args) => {\n const node = path.getNode() as HtmlNode;\n\n const rawPrintingResult = previousPrint(path, options, print, args);\n\n if (node.type === 'ieConditionalComment') {\n const printingResult = recursivelyMapDoc(rawPrintingResult, (doc) => {\n if (typeof doc === 'object' && doc.type === 'line') {\n return doc.soft ? '' : ' ';\n }\n\n return doc;\n });\n\n return printingResult;\n }\n\n return rawPrintingResult;\n };\n}\n\nconst defaults: Options = {\n endOfLine: 'lf',\n tabWidth: 2,\n plugins: [modifiedHtml],\n bracketSameLine: true,\n parser: 'html',\n};\n\nexport const pretty = (str: string, options: Options = {}) => {\n return format(str.replaceAll('\\0', ''), {\n ...defaults,\n ...options,\n });\n};\n","import {\n convert,\n type HtmlToTextOptions,\n type SelectorDefinition,\n} from 'html-to-text';\n\nexport const plainTextSelectors: SelectorDefinition[] = [\n { selector: 'img', format: 'skip' },\n { selector: '[data-skip-in-text=true]', format: 'skip' },\n {\n selector: 'a',\n options: { linkBrackets: false, hideLinkHrefIfSameAsText: true },\n },\n];\n\nexport function toPlainText(html: string, options?: HtmlToTextOptions) {\n return convert(html, {\n selectors: plainTextSelectors,\n wordwrap: false,\n ...options,\n });\n}\n","import { Writable } from 'node:stream';\nimport type {\n PipeableStream,\n ReactDOMServerReadableStream,\n} from 'react-dom/server.browser';\n\nexport const readStream = async (\n stream: PipeableStream | ReactDOMServerReadableStream,\n) => {\n let result = '';\n // Create a single TextDecoder instance to handle streaming properly\n // This fixes issues with multi-byte characters (e.g., CJK) being split across chunks\n const decoder = new TextDecoder('utf-8');\n\n if ('pipeTo' in stream) {\n // means it's a readable stream\n const writableStream = new WritableStream({\n write(chunk: BufferSource) {\n // Use stream: true to handle multi-byte characters split across chunks\n result += decoder.decode(chunk, { stream: true });\n },\n close() {\n // Flush any remaining bytes\n result += decoder.decode();\n },\n });\n await stream.pipeTo(writableStream);\n } else {\n const writable = new Writable({\n write(chunk: BufferSource, _encoding, callback) {\n // Use stream: true to handle multi-byte characters split across chunks\n result += decoder.decode(chunk, { stream: true });\n\n callback();\n },\n final(callback) {\n // Flush any remaining bytes\n result += decoder.decode();\n callback();\n },\n });\n stream.pipe(writable);\n\n await new Promise<void>((resolve, reject) => {\n writable.on('error', reject);\n writable.on('close', () => {\n resolve();\n });\n });\n }\n\n return result;\n};\n","import { Suspense } from 'react';\nimport type { Options } from '../shared/options';\nimport { pretty } from '../shared/utils/pretty';\nimport { toPlainText } from '../shared/utils/to-plain-text';\nimport { readStream } from './read-stream';\n\nexport const render = async (node: React.ReactNode, options?: Options) => {\n const suspendedElement = <Suspense>{node}</Suspense>;\n const reactDOMServer = await import('react-dom/server').then((m) => {\n if ('default' in m) {\n return m.default;\n }\n return m;\n });\n\n let html!: string;\n if (\n Object.hasOwn(reactDOMServer, 'renderToReadableStream') &&\n typeof WritableStream !== 'undefined'\n ) {\n html = await readStream(\n await reactDOMServer.renderToReadableStream(suspendedElement, {\n progressiveChunkSize: Number.POSITIVE_INFINITY,\n }),\n );\n } else {\n await new Promise<void>((resolve, reject) => {\n const stream = reactDOMServer.renderToPipeableStream(suspendedElement, {\n onAllReady() {\n void readStream(stream).then((dom) => {\n html = dom;\n resolve();\n });\n },\n onError(error) {\n reject(error as Error);\n },\n progressiveChunkSize: Number.POSITIVE_INFINITY,\n });\n });\n }\n\n if (options?.plainText) {\n return toPlainText(html, options.htmlToTextOptions);\n }\n\n const doctype = '<!DOCTYPE html>';\n\n const document = `${doctype}${html.replace(/<!DOCTYPE.*?>/, '')}`;\n\n if (options?.pretty) {\n return pretty(document);\n }\n\n return document;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["path","defaults: Options","plainTextSelectors: SelectorDefinition[]","html","templateAssetMap: Map<string, AssetCacheEntry>","html","html!: string","html","staticDir: string","fallbackStaticDir: string | undefined"],"sources":["../../src/shared/utils/pretty.ts","../../src/shared/utils/to-plain-text.ts","../../src/shared/utils/asset-registry.ts","../../src/node/read-stream.ts","../../src/node/render.tsx"],"sourcesContent":["import type { Options, Plugin } from 'prettier';\nimport type { builders } from 'prettier/doc';\nimport * as html from 'prettier/plugins/html';\nimport { format } from 'prettier/standalone';\n\ninterface HtmlNode {\n type: 'element' | 'text' | 'ieConditionalComment';\n name?: string;\n sourceSpan: {\n start: { file: unknown[]; offset: number; line: number; col: number };\n end: { file: unknown[]; offset: number; line: number; col: number };\n details: null;\n };\n parent?: HtmlNode;\n}\n\nfunction recursivelyMapDoc(\n doc: builders.Doc,\n callback: (innerDoc: string | builders.DocCommand) => builders.Doc,\n): builders.Doc {\n if (Array.isArray(doc)) {\n return doc.map((innerDoc) => recursivelyMapDoc(innerDoc, callback));\n }\n\n if (typeof doc === 'object') {\n if (doc.type === 'group') {\n return {\n ...doc,\n contents: recursivelyMapDoc(doc.contents, callback),\n expandedStates: recursivelyMapDoc(\n doc.expandedStates,\n callback,\n ) as builders.Doc[],\n };\n }\n\n if ('contents' in doc) {\n return {\n ...doc,\n contents: recursivelyMapDoc(doc.contents, callback),\n };\n }\n\n if ('parts' in doc) {\n return {\n ...doc,\n parts: recursivelyMapDoc(doc.parts, callback) as builders.Doc[],\n };\n }\n\n if (doc.type === 'if-break') {\n return {\n ...doc,\n breakContents: recursivelyMapDoc(doc.breakContents, callback),\n flatContents: recursivelyMapDoc(doc.flatContents, callback),\n };\n }\n }\n\n return callback(doc);\n}\n\nconst modifiedHtml = { ...html } as Plugin;\nif (modifiedHtml.printers) {\n const previousPrint = modifiedHtml.printers.html.print;\n modifiedHtml.printers.html.print = (path, options, print, args) => {\n const node = path.getNode() as HtmlNode;\n\n const rawPrintingResult = previousPrint(path, options, print, args);\n\n if (node.type === 'ieConditionalComment') {\n const printingResult = recursivelyMapDoc(rawPrintingResult, (doc) => {\n if (typeof doc === 'object' && doc.type === 'line') {\n return doc.soft ? '' : ' ';\n }\n\n return doc;\n });\n\n return printingResult;\n }\n\n return rawPrintingResult;\n };\n}\n\nconst defaults: Options = {\n endOfLine: 'lf',\n tabWidth: 2,\n plugins: [modifiedHtml],\n bracketSameLine: true,\n parser: 'html',\n};\n\nexport const pretty = (str: string, options: Options = {}) => {\n return format(str.replaceAll('\\0', ''), {\n ...defaults,\n ...options,\n });\n};\n","import {\n convert,\n type HtmlToTextOptions,\n type SelectorDefinition,\n} from 'html-to-text';\n\nexport const plainTextSelectors: SelectorDefinition[] = [\n { selector: 'img', format: 'skip' },\n { selector: '[data-skip-in-text=true]', format: 'skip' },\n {\n selector: 'a',\n options: { linkBrackets: false, hideLinkHrefIfSameAsText: true },\n },\n];\n\nexport function toPlainText(html: string, options?: HtmlToTextOptions) {\n return convert(html, {\n selectors: plainTextSelectors,\n wordwrap: false,\n ...options,\n });\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\n\n/**\n * Asset Registry - Embeds static assets (fonts, images) as base64 data URIs\n */\n\ninterface AssetCacheEntry {\n base64: string;\n mtime: number;\n}\n\n// Separate caches for template-specific and shared assets\nconst templateAssetCache = new Map<string, Map<string, AssetCacheEntry>>();\nconst sharedAssetCache = new Map<string, Map<string, AssetCacheEntry>>();\n\n/**\n * Recursively scan a directory and return all files with their relative paths\n */\nasync function scanDirectoryRecursive(\n dir: string,\n baseDir: string = dir,\n): Promise<Map<string, string>> {\n const files = new Map<string, string>();\n\n try {\n const entries = await fs.readdir(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n const relativePath = path.relative(baseDir, fullPath);\n\n if (entry.isDirectory()) {\n const subFiles = await scanDirectoryRecursive(fullPath, baseDir);\n for (const [relPath, absPath] of subFiles) {\n files.set(relPath, absPath);\n }\n } else {\n files.set(relativePath, fullPath);\n }\n }\n } catch {\n return files;\n }\n\n return files;\n}\n\n/**\n * Load a file and convert it to base64 data URI\n */\nasync function loadAssetAsBase64(\n filePath: string,\n url: string,\n): Promise<{ base64: string; mtime: number }> {\n const stats = await fs.stat(filePath);\n const buffer = await fs.readFile(filePath);\n const base64 = buffer.toString('base64');\n\n const ext = path.extname(url).toLowerCase();\n const mimeTypes: Record<string, string> = {\n '.woff2': 'font/woff2',\n '.woff': 'font/woff',\n '.otf': 'font/otf',\n '.ttf': 'font/ttf',\n '.eot': 'application/vnd.ms-fontobject',\n '.svg': 'image/svg+xml',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.webp': 'image/webp',\n };\n const mimeType = mimeTypes[ext] || 'application/octet-stream';\n\n const dataUri = `data:${mimeType};base64,${base64}`;\n\n return { base64: dataUri, mtime: stats.mtimeMs };\n}\n\n/**\n * Get or build asset registry for a shared/fallback static directory\n * This is cached separately and reused across all templates\n */\nasync function getSharedAssetRegistry(\n fallbackStaticDir: string,\n): Promise<Map<string, AssetCacheEntry>> {\n const cached = sharedAssetCache.get(fallbackStaticDir);\n if (cached) {\n return cached;\n }\n\n const assetMap = new Map<string, AssetCacheEntry>();\n\n try {\n await fs.access(fallbackStaticDir);\n const files = await scanDirectoryRecursive(\n fallbackStaticDir,\n fallbackStaticDir,\n );\n\n for (const [relativePath, absolutePath] of files) {\n const url = `/${relativePath.replace(/\\\\/g, '/')}`;\n const { base64, mtime } = await loadAssetAsBase64(absolutePath, url);\n\n assetMap.set(url, { base64, mtime });\n if (url.startsWith('/')) {\n assetMap.set(url.slice(1), { base64, mtime });\n }\n }\n } catch {}\n\n sharedAssetCache.set(fallbackStaticDir, assetMap);\n return assetMap;\n}\n\n/**\n * Get or build asset registry for a static directory\n *\n * @param staticDir - Absolute path to the static directory\n * @param fallbackStaticDir - Optional fallback static directory (lower priority)\n * @returns Map of asset URLs to base64 data URIs\n */\nexport async function getAssetRegistry(\n staticDir: string,\n fallbackStaticDir?: string,\n): Promise<Map<string, string>> {\n const templateCached = templateAssetCache.get(staticDir);\n let templateAssetMap: Map<string, AssetCacheEntry>;\n\n if (templateCached) {\n templateAssetMap = templateCached;\n } else {\n templateAssetMap = new Map<string, AssetCacheEntry>();\n\n try {\n await fs.access(staticDir);\n const files = await scanDirectoryRecursive(staticDir, staticDir);\n\n for (const [relativePath, absolutePath] of files) {\n const url = `/${relativePath.replace(/\\\\/g, '/')}`;\n const { base64, mtime } = await loadAssetAsBase64(absolutePath, url);\n\n templateAssetMap.set(url, { base64, mtime });\n if (url.startsWith('/')) {\n templateAssetMap.set(url.slice(1), { base64, mtime });\n }\n }\n } catch {}\n\n templateAssetCache.set(staticDir, templateAssetMap);\n }\n\n const result = new Map<string, string>();\n\n for (const [url, entry] of templateAssetMap) {\n result.set(url, entry.base64);\n }\n\n if (fallbackStaticDir) {\n const sharedAssetMap = await getSharedAssetRegistry(fallbackStaticDir);\n for (const [url, entry] of sharedAssetMap) {\n if (!result.has(url)) {\n result.set(url, entry.base64);\n }\n }\n }\n\n return result;\n}\n\n/**\n * Process HTML to replace relative asset URLs with base64 data URIs\n */\nexport function embedAssetsInHtml(\n html: string,\n assetRegistry: Map<string, string>,\n): string {\n const getBase64 = (url: string): string | undefined => {\n return (\n assetRegistry.get(url) ||\n assetRegistry.get(`/${url}`) ||\n assetRegistry.get(url.slice(1))\n );\n };\n\n const shouldSkip = (url: string): boolean => {\n return (\n url.startsWith('data:') ||\n url.startsWith('http://') ||\n url.startsWith('https://') ||\n url.startsWith('#') ||\n url.startsWith('mailto:') ||\n url.startsWith('tel:')\n );\n };\n\n let processedHtml = html;\n\n // Pattern 1: CSS url() - matches url('/fonts/...') or url(\"/fonts/...\")\n processedHtml = processedHtml.replace(\n /url\\((['\"]?)([^'\")]+)\\1\\)/gi,\n (match: string, quote: string, url: string) => {\n if (shouldSkip(url)) return match;\n const base64 = getBase64(url);\n return base64 ? `url(${quote}${base64}${quote})` : match;\n },\n );\n\n // Pattern 2: src attribute - matches src=\"/fonts/...\" or src='/fonts/...'\n processedHtml = processedHtml.replace(\n /src\\s*=\\s*(['\"])([^'\"]+)\\1/gi,\n (match: string, quote: string, url: string) => {\n if (shouldSkip(url)) return match;\n const base64 = getBase64(url);\n return base64 ? `src=${quote}${base64}${quote}` : match;\n },\n );\n\n // Pattern 3: href attribute - matches href=\"/fonts/...\" or href='/fonts/...'\n processedHtml = processedHtml.replace(\n /href\\s*=\\s*(['\"])([^'\"]+)\\1/gi,\n (match: string, quote: string, url: string) => {\n if (shouldSkip(url)) return match;\n const base64 = getBase64(url);\n return base64 ? `href=${quote}${base64}${quote}` : match;\n },\n );\n\n return processedHtml;\n}\n","import { Writable } from 'node:stream';\nimport type {\n PipeableStream,\n ReactDOMServerReadableStream,\n} from 'react-dom/server.browser';\n\nexport const readStream = async (\n stream: PipeableStream | ReactDOMServerReadableStream,\n) => {\n let result = '';\n // Create a single TextDecoder instance to handle streaming properly\n // This fixes issues with multi-byte characters (e.g., CJK) being split across chunks\n const decoder = new TextDecoder('utf-8');\n\n if ('pipeTo' in stream) {\n // means it's a readable stream\n const writableStream = new WritableStream({\n write(chunk: BufferSource) {\n // Use stream: true to handle multi-byte characters split across chunks\n result += decoder.decode(chunk, { stream: true });\n },\n close() {\n // Flush any remaining bytes\n result += decoder.decode();\n },\n });\n await stream.pipeTo(writableStream);\n } else {\n const writable = new Writable({\n write(chunk: BufferSource, _encoding, callback) {\n // Use stream: true to handle multi-byte characters split across chunks\n result += decoder.decode(chunk, { stream: true });\n\n callback();\n },\n final(callback) {\n // Flush any remaining bytes\n result += decoder.decode();\n callback();\n },\n });\n stream.pipe(writable);\n\n await new Promise<void>((resolve, reject) => {\n writable.on('error', reject);\n writable.on('close', () => {\n resolve();\n });\n });\n }\n\n return result;\n};\n","import path from 'node:path';\nimport { Suspense } from 'react';\nimport type { Options } from '../shared/options';\nimport {\n embedAssetsInHtml,\n getAssetRegistry,\n} from '../shared/utils/asset-registry';\nimport { pretty } from '../shared/utils/pretty';\nimport { toPlainText } from '../shared/utils/to-plain-text';\nimport { readStream } from './read-stream';\n\nexport const render = async (node: React.ReactNode, options?: Options) => {\n const suspendedElement = <Suspense>{node}</Suspense>;\n const reactDOMServer = await import('react-dom/server').then((m) => {\n if ('default' in m) {\n return m.default;\n }\n return m;\n });\n\n let html!: string;\n if (\n Object.hasOwn(reactDOMServer, 'renderToReadableStream') &&\n typeof WritableStream !== 'undefined'\n ) {\n html = await readStream(\n await reactDOMServer.renderToReadableStream(suspendedElement, {\n progressiveChunkSize: Number.POSITIVE_INFINITY,\n }),\n );\n } else {\n await new Promise<void>((resolve, reject) => {\n const stream = reactDOMServer.renderToPipeableStream(suspendedElement, {\n onAllReady() {\n void readStream(stream).then((dom) => {\n html = dom;\n resolve();\n });\n },\n onError(error) {\n reject(error as Error);\n },\n progressiveChunkSize: Number.POSITIVE_INFINITY,\n });\n });\n }\n\n if (options?.plainText) {\n return toPlainText(html, options.htmlToTextOptions);\n }\n\n if (options?.bundleAssets) {\n let staticDir: string;\n let fallbackStaticDir: string | undefined;\n\n if (typeof options.bundleAssets === 'object') {\n staticDir = options.bundleAssets.staticDir;\n fallbackStaticDir = options.bundleAssets.fallbackStaticDir;\n } else {\n staticDir = path.join(process.cwd(), 'static');\n }\n\n const absoluteStaticDir = path.isAbsolute(staticDir)\n ? staticDir\n : path.join(process.cwd(), staticDir);\n\n const absoluteFallbackStaticDir = fallbackStaticDir\n ? path.isAbsolute(fallbackStaticDir)\n ? fallbackStaticDir\n : path.join(process.cwd(), fallbackStaticDir)\n : undefined;\n\n const assetRegistry = await getAssetRegistry(\n absoluteStaticDir,\n absoluteFallbackStaticDir,\n );\n html = embedAssetsInHtml(html, assetRegistry);\n }\n\n const doctype = '<!DOCTYPE html>';\n\n const document = `${doctype}${html.replace(/<!DOCTYPE.*?>/, '')}`;\n\n if (options?.pretty) {\n return pretty(document);\n }\n\n return document;\n};\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ahmedrowaihi/pdf-forge-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Transform React components into HTML for PDF generation",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"main": "./dist/browser/index.js",
|
|
@@ -120,9 +120,10 @@
|
|
|
120
120
|
"@types/html-to-text": "9.0.4",
|
|
121
121
|
"@types/react": "npm:types-react@19.0.0-rc.1",
|
|
122
122
|
"@types/react-dom": "npm:types-react-dom@19.0.0",
|
|
123
|
+
"@types/node": "22.14.1",
|
|
123
124
|
"jsdom": "26.1.0",
|
|
124
125
|
"typescript": "5.8.3",
|
|
125
|
-
"tsconfig": "1.
|
|
126
|
+
"tsconfig": "1.1.0"
|
|
126
127
|
},
|
|
127
128
|
"publishConfig": {
|
|
128
129
|
"access": "public"
|