import { existsSync } from 'node:fs' import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises' import { tmpdir } from 'node:os' import { dirname, join, resolve } from 'node:path' import { fileURLToPath, pathToFileURL } from 'node:url' const root = resolve(dirname(fileURLToPath(import.meta.url)), '..') const pluginDist = resolve(root, 'packages/presets/vite-plugin/dist/index.js') function assert(condition, message) { if (!condition) { throw new Error(message) } } assert( existsSync(pluginDist), 'packages/presets/vite-plugin/dist/index.js is missing; run pnpm --filter @file-viewer/vite-plugin build first.' ) const plugin = await import(`${pathToFileURL(pluginDist).href}?t=${Date.now()}`) const { collectFileViewerRendererScanTokens, extractFileViewerRendererHintTokens, fileViewerRenderers, resolveFileViewerRendererSelection } = plugin const inlineTokens = extractFileViewerRendererHintTokens(` export const fileViewerFormats = ['pdf', 'docx', 'dwg'] const upload = '' // file-viewer-formats: typst zip xmind
`) for (const token of ['pdf', 'docx', 'dwg', 'xlsx', 'image', 'ppt', 'typst', 'zip', 'xmind', 'geo', 'eda']) { assert(inlineTokens.includes(token), `inline hint extraction missed ${token}`) } const tempRoot = await mkdtemp(join(tmpdir(), 'file-viewer-vite-scan-')) try { await mkdir(join(tempRoot, 'src'), { recursive: true }) await writeFile( join(tempRoot, 'src/App.vue'), [ '', '', '' ].join('\n') ) await writeFile( join(tempRoot, 'src/upload.ts'), [ "export const fileViewerFormats = ['eml', 'epub', 'geojson']", '// file-viewer-formats: gds oas parquet', '' ].join('\n') ) const scanTokens = collectFileViewerRendererScanTokens(tempRoot, true) for (const token of ['pdf', 'docx', 'dwf', 'step', 'xlsx', 'xmind', 'brep', 'cad', 'typst', 'eml', 'epub', 'geojson', 'gds', 'oas', 'parquet']) { assert(scanTokens.includes(token), `source scan missed ${token}`) } const selection = resolveFileViewerRendererSelection({ scan: true }, tempRoot) const packages = new Set(selection.renderers.map(renderer => renderer.packageName)) for (const packageName of [ '@file-viewer/renderer-pdf', '@file-viewer/renderer-word', '@file-viewer/renderer-spreadsheet', '@file-viewer/renderer-cad', '@file-viewer/renderer-3d', '@file-viewer/renderer-typst', '@file-viewer/renderer-mindmap', '@file-viewer/renderer-email', '@file-viewer/renderer-epub', '@file-viewer/renderer-geo', '@file-viewer/renderer-eda', '@file-viewer/renderer-data' ]) { assert(packages.has(packageName), `auto scan did not select ${packageName}`) } const officePresetSelection = resolveFileViewerRendererSelection( { preset: 'office', formats: ['dwg'] }, tempRoot ) assert( officePresetSelection.presetPackage === '@file-viewer/preset-office', 'office preset did not resolve to @file-viewer/preset-office' ) assert( officePresetSelection.packages.includes('@file-viewer/preset-office'), 'office preset package is missing from the renderer plan' ) assert( officePresetSelection.packages.includes('@file-viewer/renderer-cad'), 'office preset should allow additional explicit renderer packages' ) for (const rendererId of ['pdf', 'office-word-openxml', 'spreadsheet-openxml', 'cad']) { assert( officePresetSelection.rendererIds.includes(rendererId), `office preset selection missed renderer id ${rendererId}` ) } const officePlugin = fileViewerRenderers({ preset: 'office', formats: ['dwg'] }) await officePlugin.buildStart?.() const officeModuleId = officePlugin.resolveId?.('virtual:file-viewer-renderers') assert(typeof officeModuleId === 'string', 'office preset virtual module did not resolve') const officeVirtualCode = await officePlugin.load?.(officeModuleId) assert( officeVirtualCode.includes("@file-viewer/preset-office"), 'office preset virtual module must import @file-viewer/preset-office' ) assert( officeVirtualCode.includes("@file-viewer/renderer-cad"), 'office preset virtual module must import explicitly added CAD renderer' ) assert( !officeVirtualCode.includes("import { pdfRenderer"), 'office preset virtual module must not re-import renderer packages covered by the preset' ) assert( officeVirtualCode.includes('registerFileViewerAutoRendererPreset'), 'virtual module must register selected renderers for framework auto consumption' ) const officeHtmlTags = officePlugin.transformIndexHtml?.() assert( Array.isArray(officeHtmlTags) && officeHtmlTags.some(tag => tag?.children?.includes('virtual:file-viewer-renderers')), 'configured plugin should inject the virtual renderer module into Vite HTML' ) const manualOnlyPlugin = fileViewerRenderers({ preset: 'office', inject: false }) assert( manualOnlyPlugin.transformIndexHtml?.() === undefined, 'inject:false should keep the virtual renderer module manual-only' ) const strictRoot = await mkdtemp(join(tmpdir(), 'file-viewer-vite-strict-')) const previousCwd = process.cwd() try { const fakePdfRoot = join( strictRoot, 'node_modules/@file-viewer/preset-office/node_modules/@file-viewer/renderer-pdf/node_modules/pdfjs-dist' ) await mkdir(join(strictRoot, 'node_modules/@file-viewer/preset-office'), { recursive: true }) await mkdir(join(strictRoot, 'node_modules/@file-viewer/preset-office/node_modules/@file-viewer/renderer-pdf'), { recursive: true }) await mkdir(join(fakePdfRoot, 'legacy/build'), { recursive: true }) await mkdir(join(fakePdfRoot, 'cmaps'), { recursive: true }) await mkdir(join(fakePdfRoot, 'wasm'), { recursive: true }) await mkdir(join(fakePdfRoot, 'standard_fonts'), { recursive: true }) await writeFile(join(strictRoot, 'package.json'), '{"name":"strict-react-app","type":"module"}\n') await writeFile( join(strictRoot, 'node_modules/@file-viewer/preset-office/package.json'), '{"name":"@file-viewer/preset-office","version":"0.0.0","dependencies":{"@file-viewer/renderer-pdf":"0.0.0"}}\n' ) await writeFile( join(strictRoot, 'node_modules/@file-viewer/preset-office/node_modules/@file-viewer/renderer-pdf/package.json'), '{"name":"@file-viewer/renderer-pdf","version":"0.0.0","dependencies":{"pdfjs-dist":"0.0.0"}}\n' ) await writeFile(join(fakePdfRoot, 'package.json'), '{"name":"pdfjs-dist","version":"0.0.0"}\n') await writeFile(join(fakePdfRoot, 'legacy/build/pdf.worker.mjs'), 'export default null\n') await writeFile(join(fakePdfRoot, 'cmaps/LICENSE'), 'fake cmap\n') await writeFile(join(fakePdfRoot, 'wasm/pdf.wasm'), 'fake wasm\n') await writeFile(join(fakePdfRoot, 'standard_fonts/LICENSE'), 'fake font\n') process.chdir(strictRoot) const strictPlugin = fileViewerRenderers({ preset: 'office', copyAssets: { publicDir: 'public', mode: 'dev' } }) strictPlugin.config?.({ root: '.' }) strictPlugin.configResolved?.({ root: strictRoot, publicDir: join(strictRoot, 'public'), build: { outDir: join(strictRoot, 'dist') } }) await strictPlugin.buildStart?.() await strictPlugin.configureServer?.({}) for (const assetPath of [ 'vendor/pdf/pdf.worker.mjs', 'vendor/pdf/cmaps/LICENSE', 'vendor/pdf/wasm/pdf.wasm', 'vendor/pdf/standard_fonts/LICENSE' ]) { assert( existsSync(join(strictRoot, 'public', assetPath)), `strict preset dependency asset copy missed ${assetPath}` ) } } finally { process.chdir(previousCwd) await rm(strictRoot, { recursive: true, force: true }) } const autoPresetSelection = resolveFileViewerRendererSelection({ preset: 'auto' }, tempRoot) assert( autoPresetSelection.autoPresetPackages.length > 0, 'preset:auto should discover installed @file-viewer/preset-* packages' ) const autoPresetPlugin = fileViewerRenderers({ preset: 'auto' }) await autoPresetPlugin.buildStart?.() const autoPresetModuleId = autoPresetPlugin.resolveId?.('virtual:file-viewer-renderers') assert(typeof autoPresetModuleId === 'string', 'preset:auto virtual module did not resolve') const autoPresetVirtualCode = await autoPresetPlugin.load?.(autoPresetModuleId) assert(typeof autoPresetVirtualCode === 'string', 'preset:auto virtual module did not load') assert( autoPresetSelection.autoPresetPackages.some(packageName => autoPresetVirtualCode.includes(packageName) ), 'preset:auto virtual module should import discovered preset packages' ) } finally { await rm(tempRoot, { recursive: true, force: true }) } console.log('[vite-plugin-auto-scan] Verified source hint scanning and renderer selection.')