From a3ba5a3af6683b07a7437c947559434d13b1264c Mon Sep 17 00:00:00 2001 From: Ralf Sternberg Date: Sat, 5 Oct 2024 15:13:57 +0200 Subject: [PATCH] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Require=20Node=2020,=20npm?= =?UTF-8?q?=2010?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Node.js version 20 is the current LTS version. Node.js 18 will be end-of-life in April 2025. This commit updates the minimum required Node.js version to 20. Node 20 supports ESM out of the box. The WebCrypto API is available in the global scope. The `--experimental-global-webcrypto` flag is no longer needed to run the examples. The manual exposure of the API in the global scope has been removed from the tests. --- .github/workflows/test-build.yml | 2 +- CHANGELOG.md | 2 ++ examples/README.md | 35 +++--------------------------- package-lock.json | 4 ++-- package.json | 4 ++-- src/api/make-pdf.test.ts | 4 ---- src/image-loader.test.ts | 3 --- src/images.test.ts | 3 --- src/render/render-document.test.ts | 18 ++++++++++----- 9 files changed, 23 insertions(+), 52 deletions(-) diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 5a21201..a386542 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -8,7 +8,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v1 with: - node-version: '18.x' + node-version: '20.x' - run: npm ci - run: npm run lint - run: npm run test diff --git a/CHANGELOG.md b/CHANGELOG.md index a7cdcde..f988d0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## [0.5.5] - Unreleased +Minimum requirements bumped to Node 20 and npm 10. + ### Deprecated - `TextAttrs` in favor of `TextProps`. diff --git a/examples/README.md b/examples/README.md index df1c2a8..62213eb 100644 --- a/examples/README.md +++ b/examples/README.md @@ -32,39 +32,11 @@ If you're using [Deno], you can skip this step. ## Run the examples -### Node - -Node.js does not yet expose the [WebCrypto API] in the global scope. -Since PDF Maker uses this API, the `--experimental-global-webcrypto` -flag must be used: - -```sh -$ node --experimental-global-webcrypto src/hello-world.js -``` - -Alternatively, you can expose the API in the global scope yourself: - -```js -import * as crypto from 'crypto'; -global.crypto ??= crypto; -``` - -Also note that Node.js still relies on the `module: true` flag in the -`package.json` file to enable ESM mode. - -### Bun - -[Bun] works out of the box: - ```sh +$ node src/hello-world.js +# OR $ bun run src/hello-world.js -``` - -### Deno - -[Deno] works out of the box: - -```sh +# OR $ deno run --allow-read --allow-write src/hello-world.js ``` @@ -80,4 +52,3 @@ $ bun run --watch src/hello-world.js [Node]: https://nodejs.org/en/ [Bun]: https://bun.sh/ [Deno]: https://deno.land/ -[WebCrypto API]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API diff --git a/package-lock.json b/package-lock.json index 0cef508..ca3cc1d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,8 +25,8 @@ "vitest": "^2.1.2" }, "engines": { - "node": ">=16.13.0", - "npm": ">=8" + "node": ">=20", + "npm": ">=10" } }, "node_modules/@esbuild/aix-ppc64": { diff --git a/package.json b/package.json index fac7c6b..724d8b0 100644 --- a/package.json +++ b/package.json @@ -21,8 +21,8 @@ "module": "./dist/index.js" }, "engines": { - "node": ">=16.13.0", - "npm": ">=8" + "node": ">=20", + "npm": ">=10" }, "scripts": { "build": "rm -rf build/ dist/ && tsc && esbuild src/index.ts --bundle --sourcemap --platform=node --target=es2021,node18 --outdir=dist --format=esm --external:pdf-lib --external:@pdf-lib/fontkit && cp -a build/index.d.ts build/api/ dist/", diff --git a/src/api/make-pdf.test.ts b/src/api/make-pdf.test.ts index 00c9ce1..c02ed0a 100644 --- a/src/api/make-pdf.test.ts +++ b/src/api/make-pdf.test.ts @@ -1,11 +1,7 @@ -import crypto from 'node:crypto'; - import { describe, expect, it } from 'vitest'; import { makePdf } from './make-pdf.ts'; -global.crypto ??= (crypto as any).webcrypto; - describe('make-pdf', () => { describe('makePdf', () => { it('creates data that starts with a PDF 1.7 header', async () => { diff --git a/src/image-loader.test.ts b/src/image-loader.test.ts index 9912bae..6098520 100644 --- a/src/image-loader.test.ts +++ b/src/image-loader.test.ts @@ -1,4 +1,3 @@ -import crypto from 'node:crypto'; import { readFile } from 'node:fs/promises'; import { join } from 'node:path'; @@ -7,8 +6,6 @@ import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; import { ImageLoader, ImageStore } from './image-loader.ts'; import type { ImageSelector } from './images.ts'; -global.crypto ??= (crypto as any).webcrypto; - describe('image-loader', () => { let libertyJpg: Uint8Array; let torusPng: Uint8Array; diff --git a/src/images.test.ts b/src/images.test.ts index e58e352..90d3f76 100644 --- a/src/images.test.ts +++ b/src/images.test.ts @@ -1,4 +1,3 @@ -import crypto from 'node:crypto'; import { readFile } from 'node:fs/promises'; import { join } from 'node:path'; @@ -8,8 +7,6 @@ import type { Image } from './images.ts'; import { readImages, registerImage } from './images.ts'; import { fakePDFDocument, mkData } from './test/test-utils.ts'; -global.crypto ??= (crypto as any).webcrypto; - describe('images', () => { describe('readImages', () => { it('returns an empty array for missing images definition', () => { diff --git a/src/render/render-document.test.ts b/src/render/render-document.test.ts index 2f5640f..9b401dc 100644 --- a/src/render/render-document.test.ts +++ b/src/render/render-document.test.ts @@ -1,13 +1,9 @@ -import crypto from 'node:crypto'; - -import type { PDFStream } from 'pdf-lib'; +import type { PDFArray, PDFStream } from 'pdf-lib'; import { PDFDict, PDFDocument, PDFHexString, PDFName, PDFString } from 'pdf-lib'; import { describe, expect, it } from 'vitest'; import { renderDocument } from './render-document.ts'; -global.crypto ??= (crypto as any).webcrypto; - describe('render-document', () => { describe('renderDocument', () => { it('renders all info properties', async () => { @@ -45,6 +41,18 @@ describe('render-document', () => { expect(getInfo('bar')).toEqual(PDFHexString.fromText('bar-value')); }); + it('generates file ID', async () => { + const def = { content: [] }; + + const pdfData = await renderDocument(def, []); + + const pdfDoc = await PDFDocument.load(pdfData, { updateMetadata: false }); + const fileId = pdfDoc.context.lookup(pdfDoc.context.trailerInfo.ID) as PDFArray; + expect(fileId.size()).toBe(2); + expect(fileId.get(0).toString()).toMatch(/^<[0-9A-F]{64}>$/); + expect(fileId.get(1).toString()).toMatch(/^<[0-9A-F]{64}>$/); + }); + it('renders custom data', async () => { const def = { content: [],