@lupinum/nuxt-pdf 0.4.0-beta.1 → 0.4.0-beta.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/API_REPORT.md +36 -0
- package/CHANGELOG.md +35 -0
- package/CONFORMANCE.md +18 -5
- package/dist/build.d.mts +18 -0
- package/dist/build.mjs +220 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +9 -218
- package/dist/runtime/fonts.d.ts +1 -1
- package/dist/runtime/renderer/index.d.ts +1 -0
- package/dist/runtime/renderer/index.js +1 -0
- package/dist/runtime/server/engine/fonts.js +1 -1
- package/dist/runtime/server/engine/render-document.d.ts +7 -0
- package/dist/runtime/server/engine/render-document.js +47 -0
- package/dist/runtime/server/index.d.ts +1 -1
- package/dist/runtime/server/preview.js +9 -1
- package/dist/runtime/server/registry.d.ts +1 -1
- package/dist/runtime/server/registry.js +9 -1
- package/dist/runtime/server/result.js +1 -0
- package/dist/runtime/shared/index.d.ts +1 -1
- package/dist/runtime/shared/template.d.ts +8 -0
- package/dist/server.d.mts +4 -0
- package/dist/server.mjs +3 -0
- package/dist/shared/nuxt-pdf.D3hUPqOJ.mjs +203 -0
- package/dist/shared/{nuxt-pdf._V584vX4.mjs → nuxt-pdf.DMC_Rdsz.mjs} +59 -10
- package/dist/test.mjs +1 -1
- package/package.json +17 -9
package/API_REPORT.md
CHANGED
|
@@ -260,3 +260,39 @@ declare function comparePdfSnapshot(input: PdfInput, baselineDir: string, option
|
|
|
260
260
|
export { PdfAssertionError, comparePdfSnapshot, expectPdf, loadPdfSfc, parsePdf, rasterizePdf, renderPdfSfc, renderPdfTemplate, toPdfBytes };
|
|
261
261
|
export type { ComparePdfSnapshotOptions, LinkQuery, OutlineShape, ParsedPdf, ParsedPdfLink, ParsedPdfPage, ParsedPdfTextRun, PdfExpectation, PdfInput, PdfOutlineItem, PdfPageImage, PdfSnapshotResult, RasterizePdfOptions, RenderPdfSfcOptions, RenderPdfTemplateOptions, RenderedPdfTemplate, ToContainTextOptions };
|
|
262
262
|
```
|
|
263
|
+
|
|
264
|
+
## Standalone build entry
|
|
265
|
+
|
|
266
|
+
Source: `dist/build.d.mts`
|
|
267
|
+
|
|
268
|
+
```ts
|
|
269
|
+
import { PdfFontDeclaration } from '../dist/runtime/fonts.js';
|
|
270
|
+
import { RemoteAssetOptions } from '../dist/runtime/server/assets/remote.js';
|
|
271
|
+
import { PdfLimitsOptions } from '../dist/runtime/server/render-limits.js';
|
|
272
|
+
|
|
273
|
+
interface BuildPdfRegistryOptions {
|
|
274
|
+
/** Trusted application root containing pdfs/. Not request input. */
|
|
275
|
+
rootDir: string;
|
|
276
|
+
/** Dedicated generated directory inside rootDir and outside pdfs/. */
|
|
277
|
+
outDir: string;
|
|
278
|
+
fonts?: readonly PdfFontDeclaration[];
|
|
279
|
+
limits?: PdfLimitsOptions;
|
|
280
|
+
remote?: RemoteAssetOptions;
|
|
281
|
+
}
|
|
282
|
+
/** Compile trusted templates and embed admitted resources before deployment. */
|
|
283
|
+
declare function buildPdfRegistry(options: BuildPdfRegistryOptions): Promise<void>;
|
|
284
|
+
|
|
285
|
+
export { buildPdfRegistry };
|
|
286
|
+
export type { BuildPdfRegistryOptions };
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Standalone server entry
|
|
290
|
+
|
|
291
|
+
Source: `dist/server.d.mts`
|
|
292
|
+
|
|
293
|
+
```ts
|
|
294
|
+
export { PdfRegistry, PdfRegistryEntries, createPdfRegistry, createPdfTemplate } from '../dist/runtime/server/registry.js';
|
|
295
|
+
export { NuxtPdfError, PDF_ERROR_CODES, PdfErrorCode } from '../dist/runtime/shared/errors.js';
|
|
296
|
+
export { usePdfPageNumbers } from '../dist/runtime/composables/index.js';
|
|
297
|
+
export { PdfComponentProps, PdfDefinition, PdfRenderResult, PdfTemplate } from '../dist/runtime/shared/template.js';
|
|
298
|
+
```
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,41 @@ All notable changes to `@lupinum/nuxt-pdf` are recorded here. The format follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project adheres
|
|
5
5
|
to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## 0.4.0-beta.3 - 2026-09-03
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Add a standalone registry build and Node production runtime entry. Reuse the
|
|
12
|
+
existing PDF compiler, embedded resource admission, and rendering engine.
|
|
13
|
+
- Emit backend-consumable TypeScript declarations without requiring Vue source
|
|
14
|
+
or a Vue type checker during backend compilation.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- Keep the registry documentation example compatible with strict Markdown style
|
|
19
|
+
validation and update vulnerable documentation parser dependencies.
|
|
20
|
+
- Prepare the package build export before clean-checkout type checking.
|
|
21
|
+
|
|
22
|
+
## 0.4.0-beta.2 - 2026-08-27
|
|
23
|
+
|
|
24
|
+
[compare changes](https://github.com/lupinum-dev/nuxt-pdf/compare/v0.4.0-beta.1...v0.4.0-beta.2)
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- **fonts:** Support WOFF2 assets ([ad50390](https://github.com/lupinum-dev/nuxt-pdf/commit/ad50390))
|
|
29
|
+
- **diagnostics:** Explain unbreakable layout overflow ([a5ff0b7](https://github.com/lupinum-dev/nuxt-pdf/commit/a5ff0b7))
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- **ci:** Harden on-demand Vercel reporting ([#35](https://github.com/lupinum-dev/nuxt-pdf/pull/35))
|
|
34
|
+
- **release:** Repair from certified source evidence ([#36](https://github.com/lupinum-dev/nuxt-pdf/pull/36))
|
|
35
|
+
- **release:** Separate publication from repair ([#37](https://github.com/lupinum-dev/nuxt-pdf/pull/37))
|
|
36
|
+
- **types:** Expose PDF authoring globals ([c427310](https://github.com/lupinum-dev/nuxt-pdf/commit/c427310))
|
|
37
|
+
|
|
38
|
+
### CI
|
|
39
|
+
|
|
40
|
+
- **vercel:** Cut library preview build usage ([#34](https://github.com/lupinum-dev/nuxt-pdf/pull/34))
|
|
41
|
+
|
|
7
42
|
## 0.4.0-beta.1 - 2026-08-22
|
|
8
43
|
|
|
9
44
|
### Added
|
package/CONFORMANCE.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
# Nuxt PDF 0.4.0-beta.
|
|
1
|
+
# Nuxt PDF 0.4.0-beta.3 conformance
|
|
2
2
|
|
|
3
3
|
Nuxt PDF claims behavioral compatibility for a deliberately small, tested
|
|
4
4
|
corpus. It does not claim full React PDF API or test-suite compatibility.
|
|
5
5
|
|
|
6
6
|
## Version boundary
|
|
7
7
|
|
|
8
|
-
| Layer | 0.4.0-beta.
|
|
8
|
+
| Layer | 0.4.0-beta.3 boundary |
|
|
9
9
|
|---|---|
|
|
10
10
|
| Node.js | `^22.14.0`, `^24.0.0`, or `^26.0.0` |
|
|
11
11
|
| Nuxt | `^4.4.8` |
|
|
@@ -22,6 +22,19 @@ any of them changes.
|
|
|
22
22
|
|
|
23
23
|
## Verified corpus
|
|
24
24
|
|
|
25
|
+
### Standalone registry
|
|
26
|
+
|
|
27
|
+
`test/standalone-build.test.ts` compiles the production registry and removes
|
|
28
|
+
template, font, and image sources before rendering. It checks custom fonts,
|
|
29
|
+
Unicode, embedded images, long text, pagination, equivalent extracted content,
|
|
30
|
+
and concurrent prop isolation. Plain NodeNext TypeScript checks inferred inline
|
|
31
|
+
and imported props without Vue source. Invalid resources, output limits, failed
|
|
32
|
+
build preservation, and generated-directory ownership have focused tests.
|
|
33
|
+
|
|
34
|
+
This is local Node evidence, not a deployed Convex or serverless certification.
|
|
35
|
+
Largest-realistic-document sizing, cold/warm timing, and platform memory limits
|
|
36
|
+
remain application deployment checks. The existing Nitro path is unchanged.
|
|
37
|
+
|
|
25
38
|
### Compatibility kernel
|
|
26
39
|
|
|
27
40
|
The paired React/Vue fixture verifies:
|
|
@@ -204,7 +217,7 @@ checking.
|
|
|
204
217
|
|
|
205
218
|
### Vue and Nuxt authoring
|
|
206
219
|
|
|
207
|
-
The 0.4.0-beta.
|
|
220
|
+
The 0.4.0-beta.2 tests verify:
|
|
208
221
|
|
|
209
222
|
- `PdfDocument`, `PdfPage`, `PdfView`, `PdfText`, `PdfImage`, `PdfLink`, and
|
|
210
223
|
`PdfNote`;
|
|
@@ -326,7 +339,7 @@ point at the source files and re-read them per render, so an edited image
|
|
|
326
339
|
shows up without a restart. The tested boundary includes:
|
|
327
340
|
|
|
328
341
|
- PNG and JPEG extension/signature validation and source byte limits;
|
|
329
|
-
- TTF and
|
|
342
|
+
- TTF, OTF, and WOFF2 signature/extension/structure validation,
|
|
330
343
|
registration validation, source byte limits, and source-removal rendering;
|
|
331
344
|
- explicit local `pdfs/assets` and `pdfs/fonts` roots;
|
|
332
345
|
- rejection of absolute paths, traversal, missing assets, ambiguous sources,
|
|
@@ -437,7 +450,7 @@ parser, not two. Claimed:
|
|
|
437
450
|
Verified end-to-end against a real rendered template, including assertion
|
|
438
451
|
failure messages, in `test/test-utils-public.test.ts`.
|
|
439
452
|
|
|
440
|
-
## Explicitly not claimed in 0.4.0-beta.
|
|
453
|
+
## Explicitly not claimed in 0.4.0-beta.2
|
|
441
454
|
|
|
442
455
|
- Full React PDF component, hook, browser-helper, or test-suite parity.
|
|
443
456
|
- React runtime compatibility or React-shaped dynamic callback results.
|
package/dist/build.d.mts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { PdfFontDeclaration } from '../dist/runtime/fonts.js';
|
|
2
|
+
import { RemoteAssetOptions } from '../dist/runtime/server/assets/remote.js';
|
|
3
|
+
import { PdfLimitsOptions } from '../dist/runtime/server/render-limits.js';
|
|
4
|
+
|
|
5
|
+
interface BuildPdfRegistryOptions {
|
|
6
|
+
/** Trusted application root containing pdfs/. Not request input. */
|
|
7
|
+
rootDir: string;
|
|
8
|
+
/** Dedicated generated directory inside rootDir and outside pdfs/. */
|
|
9
|
+
outDir: string;
|
|
10
|
+
fonts?: readonly PdfFontDeclaration[];
|
|
11
|
+
limits?: PdfLimitsOptions;
|
|
12
|
+
remote?: RemoteAssetOptions;
|
|
13
|
+
}
|
|
14
|
+
/** Compile trusted templates and embed admitted resources before deployment. */
|
|
15
|
+
declare function buildPdfRegistry(options: BuildPdfRegistryOptions): Promise<void>;
|
|
16
|
+
|
|
17
|
+
export { buildPdfRegistry };
|
|
18
|
+
export type { BuildPdfRegistryOptions };
|
package/dist/build.mjs
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { readdir, readFile, writeFile, mkdir, mkdtemp, rm, lstat, rename } from 'node:fs/promises';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
|
+
import { join, relative, dirname, resolve, isAbsolute } from 'node:path';
|
|
5
|
+
import { promisify } from 'node:util';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { build } from 'esbuild';
|
|
8
|
+
import { d as discoverPdfTemplates, a as discoverPdfImageFiles, b as bundlePdfFonts, c as compilePdfSfc } from './shared/nuxt-pdf.DMC_Rdsz.mjs';
|
|
9
|
+
import ts from 'typescript';
|
|
10
|
+
import { p as preparePdfImageAssets, g as generatePdfRuntimeRegistry, a as generateAuthoringTypes, b as generatePdfRegistryTypes } from './shared/nuxt-pdf.D3hUPqOJ.mjs';
|
|
11
|
+
import { normalizeRemoteAssetPolicy } from '../dist/runtime/server/assets/remote.js';
|
|
12
|
+
import { normalizePdfLimits, DEFAULT_PDF_RENDER_LIMITS } from '../dist/runtime/server/render-limits.js';
|
|
13
|
+
import 'node:buffer';
|
|
14
|
+
import 'node:fs';
|
|
15
|
+
import '@vue/compiler-sfc';
|
|
16
|
+
import '@jridgewell/remapping';
|
|
17
|
+
import 'unimport';
|
|
18
|
+
import '../dist/runtime/shared/template.js';
|
|
19
|
+
import '../dist/runtime/components/stubs.js';
|
|
20
|
+
import 'ufo';
|
|
21
|
+
import '../dist/runtime/server/assets/resolve-asset.js';
|
|
22
|
+
|
|
23
|
+
async function normalizeDeclarationImports(directory) {
|
|
24
|
+
for (const file of await readdir(directory, { recursive: true })) {
|
|
25
|
+
if (!/\.d\.[cm]?ts$/.test(file)) continue;
|
|
26
|
+
const path = join(directory, file);
|
|
27
|
+
const source = ts.createSourceFile(path, await readFile(path, "utf8"), ts.ScriptTarget.Latest, true);
|
|
28
|
+
const transformed = ts.transform(source, [(context) => {
|
|
29
|
+
const visit = (node) => {
|
|
30
|
+
if (ts.isStringLiteral(node) && node.text.startsWith(".")) {
|
|
31
|
+
const parent = node.parent;
|
|
32
|
+
const isImport = ts.isImportDeclaration(parent) || ts.isExportDeclaration(parent) || ts.isLiteralTypeNode(parent) && ts.isImportTypeNode(parent.parent);
|
|
33
|
+
if (isImport && !node.text.endsWith(".json")) {
|
|
34
|
+
const module = ts.resolveModuleName(node.text, path, { moduleResolution: ts.ModuleResolutionKind.Bundler }, ts.sys).resolvedModule;
|
|
35
|
+
if (!module) throw new Error(`Cannot resolve emitted declaration import ${JSON.stringify(node.text)} from ${path}. Use a relative TypeScript source file inside rootDir.`);
|
|
36
|
+
const target = relative(dirname(path), module.resolvedFileName).replaceAll("\\", "/").replace(/\.d\.([cm]?)ts$/, ".$1js");
|
|
37
|
+
return ts.factory.createStringLiteral(target.startsWith(".") ? target : `./${target}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return ts.visitEachChild(node, visit, context);
|
|
41
|
+
};
|
|
42
|
+
return (node) => ts.visitNode(node, visit);
|
|
43
|
+
}]);
|
|
44
|
+
try {
|
|
45
|
+
await writeFile(path, ts.createPrinter().printFile(transformed.transformed[0]));
|
|
46
|
+
} finally {
|
|
47
|
+
transformed.dispose();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const runtimeImport = "@lupinum/nuxt-pdf/server";
|
|
53
|
+
const execute = promisify(execFile);
|
|
54
|
+
const ownershipMarker = ".nuxt-pdf-generated";
|
|
55
|
+
const ownershipContent = "Generated by @lupinum/nuxt-pdf/build. Do not edit.\n";
|
|
56
|
+
function contains(parent, child) {
|
|
57
|
+
const path = relative(parent, child);
|
|
58
|
+
return path === "" || path !== ".." && !path.startsWith("../") && !path.startsWith("..\\") && !isAbsolute(path);
|
|
59
|
+
}
|
|
60
|
+
async function checkOutputDirectory(outDir) {
|
|
61
|
+
const info = await lstat(outDir).catch((error) => {
|
|
62
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") return void 0;
|
|
63
|
+
throw error;
|
|
64
|
+
});
|
|
65
|
+
if (!info) return;
|
|
66
|
+
if (!info.isDirectory() || info.isSymbolicLink()) {
|
|
67
|
+
throw new TypeError("buildPdfRegistry outDir must be a directory, not a file or symlink.");
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
const marker = await readFile(join(outDir, ownershipMarker), "utf8");
|
|
71
|
+
if (marker !== ownershipContent) throw new Error("invalid ownership marker");
|
|
72
|
+
} catch (error) {
|
|
73
|
+
throw new TypeError("buildPdfRegistry refuses to replace a directory it did not generate.", { cause: error });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async function replaceOutputDirectory(staging, outDir) {
|
|
77
|
+
const parent = dirname(outDir);
|
|
78
|
+
const previousRoot = await mkdtemp(join(parent, ".nuxt-pdf-previous-"));
|
|
79
|
+
const previous = join(previousRoot, "output");
|
|
80
|
+
let removePreviousRoot = true;
|
|
81
|
+
try {
|
|
82
|
+
const exists = await lstat(outDir).then(() => true, (error) => {
|
|
83
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") return false;
|
|
84
|
+
throw error;
|
|
85
|
+
});
|
|
86
|
+
if (exists) await rename(outDir, previous);
|
|
87
|
+
try {
|
|
88
|
+
await rename(staging, outDir);
|
|
89
|
+
} catch (error) {
|
|
90
|
+
if (exists) {
|
|
91
|
+
try {
|
|
92
|
+
await rename(previous, outDir);
|
|
93
|
+
} catch (restoreError) {
|
|
94
|
+
removePreviousRoot = false;
|
|
95
|
+
throw new AggregateError(
|
|
96
|
+
[error, restoreError],
|
|
97
|
+
`Failed to replace generated PDF output and restore it. The prior output remains at ${previous}.`,
|
|
98
|
+
{ cause: restoreError }
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
} finally {
|
|
105
|
+
if (removePreviousRoot) await rm(previousRoot, { recursive: true, force: true });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
async function buildPdfRegistry(options) {
|
|
109
|
+
const allowed = /* @__PURE__ */ new Set(["rootDir", "outDir", "fonts", "limits", "remote"]);
|
|
110
|
+
for (const key of Object.keys(options)) {
|
|
111
|
+
if (!allowed.has(key)) throw new TypeError(`buildPdfRegistry: unsupported option ${JSON.stringify(key)}.`);
|
|
112
|
+
}
|
|
113
|
+
if (!options.rootDir?.trim() || !options.outDir?.trim()) {
|
|
114
|
+
throw new TypeError("buildPdfRegistry requires rootDir and outDir.");
|
|
115
|
+
}
|
|
116
|
+
const rootDir = resolve(options.rootDir);
|
|
117
|
+
const outDir = resolve(rootDir, options.outDir);
|
|
118
|
+
const pdfRoot = join(rootDir, "pdfs");
|
|
119
|
+
if (!contains(rootDir, outDir) || contains(pdfRoot, outDir) || contains(outDir, pdfRoot)) {
|
|
120
|
+
throw new TypeError("buildPdfRegistry outDir must be a dedicated directory inside rootDir and outside pdfs/.");
|
|
121
|
+
}
|
|
122
|
+
await checkOutputDirectory(outDir);
|
|
123
|
+
const layers = [{ rootDir }];
|
|
124
|
+
const templates = await discoverPdfTemplates(layers);
|
|
125
|
+
if (templates.length === 0) throw new TypeError("buildPdfRegistry found no templates in pdfs/.");
|
|
126
|
+
const limits = normalizePdfLimits(options.limits);
|
|
127
|
+
const [assets, fonts] = await Promise.all([
|
|
128
|
+
discoverPdfImageFiles(layers).then((images) => preparePdfImageAssets(images, limits ?? DEFAULT_PDF_RENDER_LIMITS, false)),
|
|
129
|
+
bundlePdfFonts(options.fonts ?? [], { fontRoots: [join(pdfRoot, "fonts")] })
|
|
130
|
+
]);
|
|
131
|
+
const source = generatePdfRuntimeRegistry(templates, {
|
|
132
|
+
assets,
|
|
133
|
+
fonts,
|
|
134
|
+
limits,
|
|
135
|
+
remote: normalizeRemoteAssetPolicy(options.remote),
|
|
136
|
+
runtimeImport,
|
|
137
|
+
development: false
|
|
138
|
+
});
|
|
139
|
+
const entries = new Set(templates.map((template) => template.filePath));
|
|
140
|
+
const result = await build({
|
|
141
|
+
absWorkingDir: rootDir,
|
|
142
|
+
stdin: { contents: source, resolveDir: rootDir, sourcefile: "pdf-registry.js" },
|
|
143
|
+
bundle: true,
|
|
144
|
+
packages: "external",
|
|
145
|
+
platform: "node",
|
|
146
|
+
format: "esm",
|
|
147
|
+
target: "node22",
|
|
148
|
+
tsconfigRaw: {},
|
|
149
|
+
write: false,
|
|
150
|
+
plugins: [{
|
|
151
|
+
name: "nuxt-pdf:standalone",
|
|
152
|
+
setup(builder) {
|
|
153
|
+
builder.onLoad({ filter: /\.vue$/ }, async ({ path }) => ({
|
|
154
|
+
contents: (await compilePdfSfc(await readFile(path, "utf8"), path, entries.has(path) ? "template" : "component", true, runtimeImport)).code,
|
|
155
|
+
loader: "js",
|
|
156
|
+
resolveDir: dirname(path)
|
|
157
|
+
}));
|
|
158
|
+
}
|
|
159
|
+
}]
|
|
160
|
+
});
|
|
161
|
+
const output = result.outputFiles[0];
|
|
162
|
+
if (!output) throw new Error("PDF registry compilation produced no output.");
|
|
163
|
+
await mkdir(dirname(outDir), { recursive: true });
|
|
164
|
+
const staging = await mkdtemp(join(dirname(outDir), ".nuxt-pdf-build-"));
|
|
165
|
+
try {
|
|
166
|
+
await emitDeclarations(rootDir, staging, templates);
|
|
167
|
+
await writeFile(join(staging, "index.mjs"), output.contents);
|
|
168
|
+
await writeFile(join(staging, ownershipMarker), ownershipContent);
|
|
169
|
+
await checkOutputDirectory(outDir);
|
|
170
|
+
await replaceOutputDirectory(staging, outDir);
|
|
171
|
+
} finally {
|
|
172
|
+
await rm(staging, { recursive: true, force: true });
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
async function emitDeclarations(rootDir, outDir, templates) {
|
|
176
|
+
const temporary = await mkdtemp(join(outDir, ".types-"));
|
|
177
|
+
try {
|
|
178
|
+
const globals = join(temporary, "authoring.d.ts");
|
|
179
|
+
const runtimeDirectory = join(dirname(fileURLToPath(import.meta.resolve(runtimeImport))), "runtime");
|
|
180
|
+
await writeFile(globals, generateAuthoringTypes(
|
|
181
|
+
join(runtimeDirectory, "components/index"),
|
|
182
|
+
join(runtimeDirectory, "composables/index"),
|
|
183
|
+
join(runtimeDirectory, "define-pdf")
|
|
184
|
+
));
|
|
185
|
+
const config = join(temporary, "tsconfig.json");
|
|
186
|
+
await writeFile(config, JSON.stringify({
|
|
187
|
+
compilerOptions: {
|
|
188
|
+
target: "ES2022",
|
|
189
|
+
module: "ESNext",
|
|
190
|
+
moduleResolution: "Bundler",
|
|
191
|
+
strict: true,
|
|
192
|
+
skipLibCheck: true,
|
|
193
|
+
declaration: true,
|
|
194
|
+
emitDeclarationOnly: true,
|
|
195
|
+
noEmitOnError: true,
|
|
196
|
+
rootDir,
|
|
197
|
+
declarationDir: join(outDir, "types"),
|
|
198
|
+
types: []
|
|
199
|
+
},
|
|
200
|
+
files: [...templates.map((template) => template.filePath), globals]
|
|
201
|
+
}));
|
|
202
|
+
try {
|
|
203
|
+
await execute(process.execPath, [createRequire(import.meta.url).resolve("vue-tsc/bin/vue-tsc.js"), "--project", config], { cwd: rootDir, maxBuffer: 4 * 1024 * 1024 });
|
|
204
|
+
} catch (error) {
|
|
205
|
+
const diagnostics = error instanceof Error && "stdout" in error ? String(error.stdout) : "";
|
|
206
|
+
throw new Error(`PDF template type checking failed.
|
|
207
|
+
${diagnostics}`, { cause: error });
|
|
208
|
+
}
|
|
209
|
+
await normalizeDeclarationImports(join(outDir, "types"));
|
|
210
|
+
const declarationTemplates = templates.map((template) => ({
|
|
211
|
+
...template,
|
|
212
|
+
filePath: `./types/${relative(rootDir, template.filePath).replaceAll("\\", "/")}.js`
|
|
213
|
+
}));
|
|
214
|
+
await writeFile(join(outDir, "index.d.mts"), generatePdfRegistryTypes(declarationTemplates, { runtimeImport }));
|
|
215
|
+
} finally {
|
|
216
|
+
await rm(temporary, { recursive: true, force: true });
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export { buildPdfRegistry };
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,188 +1,23 @@
|
|
|
1
1
|
import { stat } from 'node:fs/promises';
|
|
2
|
-
import { Buffer } from 'node:buffer';
|
|
3
2
|
import { join, isAbsolute, resolve, relative } from 'node:path';
|
|
4
3
|
import { defineNuxtModule, createResolver, getLayerDirectories, createIsIgnored, addServerTemplate, addTemplate, addImports, addTypeTemplate, logger, addServerHandler, addComponent } from '@nuxt/kit';
|
|
5
4
|
import { joinURL } from 'ufo';
|
|
6
|
-
import { d as discoverPdfTemplates,
|
|
7
|
-
import {
|
|
5
|
+
import { d as discoverPdfTemplates, e as discoverPdfComponentFiles, a as discoverPdfImageFiles, b as bundlePdfFonts, f as createPdfSfcPlugin, g as classifyPdfWatchEvent } from './shared/nuxt-pdf.DMC_Rdsz.mjs';
|
|
6
|
+
import { p as preparePdfImageAssets, g as generatePdfRuntimeRegistry, b as generatePdfRegistryTypes, a as generateAuthoringTypes, c as generatePdfPreviewConfig } from './shared/nuxt-pdf.D3hUPqOJ.mjs';
|
|
8
7
|
import { PDF_STUB_NAMES } from '../dist/runtime/components/stubs.js';
|
|
9
8
|
import { normalizeRemoteAssetPolicy } from '../dist/runtime/server/assets/remote.js';
|
|
10
9
|
import { normalizePdfLimits, DEFAULT_PDF_RENDER_LIMITS } from '../dist/runtime/server/render-limits.js';
|
|
10
|
+
import 'node:buffer';
|
|
11
11
|
import 'node:fs';
|
|
12
12
|
import '@vue/compiler-sfc';
|
|
13
13
|
import '@jridgewell/remapping';
|
|
14
14
|
import 'esbuild';
|
|
15
15
|
import 'unimport';
|
|
16
16
|
import '../dist/runtime/shared/template.js';
|
|
17
|
+
import '../dist/runtime/server/assets/resolve-asset.js';
|
|
17
18
|
|
|
18
|
-
const version = "0.4.0-beta.
|
|
19
|
+
const version = "0.4.0-beta.3";
|
|
19
20
|
|
|
20
|
-
const compareText = (left, right) => {
|
|
21
|
-
if (left < right) return -1;
|
|
22
|
-
if (left > right) return 1;
|
|
23
|
-
return 0;
|
|
24
|
-
};
|
|
25
|
-
const quote$1 = (value) => JSON.stringify(value);
|
|
26
|
-
const generatePdfPreviewConfig = (baseURL, buildAssetsDir) => `export const hmrClientPath = ${quote$1(joinURL(
|
|
27
|
-
baseURL.replace(/^\.\//, "/") || "/",
|
|
28
|
-
buildAssetsDir,
|
|
29
|
-
"@vite/client"
|
|
30
|
-
))}
|
|
31
|
-
`;
|
|
32
|
-
const importPath = (filePath) => filePath.replaceAll("\\", "/");
|
|
33
|
-
const runtimeOptionsSource = (options) => {
|
|
34
|
-
const assets = options.assets ?? [];
|
|
35
|
-
const fonts = options.fonts ?? [];
|
|
36
|
-
const { remote, limits } = options;
|
|
37
|
-
for (const asset of assets) {
|
|
38
|
-
if (asset.root !== void 0 === (asset.dataB64 !== void 0)) {
|
|
39
|
-
throw new TypeError(
|
|
40
|
-
`PDF image asset "${asset.key}" must declare exactly one of root or dataB64.`
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
if (assets.length === 0 && fonts.length === 0 && !remote && !limits) return [];
|
|
45
|
-
const lines = ["", "const __pdfRuntimeOptions = Object.freeze({"];
|
|
46
|
-
if (assets.length > 0) {
|
|
47
|
-
lines.push(" assets: Object.freeze({");
|
|
48
|
-
for (const asset of assets) {
|
|
49
|
-
const entry = asset.root !== void 0 ? `{ format: ${quote$1(asset.format)}, root: ${quote$1(asset.root)} }` : `{ dataB64: ${quote$1(asset.dataB64 ?? "")}, format: ${quote$1(asset.format)} }`;
|
|
50
|
-
lines.push(` ${quote$1(asset.key)}: Object.freeze(${entry}),`);
|
|
51
|
-
}
|
|
52
|
-
lines.push(" }),");
|
|
53
|
-
}
|
|
54
|
-
if (fonts.length > 0) {
|
|
55
|
-
lines.push(" fonts: Object.freeze([");
|
|
56
|
-
for (const font of fonts) {
|
|
57
|
-
lines.push(` Object.freeze(${JSON.stringify(font)}),`);
|
|
58
|
-
}
|
|
59
|
-
lines.push(" ]),");
|
|
60
|
-
}
|
|
61
|
-
if (remote) {
|
|
62
|
-
lines.push(` remote: Object.freeze(${JSON.stringify(remote)}),`);
|
|
63
|
-
}
|
|
64
|
-
if (limits) {
|
|
65
|
-
lines.push(` limits: Object.freeze(${JSON.stringify(limits)}),`);
|
|
66
|
-
}
|
|
67
|
-
lines.push("})");
|
|
68
|
-
return lines;
|
|
69
|
-
};
|
|
70
|
-
const orderedTemplates = (templates) => {
|
|
71
|
-
const result = [...templates].sort(
|
|
72
|
-
(left, right) => compareText(left.key, right.key)
|
|
73
|
-
);
|
|
74
|
-
const keys = /* @__PURE__ */ new Map();
|
|
75
|
-
for (const template of result) {
|
|
76
|
-
const duplicate = keys.get(template.key);
|
|
77
|
-
if (duplicate) {
|
|
78
|
-
throw new TypeError(
|
|
79
|
-
`Cannot generate duplicate PDF template key "${template.key}" from "${duplicate.filePath}" and "${template.filePath}".`
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
keys.set(template.key, template);
|
|
83
|
-
}
|
|
84
|
-
return result;
|
|
85
|
-
};
|
|
86
|
-
const validateOptions = (options) => {
|
|
87
|
-
if (options.runtimeImport.trim() === "") {
|
|
88
|
-
throw new TypeError("runtimeImport is required to generate the PDF registry.");
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
const generatePdfRuntimeRegistry = (templates, options) => {
|
|
92
|
-
validateOptions(options);
|
|
93
|
-
const ordered = orderedTemplates(templates);
|
|
94
|
-
const runtimeImports = options.development ? "createPdfPreviewEntry, createPdfRegistry, createPdfTemplate" : "createPdfRegistry, createPdfTemplate";
|
|
95
|
-
const lines = [
|
|
96
|
-
`import { ${runtimeImports} } from ${quote$1(options.runtimeImport)}`
|
|
97
|
-
];
|
|
98
|
-
ordered.forEach((template, index) => {
|
|
99
|
-
lines.push(
|
|
100
|
-
`import __pdfTemplate${index} from ${quote$1(importPath(template.filePath))}`
|
|
101
|
-
);
|
|
102
|
-
});
|
|
103
|
-
const runtimeOptions = runtimeOptionsSource(options);
|
|
104
|
-
lines.push(...runtimeOptions, "", "const registry = createPdfRegistry({");
|
|
105
|
-
ordered.forEach((template, index) => {
|
|
106
|
-
const file = quote$1(`pdfs/${template.relativePath}`);
|
|
107
|
-
const runtimeArgument = options.development ? runtimeOptions.length > 0 ? `, { ...__pdfRuntimeOptions, file: ${file} }` : `, { file: ${file} }` : runtimeOptions.length > 0 ? ", __pdfRuntimeOptions" : "";
|
|
108
|
-
lines.push(
|
|
109
|
-
` ${quote$1(template.key)}: createPdfTemplate(${quote$1(template.key)}, __pdfTemplate${index}${runtimeArgument}),`
|
|
110
|
-
);
|
|
111
|
-
});
|
|
112
|
-
lines.push("})");
|
|
113
|
-
if (options.development) {
|
|
114
|
-
lines.push("", "export const pdfPreview = Object.freeze({");
|
|
115
|
-
ordered.forEach((template, index) => {
|
|
116
|
-
lines.push(
|
|
117
|
-
` ${quote$1(template.key)}: createPdfPreviewEntry(registry.pdf[${quote$1(template.key)}], __pdfTemplate${index}, { file: ${quote$1(`pdfs/${template.relativePath}`)} }),`
|
|
118
|
-
);
|
|
119
|
-
});
|
|
120
|
-
lines.push("})");
|
|
121
|
-
}
|
|
122
|
-
lines.push(
|
|
123
|
-
"",
|
|
124
|
-
"export const pdf = registry.pdf",
|
|
125
|
-
"export const renderPdf = registry.renderPdf",
|
|
126
|
-
"export const getPdfTemplate = registry.getPdfTemplate",
|
|
127
|
-
"export const pdfTemplateKeys = registry.pdfTemplateKeys",
|
|
128
|
-
`export { NuxtPdfError, PDF_ERROR_CODES } from ${quote$1(options.runtimeImport)}`,
|
|
129
|
-
""
|
|
130
|
-
);
|
|
131
|
-
return lines.join("\n");
|
|
132
|
-
};
|
|
133
|
-
const generatePdfRegistryTypes = (templates, options) => {
|
|
134
|
-
validateOptions(options);
|
|
135
|
-
const ordered = orderedTemplates(templates);
|
|
136
|
-
const lines = [
|
|
137
|
-
`import type { PdfComponentProps, PdfRenderResult, PdfTemplate } from ${quote$1(options.runtimeImport)}`
|
|
138
|
-
];
|
|
139
|
-
ordered.forEach((template, index) => {
|
|
140
|
-
lines.push(
|
|
141
|
-
"",
|
|
142
|
-
`type PdfComponent${index} = typeof import(${quote$1(importPath(template.filePath))})['default']`,
|
|
143
|
-
`type PdfProps${index} = PdfComponentProps<PdfComponent${index}>`
|
|
144
|
-
);
|
|
145
|
-
});
|
|
146
|
-
lines.push("", "export declare const pdf: {");
|
|
147
|
-
ordered.forEach((template, index) => {
|
|
148
|
-
lines.push(
|
|
149
|
-
` readonly ${quote$1(template.key)}: PdfTemplate<PdfProps${index}>`
|
|
150
|
-
);
|
|
151
|
-
});
|
|
152
|
-
lines.push("}", "");
|
|
153
|
-
if (ordered.length === 0) {
|
|
154
|
-
lines.push(
|
|
155
|
-
"export declare function renderPdf(name: never, props: never): Promise<PdfRenderResult>",
|
|
156
|
-
"export declare function getPdfTemplate(name: never): never"
|
|
157
|
-
);
|
|
158
|
-
} else {
|
|
159
|
-
ordered.forEach((template, index) => {
|
|
160
|
-
lines.push(
|
|
161
|
-
`export declare function renderPdf(name: ${quote$1(template.key)}, props: PdfProps${index}): Promise<PdfRenderResult>`
|
|
162
|
-
);
|
|
163
|
-
});
|
|
164
|
-
lines.push(
|
|
165
|
-
"export declare function renderPdf(name: string, props: Record<string, unknown>, escapeHatch: { readonly unsafe: true }): Promise<PdfRenderResult>"
|
|
166
|
-
);
|
|
167
|
-
lines.push("");
|
|
168
|
-
ordered.forEach((template, index) => {
|
|
169
|
-
lines.push(
|
|
170
|
-
`export declare function getPdfTemplate(name: ${quote$1(template.key)}): PdfTemplate<PdfProps${index}>`
|
|
171
|
-
);
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
lines.push(
|
|
175
|
-
"",
|
|
176
|
-
`export declare const pdfTemplateKeys: readonly [${ordered.map((template) => quote$1(template.key)).join(", ")}]`,
|
|
177
|
-
"export type PdfTemplateKey = typeof pdfTemplateKeys[number]",
|
|
178
|
-
`export { NuxtPdfError, PDF_ERROR_CODES } from ${quote$1(options.runtimeImport)}`,
|
|
179
|
-
`export type { PdfErrorCode } from ${quote$1(options.runtimeImport)}`,
|
|
180
|
-
""
|
|
181
|
-
);
|
|
182
|
-
return lines.join("\n");
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
const quote = (value) => JSON.stringify(value);
|
|
186
21
|
const existingDirectories = async (directories) => {
|
|
187
22
|
const result = [];
|
|
188
23
|
for (const directory of directories) {
|
|
@@ -194,35 +29,6 @@ const existingDirectories = async (directories) => {
|
|
|
194
29
|
}
|
|
195
30
|
return result;
|
|
196
31
|
};
|
|
197
|
-
const generateAuthoringTypes = (componentsImport) => `declare module 'vue' {
|
|
198
|
-
interface GlobalComponents {
|
|
199
|
-
PdfDocument: typeof import(${quote(componentsImport)})['PdfDocument']
|
|
200
|
-
PdfImage: typeof import(${quote(componentsImport)})['PdfImage']
|
|
201
|
-
PdfLink: typeof import(${quote(componentsImport)})['PdfLink']
|
|
202
|
-
PdfNote: typeof import(${quote(componentsImport)})['PdfNote']
|
|
203
|
-
PdfPage: typeof import(${quote(componentsImport)})['PdfPage']
|
|
204
|
-
PdfText: typeof import(${quote(componentsImport)})['PdfText']
|
|
205
|
-
PdfView: typeof import(${quote(componentsImport)})['PdfView']
|
|
206
|
-
PdfSvg: typeof import(${quote(componentsImport)})['PdfSvg']
|
|
207
|
-
PdfG: typeof import(${quote(componentsImport)})['PdfG']
|
|
208
|
-
PdfPath: typeof import(${quote(componentsImport)})['PdfPath']
|
|
209
|
-
PdfRect: typeof import(${quote(componentsImport)})['PdfRect']
|
|
210
|
-
PdfCircle: typeof import(${quote(componentsImport)})['PdfCircle']
|
|
211
|
-
PdfEllipse: typeof import(${quote(componentsImport)})['PdfEllipse']
|
|
212
|
-
PdfLine: typeof import(${quote(componentsImport)})['PdfLine']
|
|
213
|
-
PdfPolyline: typeof import(${quote(componentsImport)})['PdfPolyline']
|
|
214
|
-
PdfPolygon: typeof import(${quote(componentsImport)})['PdfPolygon']
|
|
215
|
-
PdfDefs: typeof import(${quote(componentsImport)})['PdfDefs']
|
|
216
|
-
PdfClipPath: typeof import(${quote(componentsImport)})['PdfClipPath']
|
|
217
|
-
PdfLinearGradient: typeof import(${quote(componentsImport)})['PdfLinearGradient']
|
|
218
|
-
PdfRadialGradient: typeof import(${quote(componentsImport)})['PdfRadialGradient']
|
|
219
|
-
PdfStop: typeof import(${quote(componentsImport)})['PdfStop']
|
|
220
|
-
PdfTspan: typeof import(${quote(componentsImport)})['PdfTspan']
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
export {}
|
|
225
|
-
`;
|
|
226
32
|
const module$1 = defineNuxtModule({
|
|
227
33
|
meta: {
|
|
228
34
|
name: "@lupinum/nuxt-pdf",
|
|
@@ -256,24 +62,7 @@ const module$1 = defineNuxtModule({
|
|
|
256
62
|
const limits = normalizePdfLimits(options.limits);
|
|
257
63
|
const resolvedLimits = limits ?? DEFAULT_PDF_RENDER_LIMITS;
|
|
258
64
|
const imageFiles = await discoverPdfImageFiles(layers, isIgnored);
|
|
259
|
-
const assetEntries =
|
|
260
|
-
for (const image of imageFiles) {
|
|
261
|
-
const format = pdfImageFormatFromKey(image.key);
|
|
262
|
-
if (nuxt.options.dev) {
|
|
263
|
-
assetEntries.push({ format, key: image.key, root: image.rootDir });
|
|
264
|
-
} else {
|
|
265
|
-
const loaded = await loadPdfImageAsset(image.key, {
|
|
266
|
-
roots: [image.rootDir],
|
|
267
|
-
maxBytes: resolvedLimits.maxImageBytes,
|
|
268
|
-
maxPixels: resolvedLimits.maxImagePixels
|
|
269
|
-
});
|
|
270
|
-
assetEntries.push({
|
|
271
|
-
dataB64: Buffer.from(loaded.data).toString("base64"),
|
|
272
|
-
format,
|
|
273
|
-
key: image.key
|
|
274
|
-
});
|
|
275
|
-
}
|
|
276
|
-
}
|
|
65
|
+
const assetEntries = await preparePdfImageAssets(imageFiles, resolvedLimits, nuxt.options.dev);
|
|
277
66
|
const fontRoots = await existingDirectories(
|
|
278
67
|
layers.map((layer) => join(layer.rootDir, "pdfs", "fonts"))
|
|
279
68
|
);
|
|
@@ -331,7 +120,9 @@ const module$1 = defineNuxtModule({
|
|
|
331
120
|
addTypeTemplate({
|
|
332
121
|
filename: "types/nuxt-pdf-authoring.d.ts",
|
|
333
122
|
getContents: () => generateAuthoringTypes(
|
|
334
|
-
componentsImport
|
|
123
|
+
componentsImport,
|
|
124
|
+
composablesImport,
|
|
125
|
+
definePdfImport
|
|
335
126
|
),
|
|
336
127
|
write: true
|
|
337
128
|
}, { nitro: true, node: true, nuxt: true });
|
package/dist/runtime/fonts.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export interface PdfFontDeclaration {
|
|
|
7
7
|
fontStyle?: PdfFontStyle;
|
|
8
8
|
fontWeight?: PdfFontWeight;
|
|
9
9
|
}
|
|
10
|
-
export type PdfFontDataUrl = `data:font/${'otf' | 'ttf'};base64,${string}`;
|
|
10
|
+
export type PdfFontDataUrl = `data:font/${'otf' | 'ttf' | 'woff2'};base64,${string}`;
|
|
11
11
|
export interface BundledPdfFontDescriptor {
|
|
12
12
|
family: string;
|
|
13
13
|
src: PdfFontDataUrl;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { mountPdfComponent } from './render-component.js';
|
|
2
|
+
export { PDF_PRIMITIVE_NAMES } from './types.js';
|
|
2
3
|
export type { MountedPdfComponent, PdfComponentProps, } from './render-component.js';
|
|
3
4
|
export type { PdfDocumentNode, PdfElementNode, PdfNode, PdfRoot, PdfTextInstance, } from './types.js';
|