@cyber-dash-tech/revela 0.4.1 → 0.4.3
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/lib/pptx/export.ts +35 -22
- package/package.json +1 -1
package/lib/pptx/export.ts
CHANGED
|
@@ -17,13 +17,15 @@ import puppeteer, { type Browser, type Page } from "puppeteer-core"
|
|
|
17
17
|
import { DOMParser, XMLSerializer } from "@xmldom/xmldom"
|
|
18
18
|
import { unzipSync, zipSync, strFromU8, strToU8 } from "fflate"
|
|
19
19
|
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs"
|
|
20
|
+
import { createRequire } from "module"
|
|
20
21
|
import { basename, dirname, extname, join, posix as pathPosix, resolve } from "path"
|
|
21
22
|
import { randomBytes } from "crypto"
|
|
22
|
-
import {
|
|
23
|
+
import { pathToFileURL } from "url"
|
|
23
24
|
|
|
24
25
|
const CANVAS_W = 1920
|
|
25
26
|
const CANVAS_H = 1080
|
|
26
27
|
const PPT_REL_NS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
|
28
|
+
const requireFromExportModule = createRequire(import.meta.url)
|
|
27
29
|
|
|
28
30
|
const CHROME_PATHS = [
|
|
29
31
|
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
@@ -151,11 +153,35 @@ export function derivePptxPath(htmlFilePath: string): string {
|
|
|
151
153
|
return join(dir, `${name}.pptx`)
|
|
152
154
|
}
|
|
153
155
|
|
|
156
|
+
export function resolveDomToPptxBundlePath(): string {
|
|
157
|
+
const entryPath = requireFromExportModule.resolve("dom-to-pptx")
|
|
158
|
+
const bundlePath = join(dirname(entryPath), "dom-to-pptx.bundle.js")
|
|
159
|
+
|
|
160
|
+
if (!existsSync(bundlePath)) {
|
|
161
|
+
throw new Error(`dom-to-pptx browser bundle not found: ${bundlePath}`)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return bundlePath
|
|
165
|
+
}
|
|
166
|
+
|
|
154
167
|
function isLocalImageRef(ref: string): boolean {
|
|
155
168
|
const pathPart = ref.split(/[?#]/)[0]
|
|
156
169
|
return IMAGE_EXTS.has(extname(pathPart).toLowerCase())
|
|
157
170
|
}
|
|
158
171
|
|
|
172
|
+
export function extractImageAssetRefsForPptx(htmlContent: string): string[] {
|
|
173
|
+
const assetRefPattern = /\bsrc\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))|url\(\s*(?:"([^"]*)"|'([^']*)'|([^\s)]+))\s*\)/g
|
|
174
|
+
const refs = new Set<string>()
|
|
175
|
+
let match: RegExpExecArray | null
|
|
176
|
+
|
|
177
|
+
while ((match = assetRefPattern.exec(htmlContent)) !== null) {
|
|
178
|
+
const ref = match.slice(1).find((value): value is string => value !== undefined)
|
|
179
|
+
if (ref) refs.add(ref.trim())
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return Array.from(refs)
|
|
183
|
+
}
|
|
184
|
+
|
|
159
185
|
async function toDataUrlFromRef(ref: string, baseDir: string): Promise<string | null> {
|
|
160
186
|
if (!ref || ref.startsWith("data:") || ref.startsWith("blob:") || ref.startsWith("#")) {
|
|
161
187
|
return null
|
|
@@ -182,21 +208,15 @@ async function toDataUrlFromRef(ref: string, baseDir: string): Promise<string |
|
|
|
182
208
|
}
|
|
183
209
|
}
|
|
184
210
|
|
|
185
|
-
async function inlineImageAssets(htmlContent: string, htmlFilePath: string): Promise<string> {
|
|
211
|
+
export async function inlineImageAssets(htmlContent: string, htmlFilePath: string): Promise<string> {
|
|
186
212
|
const baseDir = dirname(resolve(htmlFilePath))
|
|
187
|
-
const
|
|
188
|
-
const refs = new Set<string>()
|
|
189
|
-
let match: RegExpExecArray | null
|
|
190
|
-
|
|
191
|
-
while ((match = urlPattern.exec(htmlContent)) !== null) {
|
|
192
|
-
refs.add(match[1])
|
|
193
|
-
}
|
|
213
|
+
const refs = extractImageAssetRefsForPptx(htmlContent)
|
|
194
214
|
|
|
195
|
-
if (refs.
|
|
215
|
+
if (refs.length === 0) return htmlContent
|
|
196
216
|
|
|
197
217
|
const replacements = new Map<string, string>()
|
|
198
218
|
await Promise.allSettled(
|
|
199
|
-
|
|
219
|
+
refs.map(async (ref) => {
|
|
200
220
|
const dataUrl = await toDataUrlFromRef(ref, baseDir)
|
|
201
221
|
if (dataUrl) replacements.set(ref, dataUrl)
|
|
202
222
|
})
|
|
@@ -211,13 +231,9 @@ async function inlineImageAssets(htmlContent: string, htmlFilePath: string): Pro
|
|
|
211
231
|
}
|
|
212
232
|
|
|
213
233
|
async function localizeExternalImages(htmlContent: string, tmpDir: string): Promise<LocalizeExternalImagesResult> {
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
while ((match = urlPattern.exec(htmlContent)) !== null) {
|
|
219
|
-
uniqueUrls.add(match[1])
|
|
220
|
-
}
|
|
234
|
+
const uniqueUrls = new Set(
|
|
235
|
+
extractImageAssetRefsForPptx(htmlContent).filter((ref) => ref.startsWith("http://") || ref.startsWith("https://"))
|
|
236
|
+
)
|
|
221
237
|
|
|
222
238
|
if (uniqueUrls.size === 0) {
|
|
223
239
|
return {
|
|
@@ -831,10 +847,7 @@ export async function exportToPptx(
|
|
|
831
847
|
): Promise<ExportPptxResult> {
|
|
832
848
|
const startMs = Date.now()
|
|
833
849
|
const abs = resolve(htmlFilePath)
|
|
834
|
-
const domToPptxBundlePath =
|
|
835
|
-
dirname(fileURLToPath(import.meta.url)),
|
|
836
|
-
"../../node_modules/dom-to-pptx/dist/dom-to-pptx.bundle.js"
|
|
837
|
-
)
|
|
850
|
+
const domToPptxBundlePath = resolveDomToPptxBundlePath()
|
|
838
851
|
|
|
839
852
|
if (!existsSync(abs)) {
|
|
840
853
|
throw new Error(`File not found: ${abs}`)
|