diff --git a/README.md b/README.md index 02c9bed4e..976211dcd 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,11 @@ +## Forked by [ADNSistemas](https://adnsistemas.com.ar) + +This fork was initially made to improve REMDRAs incremental update implementation, and was later merge with Cantoo-Scribe fork of pdf-lib, which has a number of improvements over original pdf-lib. + +Install with: `npm install @adnsistemas/pdf-lib` + +
+

pdf-lib @@ -15,19 +23,12 @@
- + NPM Version - - - CircleCI Build Status - Prettier Badge - - - Discord Badge - + + Coverage Status

@@ -50,11 +46,15 @@ ## Table of Contents +- [Important Changes](#changes) - [Features](#features) - [Motivation](#motivation) - [Usage Examples](#usage-examples) - [Create Document](#create-document) - [Modify Document](#modify-document) + - [Incremental Document Modification](#incremental-document-modification) + - [Consecutive Incremental Updates](#consecutive-incremental-updates) + - [Get Incremental Update Changed Objects](#get-modified-objects-in-incremental-update) - [Create Form](#create-form) - [Fill Form](#fill-form) - [Flatten Form](#flatten-form) @@ -63,11 +63,13 @@ - [Embed PDF Pages](#embed-pdf-pages) - [Embed Font and Measure Text](#embed-font-and-measure-text) - [Add Attachments](#add-attachments) + - [Extract Attachments](#extract-attachments) - [Set Document Metadata](#set-document-metadata) - [Read Document Metadata](#read-document-metadata) - [Set Viewer Preferences](#set-viewer-preferences) - [Read Viewer Preferences](#read-viewer-preferences) - [Draw SVG Paths](#draw-svg-paths) + - [Draw SVG](#draw-svg) - [Deno Usage](#deno-usage) - [Complete Examples](#complete-examples) - [Installation](#installation) @@ -85,10 +87,15 @@ - [Git History Rewrite](#git-history-rewrite) - [License](#license) +## Changes + +- 2026-03-24: version 2.9.0 replaced the use of ```instanceof``` by the function ```isPDFInstance()``` which allows the library to properly function in complex environments where code comes from more than a single pdf-lib package (issue detected on monorepos using Vertest). This makes the library more flexible, but slower than previous versions. + ## Features - Create new PDFs - Modify existing PDFs +- Modify existing PDFs with incremental updates (preserves original PDF, required for electronic/digital signatures) - Create forms - Fill forms - Flatten forms @@ -108,6 +115,9 @@ - Set viewer preferences - Read viewer preferences - Add attachments +- Extract attachments +- Delete attachments +- Get PDFObjects modified in a specific update of the PDF (used to check for changes between electronic/digital signatures) ## Motivation @@ -212,6 +222,296 @@ const pdfBytes = await pdfDoc.save() // • Rendered in an + + + + diff --git a/apps/web/test2.html b/apps/web/test2.html index 9ebcbc87c..e54ebb77f 100644 --- a/apps/web/test2.html +++ b/apps/web/test2.html @@ -1,4 +1,4 @@ - + + + + + + + + + Test 20 + + + + +
+ + + +
+ + + + + + diff --git a/apps/web/test21.html b/apps/web/test21.html new file mode 100644 index 000000000..84e275e3c --- /dev/null +++ b/apps/web/test21.html @@ -0,0 +1,122 @@ + + + + + + + + + Test 21 + + + + + +
+ + + +
+ + + + + + diff --git a/apps/web/test22.html b/apps/web/test22.html new file mode 100644 index 000000000..746259dc4 --- /dev/null +++ b/apps/web/test22.html @@ -0,0 +1,194 @@ + + + + + + + + + Test 22 + + + + + +
+ + + +
+ + + + + + diff --git a/apps/web/test23.html b/apps/web/test23.html new file mode 100644 index 000000000..8c5dde7a6 --- /dev/null +++ b/apps/web/test23.html @@ -0,0 +1,194 @@ + + + + + + + + + Test 23 + + + + + +
+ + + +
+ + + + + + diff --git a/apps/web/test24.html b/apps/web/test24.html new file mode 100644 index 000000000..b4780506a --- /dev/null +++ b/apps/web/test24.html @@ -0,0 +1,188 @@ + + + + + + + + + Test 24 + + + + + +
+ + + +
+ + + + + + diff --git a/apps/web/test25.html b/apps/web/test25.html new file mode 100644 index 000000000..3c46d653f --- /dev/null +++ b/apps/web/test25.html @@ -0,0 +1,177 @@ + + + + + + + + + Test 25 + + + + + +
+ + + +
+ + + + + + diff --git a/apps/web/test26.html b/apps/web/test26.html new file mode 100644 index 000000000..61d9526ba --- /dev/null +++ b/apps/web/test26.html @@ -0,0 +1,160 @@ + + + + + + + + + Test 26 - test rect cropping + + + + + +
+ + + +
+ + + + + + diff --git a/apps/web/test27.html b/apps/web/test27.html new file mode 100644 index 000000000..236285dd5 --- /dev/null +++ b/apps/web/test27.html @@ -0,0 +1,350 @@ + + + + + + + + + Test 27 - test rect cropping + + + + + +
+ + + +
+ + + + + + diff --git a/apps/web/test28.html b/apps/web/test28.html new file mode 100644 index 000000000..ff1bff9eb --- /dev/null +++ b/apps/web/test28.html @@ -0,0 +1,242 @@ + + + + + + + + + Test 28 - test matrix transform + + + + + +
+ + + +
+ + + + + + diff --git a/apps/web/test29.html b/apps/web/test29.html new file mode 100644 index 000000000..f778f7121 --- /dev/null +++ b/apps/web/test29.html @@ -0,0 +1,136 @@ + + + + + + + + + Test 29 - test matrix transform + + + + + +
+ + + +
+ + + + + + diff --git a/apps/web/test3.html b/apps/web/test3.html index 985198f0c..bfbd9a672 100644 --- a/apps/web/test3.html +++ b/apps/web/test3.html @@ -1,4 +1,4 @@ - + + + + + + + + + Test - Draw Rectangles with PDF-Lib + + + + + +
+ + + +
+ + + + diff --git a/apps/web/test31.html b/apps/web/test31.html new file mode 100644 index 000000000..38d8ef6f5 --- /dev/null +++ b/apps/web/test31.html @@ -0,0 +1,111 @@ + + + + + + + + + Test - Draw SVG with Text and TSpans using PDF-Lib + + + + + +
+ + + +
+ + + + diff --git a/apps/web/test32.html b/apps/web/test32.html new file mode 100644 index 000000000..0ba277bb6 --- /dev/null +++ b/apps/web/test32.html @@ -0,0 +1,286 @@ + + + + + + + + + Test 32 - Ellipse Drawing + + + + + + +
+ + + +
+
+ + + + + diff --git a/apps/web/test33.html b/apps/web/test33.html new file mode 100644 index 000000000..fb5f06efc --- /dev/null +++ b/apps/web/test33.html @@ -0,0 +1,80 @@ + + + + + + + + + Test 33 - PDF Incremental update + + + + + + +
+ + + +
+
+ + + + + diff --git a/apps/web/test34.html b/apps/web/test34.html new file mode 100644 index 000000000..ef49b2e02 --- /dev/null +++ b/apps/web/test34.html @@ -0,0 +1,239 @@ + + + + + + + + + Test 34 - PDF automatic incremental update + + + + + + +
+ + + +
+
+ + + + + diff --git a/apps/web/test4.html b/apps/web/test4.html index 0bdef58fd..71bdeb40f 100644 --- a/apps/web/test4.html +++ b/apps/web/test4.html @@ -1,4 +1,4 @@ - + + + +
-
+
diff --git a/apps/web/test8.html b/apps/web/test8.html index 251c2991d..2c865608f 100644 --- a/apps/web/test8.html +++ b/apps/web/test8.html @@ -1,4 +1,4 @@ - + + { + const slideRight = () => { moveTo(xCoord); xCoord += delta; @@ -18,7 +19,7 @@ function startFpsTracker(id) { } }; - const slideLeft = (timestamp) => { + const slideLeft = () => { moveTo(xCoord); xCoord -= delta; diff --git a/assets/pdfs/encrypted_literal_strings.pdf b/assets/pdfs/encrypted_literal_strings.pdf new file mode 100644 index 000000000..85a34e829 Binary files /dev/null and b/assets/pdfs/encrypted_literal_strings.pdf differ diff --git a/assets/pdfs/examples/incremental_document_modification.pdf b/assets/pdfs/examples/incremental_document_modification.pdf new file mode 100644 index 000000000..df1a37ed3 Binary files /dev/null and b/assets/pdfs/examples/incremental_document_modification.pdf differ diff --git a/assets/pdfs/invalid_xref.pdf b/assets/pdfs/invalid_xref.pdf new file mode 100644 index 000000000..72f3cee52 Binary files /dev/null and b/assets/pdfs/invalid_xref.pdf differ diff --git a/assets/pdfs/simple.pdf b/assets/pdfs/simple.pdf new file mode 100644 index 000000000..5ee9f757d Binary files /dev/null and b/assets/pdfs/simple.pdf differ diff --git a/assets/pdfs/simple_streams.pdf b/assets/pdfs/simple_streams.pdf new file mode 100644 index 000000000..3c5734cd2 Binary files /dev/null and b/assets/pdfs/simple_streams.pdf differ diff --git a/assets/pdfs/v15xref.pdf b/assets/pdfs/v15xref.pdf new file mode 100755 index 000000000..8cdf877de Binary files /dev/null and b/assets/pdfs/v15xref.pdf differ diff --git a/docs/MIGRATION.md b/docs/MIGRATION.md index eb0db27db..f3fbe424f 100644 --- a/docs/MIGRATION.md +++ b/docs/MIGRATION.md @@ -1,3 +1,43 @@ + +## From v1.x.x (>= v1.17.1) to v2.0.0 and above + +The latest release of `pdf-lib` (`v2.0.0`) introduced a breaking change in the API for drawSVG, making it asynchronous. You'll also need to manually embed the images that might be contained inside your svg file. + +### If your svg doesn't contain images + +To update your code, you just need to convert it into synchronous mode: + +```js +const svg = ` + + +`; +await pdfPage.drawSvg(svg) +``` + +Will become: + +```js +const svg = ` + + +`; +pdfPage.drawSvg(svg) +``` + +### If your svg might contain an image + +To update your code, you must call embedSvg first + +```js +const svg = '' +const pdfSvg = await pdfDoc.embedSvg(svg) +pdfPage.drawSvg(pdfSvg) +``` + + +## From v0.x.x to v1.0.0 and above + The latest release of `pdf-lib` (`v1.0.0`) includes several breaking API changes. If you have code written for older versions of `pdf-lib` (`v0.x.x`), you can use the following instructions to help migrate your code to v1.0.0. Note that many of the API methods are now asynchronous and return promises, so you'll need to `await` on them (or use promise chaining: `.then(res => ...)`). diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 000000000..aa0f44185 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,89 @@ +/*eslint no-undef: "off"*/ +const eslint = require('@eslint/js'); +const tseslint = require('@typescript-eslint/eslint-plugin'); +const tsparser = require('@typescript-eslint/parser'); +const prettier = require('eslint-plugin-prettier'); +const globals = require('globals'); + +module.exports = [ + eslint.configs.recommended, + { + files: ['src/**/*.{ts,tsx,js,jsx,mjs}','tests/**/*.{ts,tsx,js,jsx,mjs}','apps/**/*.{ts,tsx,js,jsx,mjs}'], + languageOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + parser: tsparser, + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + }, + globals: { + ...globals.browser, + ...globals.node, + ...globals.es2021, + ...globals.jest, + process: 'readonly', + }, + }, + plugins: { + '@typescript-eslint': tseslint, + prettier: prettier, + }, + rules: { + 'prettier/prettier': [ + 'error', + { + singleQuote: true, + trailingComma: 'all', + semi: true, + }, + ], + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/no-explicit-any': 'warn', + '@typescript-eslint/no-unused-vars': [ + 'error', + { + argsIgnorePattern: '^_', + varsIgnorePattern: '^(_|unused|UNUSED)', + ignoreRestSiblings: true, + }, + ], + 'no-console': 'off', + 'no-empty-interface': 'off', + '@typescript-eslint/no-empty-interface': 'off', + 'prefer-const': 'error', + 'no-var': 'error', + eqeqeq: ['error', 'always'], + 'no-unused-vars': 'off', + 'no-dupe-class-members': 'off', + 'no-undef': 'off', + }, + }, + { + files: [ + 'tests/**/*.{ts,tsx,js,jsx}', + '**/*.spec.{ts,tsx,js,jsx}', + '**/*.test.{ts,tsx,js,jsx}', + ], + rules: { + '@typescript-eslint/no-explicit-any': 'off', + 'quotes': 'off', + }, + }, + { + files: ['apps/rn/**/*.{ts,tsx,js,jsx,mjs}'], + languageOptions: { + globals: { + require: 'readonly', + }, + }, + }, + { + files: ['apps/deno/**/*.{ts,tsx,js,jsx,mjs}'], + languageOptions: { + globals: { + Deno: 'readonly', + }, + }, + } +]; diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 000000000..a315a9342 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,28 @@ +/*eslint no-undef: "off"*/ +module.exports = { + // Base configuration + preset: 'ts-jest', + testEnvironment: 'node', + + // TypeScript transformation + transform: { + '^.+\\.tsx?$': 'ts-jest', + }, + + // Test pattern matching + testMatch: ['/tests/**/*.spec.ts'], + + // Source directories + roots: ['src', 'tests'], + + // Module resolution + moduleNameMapper: { + '^src/(.*)$': '/src/$1', + }, + + // Supported file extensions + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], + + // Coverage reporting + coverageReporters: ['html','lcov'], +}; diff --git a/jest.json b/jest.json deleted file mode 100644 index 75c7dbf24..000000000 --- a/jest.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "preset": "ts-jest", - "testEnvironment": "node", - "coverageReporters": ["html"], - "testMatch": ["/tests/**/*.spec.ts"], - "roots": ["src", "tests"], - "moduleNameMapper": { - "^src/(.*)$": "/src/$1" - } -} diff --git a/package.json b/package.json index 090b03eac..622209f94 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,16 @@ { - "name": "pdf-lib", - "version": "1.17.1", + "name": "@adnsistemas/pdf-lib", + "version": "2.9.1", "description": "Create and modify PDF files with JavaScript", "author": "Andrew Dillon ", + "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e", + "exports": { + ".": { + "types": "./cjs/index.d.ts", + "require": "./cjs/index.js", + "import": "./es/index.js" + } + }, "contributors": [ "jerp (https://github.com/jerp)", "Greg Bacchus (https://github.com/gregbacchus)", @@ -29,37 +37,44 @@ "Bj Tecu (https://github.com/btecu)", "Brent McSharry (https://github.com/mcshaz)", "Tim Knapp (https://github.com/duffyd)", - "Ching Chang (https://github.com/ChingChang9)" + "Ching Chang (https://github.com/ChingChang9)", + "François Billioud (https://github.com/Sharcoux)", + "Phakorn Kiong (https://github.com/PhakornKiong)", + "Donald Ness (https://github.com/programmarchy)", + "Remus DRAICA (https://github.com/remdra)", + "David Abdala (https://github.com/adnsistemas)", + "Eran Ohayon (https://github.com/erano067)", + "Shaun Verch (https://github.com/sverch)", + "Guido Flohr (https://github.com/gflohr)" ], "scripts": { - "release:latest": "yarn publish --tag latest && yarn pack && yarn release:tag", - "release:next": "yarn publish --tag next", - "release:prep": "yarn clean && yarn lint && yarn typecheck && yarn test && yarn build", - "release:tag": "TAG=\"v$(yarn --silent get:version)\" && git tag $TAG && git push origin $TAG", + "release": "yarn release:prep && release-it", + "release:prep": "yarn clean && yarn lint && yarn typecheck && yarn test && yarn build && coveralls report", "get:version": "node --eval 'console.log(require(`./package.json`).version)'", "clean": "rimraf ts3.4 build cjs dist es scratchpad/build coverage tsBuildInfo.json apps/node-build apps/node/tsBuildInfo.json isolate*.log flamegraph.html out.pdf", "typecheck": "tsc --noEmit --incremental false --tsBuildInfoFile null", - "test": "jest --config jest.json --runInBand", - "testw": "jest --config jest.json --watch", - "testc": "jest --config jest.json --coverage && open coverage/index.html", - "lint": "yarn lint:prettier && yarn lint:tslint:src && yarn lint:tslint:tests", - "lint:tslint:src": "tslint --project tsconfig.json --fix", - "lint:tslint:tests": "tslint --project tests/tsconfig.json --fix", - "lint:prettier": "prettier --write \"./{src,tests,apps}/**/*.{ts,js,json,html,css}\" --loglevel error", + "test": "jest --config jest.config.js --runInBand --coverage", + "testw": "jest --config jest.config.js --watch", + "testc": "jest --config jest.config.js --coverage && open coverage/index.html", + "lint-staged": "lint-staged", + "lint": "yarn clean && yarn lint:prettier && yarn lint:eslint", + "lint:eslint": "eslint .", + "lint:prettier": "prettier --write \"./{src,tests,apps}/**/*.{ts,js,json,html,css}\" --log-level error", "build": "yarn build:cjs && yarn build:es && yarn build:esm && yarn build:esm:min && yarn build:umd && yarn build:umd:min && yarn build:downlevel-dts", - "build:cjs": "ttsc --module commonjs --outDir cjs", - "build:es": "ttsc --module ES2015 --outDir es", - "build:esm": "rollup --config rollup.config.js --file dist/pdf-lib.esm.js --environment MODULE_TYPE:es", - "build:esm:min": "rollup --config rollup.config.js --file dist/pdf-lib.esm.min.js --environment MINIFY,MODULE_TYPE:es", - "build:umd": "rollup --config rollup.config.js --file dist/pdf-lib.js --environment MODULE_TYPE:umd", - "build:umd:min": "rollup --config rollup.config.js --file dist/pdf-lib.min.js --environment MINIFY,MODULE_TYPE:umd", + "build:cjs": "tsc --module commonjs --outDir cjs", + "build:es": "tsc --module ES2015 --outDir es && node ./scripts/es-build.js", + "build:esm": "rollup --config rollup.config.mjs --file dist/pdf-lib.esm.js --environment MODULE_TYPE:es", + "build:esm:min": "rollup --config rollup.config.mjs --file dist/pdf-lib.esm.min.js --environment MINIFY,MODULE_TYPE:es", + "build:umd": "rollup --config rollup.config.mjs --file dist/pdf-lib.js --environment MODULE_TYPE:umd", + "build:umd:min": "rollup --config rollup.config.mjs --file dist/pdf-lib.min.js --environment MINIFY,MODULE_TYPE:umd", "build:downlevel-dts": "rimraf ts3.4 && yarn downlevel-dts . ts3.4 && rimraf ts3.4/scratchpad", - "scratchpad:start": "ttsc --build scratchpad/tsconfig.json --watch", + "build:test": "yarn build:es && yarn build:umd", + "scratchpad:start": "tsc --build scratchpad/tsconfig.json --watch", "scratchpad:run": "node scratchpad/build/scratchpad/index.js", "scratchpad:flame": "rimraf isolate*.log && node --prof scratchpad/build/scratchpad/index.js && node --prof-process --preprocess -j isolate*.log | flamebearer", - "apps:node": "ttsc --build apps/node/tsconfig.json && node apps/node-build/index.js", + "apps:node": "tsc --build apps/node/tsconfig.json && node apps/node-build/index.js", "apps:deno": "deno run --allow-read --allow-write --allow-run apps/deno/index.ts", - "apps:web": "http-server -c-1 .", + "apps:web": "http-server -c-1 -o apps/web/test1.html", "apps:web:mac": "bash -c 'sleep 1 && open http://localhost:8080/apps/web/test1.html' & yarn apps:web", "apps:rn:ios": "cd apps/rn && yarn add ./../.. --force && react-native run-ios", "apps:rn:android": "yarn apps:rn:emulator & cd apps/rn && yarn add ./../.. --force && react-native run-android", @@ -88,41 +103,52 @@ "yarn.lock" ], "dependencies": { + "@adnsistemas/upng": "^1.0.3", "@pdf-lib/standard-fonts": "^1.0.0", - "@pdf-lib/upng": "^1.0.1", + "color": "^4.2.3", + "crypto-js": "^4.2.0", + "node-html-better-parser": "^1.4.0", "pako": "^1.0.11", - "tslib": "^1.11.1" + "tslib": ">=2" }, "devDependencies": { + "@eslint/js": "^8.56.0", "@pdf-lib/fontkit": "^1.1.0", - "@rollup/plugin-commonjs": "^13.0.0", - "@rollup/plugin-json": "^4.1.0", - "@rollup/plugin-node-resolve": "^8.0.1", - "@types/jest": "^26.0.0", + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-json": "^6.1.0", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-terser": "^0.4.4", + "@types/color": "^3.0.1", + "@types/crypto-js": "^4.2.2", + "@types/jest": "^29.5.12", "@types/node-fetch": "^2.5.7", "@types/pako": "^1.0.1", - "@zerollup/ts-transform-paths": "^1.7.18", - "downlevel-dts": "^0.5.0", + "@typescript-eslint/eslint-plugin": "^7.0.0", + "@typescript-eslint/parser": "^7.0.0", + "downlevel-dts": "^0.11.0", + "eslint": "^8.56.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.1.3", "flamebearer": "^1.1.3", - "http-server": "^0.12.3", - "jest": "^26.0.1", - "node-fetch": "^2.6.0", - "prettier": "^2.0.5", - "rimraf": "^3.0.2", - "rollup": "^2.17.1", - "rollup-plugin-terser": "^6.1.0", - "ts-jest": "^26.1.0", - "tslint": "^6.1.2", - "tslint-config-prettier": "^1.18.0", - "ttypescript": "^1.5.10", - "typescript": "^3.9.5" + "globals": "^14.0.0", + "http-server": "^14.1.1", + "husky": "4", + "jest": "29.7.0", + "lint-staged": "^15.5.0", + "node-fetch": "^3.3.2", + "prettier": "^3.2.5", + "release-it": "^17.0.3", + "rimraf": "^5.0.5", + "rollup": "^4.9.6", + "ts-jest": "^29.0", + "typescript": "^4.9.5" }, "license": "MIT", "private": false, "homepage": "https://pdf-lib.js.org", - "repository": "git+https://github.com/Hopding/pdf-lib.git", + "repository": "git+https://github.com/adnsistemas/pdf-lib.git", "bugs": { - "url": "https://github.com/Hopding/pdf-lib/issues" + "url": "https://github.com/adnsistemas/pdf-lib/issues" }, "keywords": [ "pdf-lib", @@ -137,5 +163,22 @@ "typescript", "javascript", "library" - ] + ], + "lint-staged": { + "{src,tests,apps}/**/*.{ts,js,json,html,css}": [ + "prettier --check", + "eslint --fix" + ] + }, + "husky": { + "hooks": { + "pre-commit": "lint-staged" + } + }, + "npm": { + "publish": false + }, + "publishConfig": { + "registry": "https://registry.npmjs.org" + } } diff --git a/rollup.config.js b/rollup.config.mjs similarity index 95% rename from rollup.config.js rename to rollup.config.mjs index 5964f6c0e..80e737331 100644 --- a/rollup.config.js +++ b/rollup.config.mjs @@ -1,9 +1,8 @@ +/*eslint no-undef: "off"*/ import resolve from '@rollup/plugin-node-resolve'; import commonjs from '@rollup/plugin-commonjs'; import json from '@rollup/plugin-json'; -import { terser } from 'rollup-plugin-terser'; - -const { MINIFY, MODULE_TYPE } = process.env; +import terser from '@rollup/plugin-terser'; const IgnoredWarnings = [ // Mac & Linux @@ -50,8 +49,13 @@ export default { input: 'es/index.js', output: { name: 'PDFLib', - format: MODULE_TYPE, + format: process.env.MODULE_TYPE, sourcemap: true, }, - plugins: [resolve(), commonjs(), json(), MINIFY === 'true' && terser()], + plugins: [ + resolve(), + commonjs(), + json(), + process.env.MINIFY === 'true' && terser(), + ], }; diff --git a/scratchpad/index.ts b/scratchpad/index.ts index 370b95030..832753fa9 100644 --- a/scratchpad/index.ts +++ b/scratchpad/index.ts @@ -1,6 +1,6 @@ import fs from 'fs'; import { openPdf, Reader } from './open'; -import { PDFDocument } from 'src/index'; +import { PDFDocument } from '../src/index'; (async () => { const pdfDoc1 = await PDFDocument.create(); diff --git a/scratchpad/open.ts b/scratchpad/open.ts index 87cb23ed9..3a0378c56 100644 --- a/scratchpad/open.ts +++ b/scratchpad/open.ts @@ -13,8 +13,10 @@ export const openPdf = (path: string, reader = Reader.Preview) => { if (process.platform === 'darwin') { execSync(`open -a "${reader}" ${path}`); } else { - const msg1 = `Note: Automatically opening PDFs currently only works on Macs. If you're using a Windows or Linux machine, please consider contributing to expand support for this feature`; - const msg2 = `(https://github.com/Hopding/pdf-lib/blob/master/apps/node/index.ts#L8-L17)\n`; + const msg1 = + "Note: Automatically opening PDFs currently only works on Macs. If you're using a Windows or Linux machine, please consider contributing to expand support for this feature"; + const msg2 = + '(https://github.com/Hopding/pdf-lib/blob/master/apps/node/index.ts#L8-L17)\n'; console.warn(msg1); console.warn(msg2); } diff --git a/scripts/es-build.js b/scripts/es-build.js new file mode 100644 index 000000000..e2a712c09 --- /dev/null +++ b/scripts/es-build.js @@ -0,0 +1,48 @@ +/*eslint no-undef: "off"*/ +const fs = require('fs'); +const path = require('path'); + +const walk = (dir) => { + let results = []; + const list = fs.readdirSync(dir); + list.forEach((file) => { + file = path.join(dir, file); + const stat = fs.statSync(file); + if (stat && stat.isDirectory()) { + results = results.concat(walk(file)); + } else { + results.push(file); + } + }); + return results; +}; + +const files = walk('./es'); // Adjust the path if needed + +files.forEach((file) => { + if (file.endsWith('.js')) { + let content = fs.readFileSync(file, 'utf-8'); + content = content.replace(/from '(.+?)'/g, (match, p1) => { + // If it's an absolute path, a module or URL, or it already ends with .js, don't change it + if (!p1.startsWith('.') || p1.endsWith('.js')) { + return match; + } + // If it's referencing a directory (implying index.js inside that directory) + if ( + fs.existsSync(path.join(path.dirname(file), p1)) && + fs.statSync(path.join(path.dirname(file), p1)).isDirectory() + ) { + return `from '${p1}/index.js'`; + } + // Otherwise, append .js + return `from '${p1}.js'`; + }); + fs.writeFileSync(file, content); + } +}); + +// Write the package.json file in the es directory +fs.writeFileSync( + './es/package.json', + JSON.stringify({ type: 'module' }, null, 2), +); diff --git a/src/api/PDFDocument.ts b/src/api/PDFDocument.ts index e102368e2..7ad3c3fd4 100644 --- a/src/api/PDFDocument.ts +++ b/src/api/PDFDocument.ts @@ -1,26 +1,35 @@ -import Embeddable from 'src/api/Embeddable'; +import { + parse as parseHtml, + HTMLElement, + NodeType, +} from 'node-html-better-parser'; +import Embeddable from './Embeddable'; import { EncryptedPDFError, FontkitNotRegisteredError, ForeignPageError, RemovePageFromEmptyDocumentError, -} from 'src/api/errors'; -import PDFEmbeddedPage from 'src/api/PDFEmbeddedPage'; -import PDFFont from 'src/api/PDFFont'; -import PDFImage from 'src/api/PDFImage'; -import PDFPage from 'src/api/PDFPage'; -import PDFForm from 'src/api/form/PDFForm'; -import { PageSizes } from 'src/api/sizes'; -import { StandardFonts } from 'src/api/StandardFonts'; +} from './errors'; +import PDFEmbeddedPage from './PDFEmbeddedPage'; +import PDFFont from './PDFFont'; +import PDFImage from './PDFImage'; +import PDFPage from './PDFPage'; +import PDFForm from './form/PDFForm'; +import { PageSizes } from './sizes'; +import { StandardFonts } from './StandardFonts'; import { CustomFontEmbedder, CustomFontSubsetEmbedder, JpegEmbedder, PageBoundingBox, PageEmbeddingMismatchedContextError, + PDFArray, PDFCatalog, PDFContext, PDFDict, + decodePDFRawStream, + PDFStream, + PDFRawStream, PDFHexString, PDFName, PDFObjectCopier, @@ -34,7 +43,7 @@ import { PngEmbedder, StandardFontEmbedder, UnexpectedObjectTypeError, -} from 'src/core'; +} from '../core'; import { ParseSpeeds, AttachmentOptions, @@ -44,11 +53,12 @@ import { CreateOptions, EmbedFontOptions, SetTitleOptions, -} from 'src/api/PDFDocumentOptions'; -import PDFObject from 'src/core/objects/PDFObject'; -import PDFRef from 'src/core/objects/PDFRef'; -import { Fontkit } from 'src/types/fontkit'; -import { TransformationMatrix } from 'src/types/matrix'; + IncrementalSaveOptions, +} from './PDFDocumentOptions'; +import PDFObject from '../core/objects/PDFObject'; +import PDFRef from '../core/objects/PDFRef'; +import { Fontkit } from '../types/fontkit'; +import { TransformationMatrix } from '../types/matrix'; import { assertIs, assertIsOneOfOrUndefined, @@ -61,11 +71,44 @@ import { pluckIndices, range, toUint8Array, -} from 'src/utils'; -import FileEmbedder, { AFRelationship } from 'src/core/embedders/FileEmbedder'; -import PDFEmbeddedFile from 'src/api/PDFEmbeddedFile'; -import PDFJavaScript from 'src/api/PDFJavaScript'; -import JavaScriptEmbedder from 'src/core/embedders/JavaScriptEmbedder'; +} from '../utils'; +import FileEmbedder, { AFRelationship } from '../core/embedders/FileEmbedder'; +import PDFEmbeddedFile from './PDFEmbeddedFile'; +import PDFJavaScript from './PDFJavaScript'; +import JavaScriptEmbedder from '../core/embedders/JavaScriptEmbedder'; +import { CipherTransformFactory } from '../core/crypto'; +import PDFSvg from './PDFSvg'; +import PDFSecurity, { SecurityOptions } from '../core/security/PDFSecurity'; +import { IncrementalDocumentSnapshot } from './snapshot'; +import type { DocumentSnapshot } from './snapshot'; +import { isPDFInstance, PDFClasses } from './objects'; + +export type BasePDFAttachment = { + name: string; + data: Uint8Array; + mimeType: string | undefined; + afRelationship: AFRelationship | undefined; + description: string | undefined; + creationDate: Date | undefined; + modificationDate: Date | undefined; +}; + +export type SavedPDFAttachment = BasePDFAttachment & { + embeddedFileDict: PDFDict; + specRef: PDFRef; +}; + +export type UnsavedPDFAttachment = BasePDFAttachment & { + pdfEmbeddedFile: PDFEmbeddedFile; +}; + +export type PDFAttachment = UnsavedPDFAttachment | SavedPDFAttachment; + +export type PDFObjectVersions = { + ref: PDFRef; + actual: PDFObject | undefined; + previous: PDFObject[]; +}; /** * Represents a PDF document. @@ -131,23 +174,63 @@ export default class PDFDocument { ignoreEncryption = false, parseSpeed = ParseSpeeds.Slow, throwOnInvalidObject = false, + warnOnInvalidObjects = false, updateMetadata = true, capNumbers = false, + password, + forIncrementalUpdate = false, + preserveObjectsVersions = false, } = options; assertIs(pdf, 'pdf', ['string', Uint8Array, ArrayBuffer]); assertIs(ignoreEncryption, 'ignoreEncryption', ['boolean']); assertIs(parseSpeed, 'parseSpeed', ['number']); assertIs(throwOnInvalidObject, 'throwOnInvalidObject', ['boolean']); + assertIs(warnOnInvalidObjects, 'warnOnInvalidObjects', ['boolean']); + assertIs(password, 'password', ['string', 'undefined']); + assertIs(forIncrementalUpdate, 'forIncrementalUpdate', ['boolean']); + assertIs(preserveObjectsVersions, 'preserveObjectsVersions', ['boolean']); const bytes = toUint8Array(pdf); const context = await PDFParser.forBytesWithOptions( bytes, parseSpeed, throwOnInvalidObject, + undefined, capNumbers, + undefined, + forIncrementalUpdate, + preserveObjectsVersions, ).parseDocument(); - return new PDFDocument(context, ignoreEncryption, updateMetadata); + if ( + !!context.lookup(context.trailerInfo.Encrypt) && + password !== undefined + ) { + // Decrypt + const fileIds = context.lookup(context.trailerInfo.ID, PDFArray); + const encryptDict = context.lookup(context.trailerInfo.Encrypt, PDFDict); + const decryptedContext = await PDFParser.forBytesWithOptions( + bytes, + parseSpeed, + throwOnInvalidObject, + warnOnInvalidObjects, + capNumbers, + new CipherTransformFactory( + encryptDict, + (fileIds.get(0) as PDFHexString).asBytes(), + password, + ), + forIncrementalUpdate, + preserveObjectsVersions, + ).parseDocument(); + const pdfDoc = new PDFDocument(decryptedContext, true, updateMetadata); + if (forIncrementalUpdate) pdfDoc.takeSnapshot(); + return pdfDoc; + } else { + const pdfDoc = new PDFDocument(context, ignoreEncryption, updateMetadata); + if (forIncrementalUpdate) pdfDoc.takeSnapshot(); + return pdfDoc; + } } /** @@ -165,6 +248,11 @@ export default class PDFDocument { return new PDFDocument(context, false, updateMetadata); } + static className = () => PDFClasses.PDFDocument; + + myClass(): PDFClasses { + return PDFClasses.PDFDocument; + } /** The low-level context of this document. */ readonly context: PDFContext; @@ -199,6 +287,11 @@ export default class PDFDocument { this.context = context; this.catalog = context.lookup(context.trailerInfo.Root) as PDFCatalog; + + if (!!context.lookup(context.trailerInfo.Encrypt) && context.isDecrypted) { + // context.delete(context.trailerInfo.Encrypt); + delete context.trailerInfo.Encrypt; + } this.isEncrypted = !!context.lookup(context.trailerInfo.Encrypt); this.pageCache = Cache.populatedBy(this.computePages); @@ -352,6 +445,22 @@ export default class PDFDocument { return producer.decodeText(); } + /** + * Get this document's language metadata. The language appears in the + * "Document Properties" section of most PDF readers. For example: + * ```js + * const language = pdfDoc.getLanguage() + * ``` + * @returns A string containing the RFC 3066 _Language-Tag_ of this document, + * if it has one. + */ + getLanguage(): string | undefined { + const language = this.catalog.get(PDFName.of('Lang')); + if (!language) return undefined; + assertIsLiteralOrHexString(language); + return language.decodeText(); + } + /** * Get this document's creation date metadata. The creation date appears in * the "Document Properties" section of most PDF readers. For example: @@ -606,8 +715,10 @@ export default class PDFDocument { const pageCount = this.getPageCount(); if (this.pageCount === 0) throw new RemovePageFromEmptyDocumentError(); assertRange(index, 'index', 0, pageCount - 1); + const page = this.getPage(index); this.catalog.removeLeafNode(index); this.pageCount = pageCount - 1; + this.context.delete(page.ref); } /** @@ -725,14 +836,14 @@ export default class PDFDocument { await srcDoc.flush(); const copier = PDFObjectCopier.for(srcDoc.context, this.context); const srcPages = srcDoc.getPages(); - const copiedPages: PDFPage[] = new Array(indices.length); - for (let idx = 0, len = indices.length; idx < len; idx++) { - const srcPage = srcPages[indices[idx]]; - const copiedPage = copier.copy(srcPage.node); - const ref = this.context.register(copiedPage); - copiedPages[idx] = PDFPage.of(copiedPage, ref, this); - } - return copiedPages; + // Copy each page in a separate thread + const copiedPages = indices + .map((i) => srcPages[i]) + .map(async (page) => copier.copy(page.node)) + .map((p) => + p.then((copy) => PDFPage.of(copy, this.context.register(copy), this)), + ); + return Promise.all(copiedPages); } /** @@ -766,6 +877,9 @@ export default class PDFDocument { if (this.getCreator() !== undefined) { pdfCopy.setCreator(this.getCreator()!); } + if (this.getLanguage() !== undefined) { + pdfCopy.setLanguage(this.getLanguage()!); + } if (this.getModificationDate() !== undefined) { pdfCopy.setModificationDate(this.getModificationDate()!); } @@ -900,6 +1014,173 @@ export default class PDFDocument { this.embeddedFiles.push(embeddedFile); } + private getRawAttachments() { + if (!this.catalog.has(PDFName.of('Names'))) return []; + const Names = this.catalog.lookup(PDFName.of('Names'), PDFDict); + + if (!Names.has(PDFName.of('EmbeddedFiles'))) return []; + const EmbeddedFiles = Names.lookup(PDFName.of('EmbeddedFiles'), PDFDict); + + if (!EmbeddedFiles.has(PDFName.of('Names'))) return []; + const EFNames = EmbeddedFiles.lookup(PDFName.of('Names'), PDFArray); + + const rawAttachments = []; + for (let idx = 0, len = EFNames.size(); idx < len; idx += 2) { + const fileName = EFNames.lookup(idx) as PDFHexString | PDFString; + const fileSpec = EFNames.lookup(idx + 1, PDFDict); + rawAttachments.push({ + fileName, + fileSpec, + specRef: EFNames.get(idx + 1) as PDFRef, + }); + } + + return rawAttachments; + } + + private getSavedAttachments(): SavedPDFAttachment[] { + const rawAttachments = this.getRawAttachments(); + return rawAttachments.flatMap(({ fileName, fileSpec, specRef }) => { + const efDict = fileSpec.lookup(PDFName.of('EF')); + if (!isPDFInstance(efDict, PDFClasses.PDFDict)) return []; + + const stream = (efDict as PDFDict).lookup(PDFName.of('F')); + if (!isPDFInstance(stream, PDFClasses.PDFStream)) return []; + + const afr = fileSpec.lookup(PDFName.of('AFRelationship')); + const afRelationship = isPDFInstance(afr, PDFClasses.PDFName) + ? (afr as PDFName).toString().slice(1) // Remove leading slash + : isPDFInstance(afr, PDFClasses.PDFString) + ? (afr as PDFString).decodeText() + : undefined; + + const embeddedFileDict = (stream as PDFStream).dict; + const subtype = embeddedFileDict.lookup(PDFName.of('Subtype')); + + const mimeType = isPDFInstance(subtype, PDFClasses.PDFName) + ? (subtype as PDFName).toString().slice(1) + : isPDFInstance(subtype, PDFClasses.PDFString) + ? (subtype as PDFString).decodeText() + : undefined; + + const paramsDict = embeddedFileDict.lookup(PDFName.of('Params'), PDFDict); + + let creationDate: Date | undefined; + let modificationDate: Date | undefined; + + if (isPDFInstance(paramsDict, PDFClasses.PDFDict)) { + const creationDateRaw = paramsDict.lookup(PDFName.of('CreationDate')); + const modDateRaw = paramsDict.lookup(PDFName.of('ModDate')); + + if (isPDFInstance(creationDateRaw, PDFClasses.PDFString)) { + creationDate = (creationDateRaw as PDFString).decodeDate(); + } + + if (isPDFInstance(modDateRaw, PDFClasses.PDFString)) { + modificationDate = (modDateRaw as PDFString).decodeDate(); + } + } + + const descRaw = fileSpec.lookup(PDFName.of('Desc')); + let description: string | undefined; + + if (isPDFInstance(descRaw, PDFClasses.PDFHexString)) { + description = (descRaw as PDFHexString).decodeText(); + } + + return [ + { + name: fileName.decodeText(), + data: decodePDFRawStream(stream as PDFRawStream).decode(), + mimeType: mimeType?.replace(/#([0-9A-Fa-f]{2})/g, (_, hex) => + String.fromCharCode(parseInt(hex, 16)), + ), + afRelationship: afRelationship as AFRelationship, + description, + creationDate, + modificationDate, + embeddedFileDict: efDict as PDFDict, + specRef, + }, + ]; + }); + } + + private getUnsavedAttachments(): UnsavedPDFAttachment[] { + const attachments = this.embeddedFiles.flatMap((file) => { + if (file.getAlreadyEmbedded()) return []; + const embedder = file.getEmbedder(); + + return { + name: embedder.fileName, + data: embedder.getFileData(), + description: embedder.options.description, + mimeType: embedder.options.mimeType, + afRelationship: embedder.options.afRelationship, + creationDate: embedder.options.creationDate, + modificationDate: embedder.options.modificationDate, + pdfEmbeddedFile: file, + }; + }); + + return attachments; + } + + /** + * Get all attachments that are embedded in this document. + * + * @returns Array of attachments with name and data + */ + getAttachments(): PDFAttachment[] { + const savedAttachments = this.getSavedAttachments(); + const unsavedAttachments = this.getUnsavedAttachments(); + + return [...savedAttachments, ...unsavedAttachments]; + } + + /** + * Removes an attachment from PDF, based on name. + * @param {string} name Name of the attachmet to remove. + */ + detach(name: string) { + const attachedFiles = this.getAttachments(); + attachedFiles.forEach((file) => { + if (file.name !== name) return; + // the file wasn't embedded into context yet + if ('pdfEmbeddedFile' in file) { + const i = this.embeddedFiles.findIndex( + (f) => file.pdfEmbeddedFile === f, + ); + if (i !== undefined) this.embeddedFiles.splice(i, 1); + } else { + // remove references from catalog + const namesArr = this.catalog + .Names() + ?.lookup(PDFName.of('EmbeddedFiles'), PDFDict) + .lookup(PDFName.of('Names'), PDFArray); + const iNames = namesArr?.indexOf(file.specRef); + if (iNames !== undefined && iNames > 0) { + // attachment spec ref + namesArr?.remove(iNames); + // attachment name + namesArr?.remove(iNames - 1); + } + // AF-Tag for PDF-A3 compliance + const AF = this.catalog.AttachedFiles(); + const afIndex = AF?.indexOf(file.specRef); + if (afIndex !== undefined) AF?.remove(afIndex); + + // remove references from context + const streamRef = this.context + .lookupMaybe(file.specRef, PDFDict) + ?.lookupMaybe(PDFName.of('EF'), PDFDict) + ?.get(PDFName.of('F')) as PDFRef | undefined; + if (streamRef) this.context.delete(streamRef); + this.context.delete(file.specRef); + } + }); + } + /** * Embed a font into this document. The input data can be provided in multiple * formats: @@ -1077,6 +1358,36 @@ export default class PDFDocument { return pdfImage; } + async embedSvg(svg: string): Promise { + if (!svg) return new PDFSvg(svg); + const parsedSvg = parseHtml(svg); + const findImages = (element: HTMLElement): HTMLElement[] => { + if (element.tagName === 'image') return [element]; + else { + return element.childNodes + .map((child) => + child.nodeType === NodeType.ELEMENT_NODE ? findImages(child) : [], + ) + .flat(); + } + }; + const images = findImages(parsedSvg); + const imagesDict = {} as Record; + + await Promise.all( + images.map(async (image) => { + const href = image.attributes.href ?? image.attributes['xlink:href']; + if (!href || imagesDict[href]) return; + const isPng = href.match(/\.png(\?|$)|^data:image\/png;base64/gim); + const pdfImage = isPng + ? await this.embedPng(href) + : await this.embedJpg(href); + imagesDict[href] = pdfImage; + }), + ); + + return new PDFSvg(svg, imagesDict); + } /** * Embed one or more PDF pages into this document. * @@ -1109,10 +1420,11 @@ export default class PDFDocument { ]); assertIs(indices, 'indices', [Array]); - const srcDoc = - pdf instanceof PDFDocument ? pdf : await PDFDocument.load(pdf); + const srcDoc = isPDFInstance(pdf, PDFClasses.PDFDocument) + ? pdf + : await PDFDocument.load(pdf as string | Uint8Array | ArrayBuffer); - const srcPages = pluckIndices(srcDoc.getPages(), indices); + const srcPages = pluckIndices((srcDoc as PDFDocument).getPages(), indices); return this.embedPages(srcPages); } @@ -1230,6 +1542,10 @@ export default class PDFDocument { return embeddedPages; } + encrypt(options: SecurityOptions) { + this.context.security = PDFSecurity.create(this.context, options).encrypt(); + } + /** * > **NOTE:** You shouldn't need to call this method directly. The [[save]] * > and [[saveAsBase64]] methods will automatically ensure that all embedded @@ -1265,31 +1581,95 @@ export default class PDFDocument { * @returns Resolves with the bytes of the serialized document. */ async save(options: SaveOptions = {}): Promise { + // check PDF version + const vparts = this.context.header.getVersionString().split('.'); + const uOS = + options.rewrite || Number(vparts[0]) > 1 || Number(vparts[1]) >= 5; const { - useObjectStreams = true, - addDefaultPage = true, + useObjectStreams = uOS, objectsPerTick = 50, - updateFieldAppearances = true, + rewrite = false, } = options; assertIs(useObjectStreams, 'useObjectStreams', ['boolean']); - assertIs(addDefaultPage, 'addDefaultPage', ['boolean']); assertIs(objectsPerTick, 'objectsPerTick', ['number']); - assertIs(updateFieldAppearances, 'updateFieldAppearances', ['boolean']); - - if (addDefaultPage && this.getPageCount() === 0) this.addPage(); - - if (updateFieldAppearances) { - const form = this.formCache.getValue(); - if (form) form.updateFieldAppearances(); + assertIs(rewrite, 'rewrite', ['boolean']); + const incrementalUpdate = + !rewrite && + this.context.pdfFileDetails.originalBytes && + this.context.snapshot; + if (incrementalUpdate) { + options.addDefaultPage = false; + options.updateFieldAppearances = false; } - await this.flush(); + await this.prepareForSave(options); const Writer = useObjectStreams ? PDFStreamWriter : PDFWriter; + if (incrementalUpdate) { + const increment = await Writer.forContextWithSnapshot( + this.context, + objectsPerTick, + this.context.snapshot!, + ).serializeToBuffer(); + const result = new Uint8Array( + this.context.pdfFileDetails.originalBytes!.byteLength + + increment.byteLength, + ); + result.set(this.context.pdfFileDetails.originalBytes!); + result.set( + increment, + this.context.pdfFileDetails.originalBytes!.byteLength, + ); + return result; + } return Writer.forContext(this.context, objectsPerTick).serializeToBuffer(); } + /** + * Serialize only the changes to this document to an array of bytes making up a PDF file. + * For example: + * ```js + * const snapshot = pdfDoc.takeSnapshot(); + * ... + * const pdfBytes = await pdfDoc.saveIncremental(snapshot); + * ``` + * + * Similar to [[save]] function. + * The changes are saved in an incremental way, the result buffer + * will contain only the differences + * + * @param snapshot The snapshot to be used when saving the document. + * @param options The options to be used when saving the document. + * @returns Resolves with the bytes of the serialized document. + */ + async saveIncremental( + snapshot: DocumentSnapshot, + options: IncrementalSaveOptions = {}, + ): Promise { + // check PDF version + const vparts = this.context.header.getVersionString().split('.'); + const uOS = Number(vparts[0]) > 1 || Number(vparts[1]) >= 5; + const { objectsPerTick = 50 } = options; + + assertIs(objectsPerTick, 'objectsPerTick', ['number']); + + const saveOptions: SaveOptions = { + useObjectStreams: uOS, + ...options, + addDefaultPage: false, + updateFieldAppearances: false, + }; + await this.prepareForSave(saveOptions); + + const Writer = saveOptions.useObjectStreams ? PDFStreamWriter : PDFWriter; + return Writer.forContextWithSnapshot( + this.context, + objectsPerTick, + snapshot, + ).serializeToBuffer(); + } + /** * Serialize this document to a base64 encoded string or data URI making up a * PDF file. For example: @@ -1327,6 +1707,141 @@ export default class PDFDocument { return undefined; } + takeSnapshot(): DocumentSnapshot { + const indirectObjects: Set = new Set(); + + const snapshot = new IncrementalDocumentSnapshot( + this.context.largestObjectNumber, + indirectObjects, + this.context.pdfFileDetails.pdfSize, + this.context.pdfFileDetails.prevStartXRef, + this.context, + ); + if (!this.context.snapshot && this.context.pdfFileDetails.originalBytes) { + this.context.snapshot = snapshot; + this.catalog.registerChange(); + } + return snapshot; + } + + /** + * Returns the update version of the object as 'actual', and all the previous versions, of the objects + * that has changed in the indicated update (or the last one). + * If document wasn't load to preserve objects versions, an empty array is returned. + * @param {number} lastUpdateMinusX If not the last update, how many updates before the last. + * @returns {PDFObjectVersions[]} Objects modified in the update, and previous versions + */ + getChangedObjects(lastUpdateMinusX: number = 0): PDFObjectVersions[] { + if (!this.context.preserveObjectsVersions) return []; + if (lastUpdateMinusX < 0) lastUpdateMinusX = 0; + const upind = this.context.xrefs.length - lastUpdateMinusX - 1; + const entries = this.context.listXrefEntries(upind); + if (!entries.length) return []; + const changed = new Map(); + for (const entry of entries) { + const ref = entry.ref; + changed.set(ref.toString(), { + ref, + actual: entry.deleted ? undefined : this.context.lookup(ref), + previous: this.context.getObjectVersions(ref), + }); + } + // if not the las update, then check objects later modified and adjust PDFObjectVersions accordingly + if (!lastUpdateMinusX) return Array.from(changed.values()); + while (lastUpdateMinusX) { + lastUpdateMinusX -= 1; + const upind = this.context.xrefs.length - lastUpdateMinusX - 1; + const nentries = this.context.listXrefEntries(upind); + for (const nentry of nentries) { + const oce = changed.get(nentry.ref.toString()); + if (oce && oce.actual) { + oce.actual = oce.previous[0]; + oce.previous = oce.previous.slice(1); + } + } + } + // if PDF has errors, it may happen to end with objects that has no current, nor previous versions + return Array.from(changed.values()).filter( + (ov) => ov.actual || ov.previous.length, + ); + } + + /** + * Saves the current changes to the document as an incremental update, returns the full document, + * like save method, and modifies the internal state to be able to continue editing the document + * for another incremental update. + * This allows you to save multiple incremental updates without reloading the PDF. + * + * For example: + * ```js + * const pdfDoc = await PDFDocument.load(pdfBytes, { forIncrementalUpdate: true }) + * + * const page = pdfDoc.getPage(0) + * page.drawText('First update') + * const firstsave = await pdfDoc.saveAndContinue() + * + * page.drawText('Second update', { y: 100 }) + * const secondsave = await pdfDoc.saveAndContinue() + * ``` + * + * @param options The options to be used when saving changes. + * @returns Resolves with the complete PDF bytes including all updates. + */ + async saveAndContinue( + options: IncrementalSaveOptions = {}, + ): Promise { + if (!this.context.pdfFileDetails.originalBytes || !this.context.snapshot) { + throw new Error( + 'saveAndContinue() requires the document to be loaded with forIncrementalUpdate: true', + ); + } + const originalBytes = this.context.pdfFileDetails.originalBytes; + const incrementalBytes = await this.saveIncremental( + this.context.snapshot, + options, + ); + + const newPdfBytes = new Uint8Array( + originalBytes.byteLength + incrementalBytes.byteLength, + ); + newPdfBytes.set(originalBytes); + newPdfBytes.set(incrementalBytes, originalBytes.byteLength); + + this.context.pdfFileDetails.originalBytes = newPdfBytes; + this.context.pdfFileDetails.pdfSize = newPdfBytes.byteLength; + + const incrementalStr = new TextDecoder('latin1').decode(incrementalBytes); + const startxrefMatch = incrementalStr.match(/startxref\s+(\d+)/); + if (startxrefMatch) { + this.context.pdfFileDetails.prevStartXRef = parseInt( + startxrefMatch[1], + 10, + ); + } else { + this.context.pdfFileDetails.prevStartXRef = originalBytes.byteLength; + } + + this.context.snapshot = this.takeSnapshot(); + + return newPdfBytes; + } + + private async prepareForSave(options: SaveOptions): Promise { + const { addDefaultPage = true, updateFieldAppearances = true } = options; + + assertIs(addDefaultPage, 'addDefaultPage', ['boolean']); + assertIs(updateFieldAppearances, 'updateFieldAppearances', ['boolean']); + + if (addDefaultPage && this.getPageCount() === 0) this.addPage(); + + if (updateFieldAppearances) { + const form = this.formCache.getValue(); + if (form) form.updateFieldAppearances(); + } + + await this.flush(); + } + private async embedAll(embeddables: Embeddable[]): Promise { for (let idx = 0, len = embeddables.length; idx < len; idx++) { await embeddables[idx].embed(); @@ -1334,7 +1849,7 @@ export default class PDFDocument { } private updateInfoDict(): void { - const pdfLib = `pdf-lib (https://github.com/Hopding/pdf-lib)`; + const pdfLib = 'pdf-lib (https://github.com/Hopding/pdf-lib)'; const now = new Date(); const info = this.getInfoDict(); @@ -1348,7 +1863,9 @@ export default class PDFDocument { private getInfoDict(): PDFDict { const existingInfo = this.context.lookup(this.context.trailerInfo.Info); - if (existingInfo instanceof PDFDict) return existingInfo; + if (isPDFInstance(existingInfo, PDFClasses.PDFDict)) { + return existingInfo as PDFDict; + } const newInfo = this.context.obj({}); this.context.trailerInfo.Info = this.context.register(newInfo); @@ -1364,11 +1881,11 @@ export default class PDFDocument { private computePages = (): PDFPage[] => { const pages: PDFPage[] = []; this.catalog.Pages().traverse((node, ref) => { - if (node instanceof PDFPageLeaf) { - let page = this.pageMap.get(node); + if (isPDFInstance(node, PDFClasses.PDFPageLeaf)) { + let page = this.pageMap.get(node as PDFPageLeaf); if (!page) { - page = PDFPage.of(node, ref, this); - this.pageMap.set(node, page); + page = PDFPage.of(node as PDFPageLeaf, ref, this); + this.pageMap.set(node as PDFPageLeaf, page); } pages.push(page); } @@ -1387,8 +1904,8 @@ function assertIsLiteralOrHexString( pdfObject: PDFObject, ): asserts pdfObject is PDFHexString | PDFString { if ( - !(pdfObject instanceof PDFHexString) && - !(pdfObject instanceof PDFString) + !isPDFInstance(pdfObject, PDFClasses.PDFHexString) && + !isPDFInstance(pdfObject, PDFClasses.PDFString) ) { throw new UnexpectedObjectTypeError([PDFHexString, PDFString], pdfObject); } diff --git a/src/api/PDFDocumentOptions.ts b/src/api/PDFDocumentOptions.ts index fc6430d5d..c893552f8 100644 --- a/src/api/PDFDocumentOptions.ts +++ b/src/api/PDFDocumentOptions.ts @@ -1,5 +1,5 @@ -import { EmbeddedFileOptions } from 'src/core/embedders/FileEmbedder'; -import { TypeFeatures } from 'src/types/fontkit'; +import { EmbeddedFileOptions } from '../core/embedders/FileEmbedder'; +import { TypeFeatures } from '../types/fontkit'; export enum ParseSpeeds { Fastest = Infinity, @@ -15,6 +15,12 @@ export interface SaveOptions { addDefaultPage?: boolean; objectsPerTick?: number; updateFieldAppearances?: boolean; + rewrite?: boolean; +} + +export interface IncrementalSaveOptions { + objectsPerTick?: number; + useObjectStreams?: boolean; } export interface Base64SaveOptions extends SaveOptions { @@ -25,8 +31,12 @@ export interface LoadOptions { ignoreEncryption?: boolean; parseSpeed?: ParseSpeeds | number; throwOnInvalidObject?: boolean; + warnOnInvalidObjects?: boolean; updateMetadata?: boolean; capNumbers?: boolean; + password?: string; + forIncrementalUpdate?: boolean; + preserveObjectsVersions?: boolean; } export interface CreateOptions { diff --git a/src/api/PDFEmbeddedFile.ts b/src/api/PDFEmbeddedFile.ts index 556fdcb3c..51e734f5f 100644 --- a/src/api/PDFEmbeddedFile.ts +++ b/src/api/PDFEmbeddedFile.ts @@ -1,7 +1,7 @@ -import Embeddable from 'src/api/Embeddable'; -import PDFDocument from 'src/api/PDFDocument'; -import FileEmbedder from 'src/core/embedders/FileEmbedder'; -import { PDFName, PDFArray, PDFDict, PDFHexString, PDFRef } from 'src/core'; +import Embeddable from './Embeddable'; +import PDFDocument from './PDFDocument'; +import FileEmbedder from '../core/embedders/FileEmbedder'; +import { PDFName, PDFArray, PDFDict, PDFHexString, PDFRef } from '../core'; /** * Represents a file that has been embedded in a [[PDFDocument]]. @@ -87,4 +87,24 @@ export default class PDFEmbeddedFile implements Embeddable { this.alreadyEmbedded = true; } } + + /** + * Get the embedder used to embed the file. + * @returns the embedder. + */ + getEmbedder() { + return this.embedder; + } + + /** + * Returns whether or not this file has already been embedded. + * @returns true if the file has already been embedded, false otherwise. + */ + getAlreadyEmbedded() { + return this.alreadyEmbedded; + } + + getRef() { + return this.ref; + } } diff --git a/src/api/PDFEmbeddedPage.ts b/src/api/PDFEmbeddedPage.ts index 9766f6a6a..4ea9d406c 100644 --- a/src/api/PDFEmbeddedPage.ts +++ b/src/api/PDFEmbeddedPage.ts @@ -1,7 +1,7 @@ -import Embeddable from 'src/api/Embeddable'; -import PDFDocument from 'src/api/PDFDocument'; -import { PDFPageEmbedder, PDFRef } from 'src/core'; -import { assertIs } from 'src/utils'; +import Embeddable from './Embeddable'; +import PDFDocument from './PDFDocument'; +import { PDFPageEmbedder, PDFRef } from '../core'; +import { assertIs } from '../utils'; /** * Represents a PDF page that has been embedded in a [[PDFDocument]]. diff --git a/src/api/PDFFont.ts b/src/api/PDFFont.ts index 44274f0a0..4050ea47d 100644 --- a/src/api/PDFFont.ts +++ b/src/api/PDFFont.ts @@ -1,12 +1,13 @@ -import Embeddable from 'src/api//Embeddable'; -import PDFDocument from 'src/api/PDFDocument'; +import Embeddable from './Embeddable'; +import PDFDocument from './PDFDocument'; import { CustomFontEmbedder, PDFHexString, PDFRef, StandardFontEmbedder, -} from 'src/core'; -import { assertIs, assertOrUndefined } from 'src/utils'; +} from '../core'; +import { assertIs, assertOrUndefined } from '../utils'; +import { isPDFInstance, PDFClasses } from './objects'; export type FontEmbedder = CustomFontEmbedder | StandardFontEmbedder; @@ -38,7 +39,7 @@ export default class PDFFont implements Embeddable { /** The name of this font. */ readonly name: string; - private modified = true; + private alreadyEmbedded = false; private readonly embedder: FontEmbedder; private constructor(ref: PDFRef, doc: PDFDocument, embedder: FontEmbedder) { @@ -68,7 +69,6 @@ export default class PDFFont implements Embeddable { */ encodeText(text: string): PDFHexString { assertIs(text, 'text', ['string']); - this.modified = true; return this.embedder.encodeText(text); } @@ -128,10 +128,11 @@ export default class PDFFont implements Embeddable { * @returns The set of unicode code points supported by this font. */ getCharacterSet(): number[] { - if (this.embedder instanceof StandardFontEmbedder) { - return this.embedder.encoding.supportedCodePoints; + if (isPDFInstance(this.embedder, PDFClasses.StandardFontEmbedder)) { + return (this.embedder as StandardFontEmbedder).encoding + .supportedCodePoints; } else { - return this.embedder.font.characterSet; + return (this.embedder as CustomFontEmbedder).font.characterSet; } } @@ -145,10 +146,9 @@ export default class PDFFont implements Embeddable { * @returns Resolves when the embedding is complete. */ async embed(): Promise { - // TODO: Cleanup orphan embedded objects if a font is embedded multiple times... - if (this.modified) { + if (!this.alreadyEmbedded) { await this.embedder.embedIntoContext(this.doc.context, this.ref); - this.modified = false; + this.alreadyEmbedded = true; } } } diff --git a/src/api/PDFImage.ts b/src/api/PDFImage.ts index 544150558..42da17080 100644 --- a/src/api/PDFImage.ts +++ b/src/api/PDFImage.ts @@ -1,7 +1,7 @@ -import Embeddable from 'src/api/Embeddable'; -import PDFDocument from 'src/api/PDFDocument'; -import { JpegEmbedder, PDFRef, PngEmbedder } from 'src/core'; -import { assertIs } from 'src/utils'; +import Embeddable from './Embeddable'; +import PDFDocument from './PDFDocument'; +import { JpegEmbedder, PDFRef, PngEmbedder } from '../core'; +import { assertIs } from '../utils'; export type ImageEmbedder = JpegEmbedder | PngEmbedder; diff --git a/src/api/PDFJavaScript.ts b/src/api/PDFJavaScript.ts index 8727d6d7c..fefd4596a 100644 --- a/src/api/PDFJavaScript.ts +++ b/src/api/PDFJavaScript.ts @@ -1,7 +1,7 @@ -import Embeddable from 'src/api/Embeddable'; -import PDFDocument from 'src/api/PDFDocument'; -import JavaScriptEmbedder from 'src/core/embedders/JavaScriptEmbedder'; -import { PDFName, PDFArray, PDFDict, PDFHexString, PDFRef } from 'src/core'; +import Embeddable from './Embeddable'; +import PDFDocument from './PDFDocument'; +import JavaScriptEmbedder from '../core/embedders/JavaScriptEmbedder'; +import { PDFName, PDFArray, PDFDict, PDFHexString, PDFRef } from '../core'; /** * Represents JavaScript that has been embedded in a [[PDFDocument]]. diff --git a/src/api/PDFPage.ts b/src/api/PDFPage.ts index 7333440bd..c4b91262f 100644 --- a/src/api/PDFPage.ts +++ b/src/api/PDFPage.ts @@ -1,4 +1,4 @@ -import { Color, rgb } from 'src/api/colors'; +import { Color, rgb } from './colors'; import { drawImage, drawLine, @@ -7,18 +7,20 @@ import { drawRectangle, drawSvgPath, drawEllipse, -} from 'src/api/operations'; +} from './operations'; import { popGraphicsState, pushGraphicsState, translate, LineCapStyle, scale, -} from 'src/api/operators'; -import PDFDocument from 'src/api/PDFDocument'; -import PDFEmbeddedPage from 'src/api/PDFEmbeddedPage'; -import PDFFont from 'src/api/PDFFont'; -import PDFImage from 'src/api/PDFImage'; + FillRule, +} from './operators'; +import PDFDocument from './PDFDocument'; +import PDFEmbeddedPage from './PDFEmbeddedPage'; +import PDFFont from './PDFFont'; +import PDFImage from './PDFImage'; +import PDFSvg from './PDFSvg'; import { PDFPageDrawCircleOptions, PDFPageDrawEllipseOptions, @@ -30,9 +32,10 @@ import { PDFPageDrawSVGOptions, PDFPageDrawTextOptions, BlendMode, -} from 'src/api/PDFPageOptions'; -import { degrees, Rotation, toDegrees } from 'src/api/rotations'; -import { StandardFonts } from 'src/api/StandardFonts'; + PDFPageDrawSVGElementOptions, +} from './PDFPageOptions'; +import { degrees, Rotation, toDegrees } from './rotations'; +import { StandardFonts } from './StandardFonts'; import { PDFContentStream, PDFHexString, @@ -42,7 +45,7 @@ import { PDFRef, PDFDict, PDFArray, -} from 'src/core'; +} from '../core'; import { assertEachIs, assertIs, @@ -54,7 +57,9 @@ import { lineSplit, assertRangeOrUndefined, assertIsOneOfOrUndefined, -} from 'src/utils'; +} from '../utils'; +import { drawSvg } from './svg'; +import { isPDFInstance, PDFClasses } from './objects'; /** * Represents a single page of a [[PDFDocument]]. @@ -648,7 +653,8 @@ export default class PDFPage { for (let idx = 0; idx < annots.size(); idx++) { const annot = annots.lookup(idx); - if (annot instanceof PDFDict) this.scaleAnnot(annot, x, y); + if (isPDFInstance(annot, PDFClasses.PDFDict)) + this.scaleAnnot(annot as PDFDict, x, y); } } @@ -977,6 +983,11 @@ export default class PDFPage { assertOrUndefined(options.maxWidth, 'options.maxWidth', ['number']); assertOrUndefined(options.wordBreaks, 'options.wordBreaks', [Array]); assertIsOneOfOrUndefined(options.blendMode, 'options.blendMode', BlendMode); + assertOrUndefined(options.strokeColor, 'options.strokeColor', [ + [Object, 'Color'], + ]); + assertOrUndefined(options.strokeWidth, 'options.strokeWidth', ['number']); + assertOrUndefined(options.renderMode, 'options.renderMode', ['number']); const { oldFont, newFont, newFontKey } = this.setOrEmbedFont(options.font); const fontSize = options.size || this.fontSize; @@ -1011,6 +1022,11 @@ export default class PDFPage { y: options.y ?? this.y, lineHeight: options.lineHeight ?? this.lineHeight, graphicsState: graphicsStateKey, + matrix: options.matrix, + clipSpaces: options.clipSpaces, + strokeColor: options.strokeColor, + strokeWidth: options.strokeWidth, + renderMode: options.renderMode, }), ); @@ -1076,6 +1092,8 @@ export default class PDFPage { xSkew: options.xSkew ?? degrees(0), ySkew: options.ySkew ?? degrees(0), graphicsState: graphicsStateKey, + matrix: options.matrix, + clipSpaces: options.clipSpaces, }), ); } @@ -1144,16 +1162,16 @@ export default class PDFPage { // prettier-ignore const xScale = ( - options.width !== undefined ? options.width / embeddedPage.width - : options.xScale !== undefined ? options.xScale - : 1 + options.width !== undefined ? options.width / embeddedPage.width + : options.xScale !== undefined ? options.xScale + : 1 ); // prettier-ignore const yScale = ( - options.height !== undefined ? options.height / embeddedPage.height - : options.yScale !== undefined ? options.yScale - : 1 + options.height !== undefined ? options.height / embeddedPage.height + : options.yScale !== undefined ? options.yScale + : 1 ); const contentStream = this.getContentStream(); @@ -1238,6 +1256,7 @@ export default class PDFPage { 1, ); assertIsOneOfOrUndefined(options.blendMode, 'options.blendMode', BlendMode); + assertIsOneOfOrUndefined(options.fillRule, 'options.fillRule', FillRule); const graphicsStateKey = this.maybeEmbedGraphicsState({ opacity: options.opacity, @@ -1258,11 +1277,14 @@ export default class PDFPage { rotate: options.rotate ?? degrees(0), color: options.color ?? undefined, borderColor: options.borderColor ?? undefined, - borderWidth: options.borderWidth ?? 0, + borderWidth: options.borderWidth ?? 1, borderDashArray: options.borderDashArray ?? undefined, borderDashPhase: options.borderDashPhase ?? undefined, borderLineCap: options.borderLineCap ?? undefined, graphicsState: graphicsStateKey, + fillRule: options.fillRule, + matrix: options.matrix, + clipSpaces: options.clipSpaces, }), ); } @@ -1321,6 +1343,8 @@ export default class PDFPage { dashPhase: options.dashPhase ?? undefined, lineCap: options.lineCap ?? undefined, graphicsState: graphicsStateKey, + matrix: options.matrix, + clipSpaces: options.clipSpaces, }), ); } @@ -1333,6 +1357,8 @@ export default class PDFPage { * page.drawRectangle({ * x: 25, * y: 75, + * rx: 5, // This is the border radius + * ry: 5, * width: 250, * height: 75, * rotate: degrees(-15), @@ -1355,7 +1381,9 @@ export default class PDFPage { assertOrUndefined(options.ySkew, 'options.ySkew', [[Object, 'Rotation']]); assertOrUndefined(options.borderWidth, 'options.borderWidth', ['number']); assertOrUndefined(options.color, 'options.color', [[Object, 'Color']]); - assertRangeOrUndefined(options.opacity, 'opacity.opacity', 0, 1); + assertRangeOrUndefined(options.opacity, 'options.opacity', 0, 1); + assertOrUndefined(options.rx, 'options.rx', ['number']); + assertOrUndefined(options.ry, 'options.ry', ['number']); assertOrUndefined(options.borderColor, 'options.borderColor', [ [Object, 'Color'], ]); @@ -1400,11 +1428,15 @@ export default class PDFPage { ySkew: options.ySkew ?? degrees(0), borderWidth: options.borderWidth ?? 0, color: options.color ?? undefined, + rx: options.rx ?? 0, + ry: options.ry ?? 0, borderColor: options.borderColor ?? undefined, borderDashArray: options.borderDashArray ?? undefined, borderDashPhase: options.borderDashPhase ?? undefined, graphicsState: graphicsStateKey, borderLineCap: options.borderLineCap ?? undefined, + matrix: options.matrix, + clipSpaces: options.clipSpaces, }), ); } @@ -1508,6 +1540,8 @@ export default class PDFPage { borderDashPhase: options.borderDashPhase ?? undefined, borderLineCap: options.borderLineCap ?? undefined, graphicsState: graphicsStateKey, + matrix: options.matrix, + clipSpaces: options.clipSpaces, }), ); } @@ -1549,7 +1583,48 @@ export default class PDFPage { return { oldFont, oldFontKey, newFont, newFontKey }; } - private getFont(): [PDFFont, PDFName] { + /** + * Draw an SVG on this page. For example: + * ```js + * const svg = '' + * + * // Draw svg + * page.drawSvg(svg, { x: 25, y: 75 }) + * ``` + * + * If the svg contains images, you must call embedSvg from the document that contains that page first: + * ```js + * const svg = '' + * + * // Draw svg + * const pdfSvg = await pdfDoc.embedSvg(svg) + * page.drawSvg(pdfSvg, { x: 25, y: 75 }) + * ``` + * @param svg The SVG to be drawn. + * @param options The options to be used when drawing the SVG. + */ + drawSvg( + svg: PDFSvg | string, + options: PDFPageDrawSVGElementOptions = {}, + ): void { + assertIs(svg, 'svg', ['string', [PDFSvg, 'PDFSvg']]); + assertOrUndefined(options.x, 'options.x', ['number']); + assertOrUndefined(options.y, 'options.y', ['number']); + assertOrUndefined(options.width, 'options.width', ['number']); + assertOrUndefined(options.height, 'options.height', ['number']); + assertIsOneOfOrUndefined(options.blendMode, 'options.blendMode', BlendMode); + + drawSvg(this, svg, { + x: options.x ?? this.x, + y: options.y ?? this.y, + fonts: options.fonts, + width: options.width, + height: options.height, + blendMode: options.blendMode, + }); + } + + getFont(): [PDFFont, PDFName] { if (!this.font || !this.fontKey) { const font = this.doc.embedStandardFont(StandardFonts.Helvetica); this.setFont(font); @@ -1607,14 +1682,16 @@ export default class PDFPage { const selectors = ['RD', 'CL', 'Vertices', 'QuadPoints', 'L', 'Rect']; for (let idx = 0, len = selectors.length; idx < len; idx++) { const list = annot.lookup(PDFName.of(selectors[idx])); - if (list instanceof PDFArray) list.scalePDFNumbers(x, y); + if (isPDFInstance(list, PDFClasses.PDFArray)) + (list as PDFArray).scalePDFNumbers(x, y); } const inkLists = annot.lookup(PDFName.of('InkList')); - if (inkLists instanceof PDFArray) { - for (let idx = 0, len = inkLists.size(); idx < len; idx++) { - const arr = inkLists.lookup(idx); - if (arr instanceof PDFArray) arr.scalePDFNumbers(x, y); + if (isPDFInstance(inkLists, PDFClasses.PDFArray)) { + for (let idx = 0, len = (inkLists as PDFArray).size(); idx < len; idx++) { + const arr = (inkLists as PDFArray).lookup(idx); + if (isPDFInstance(arr, PDFClasses.PDFArray)) + (arr as PDFArray).scalePDFNumbers(x, y); } } } diff --git a/src/api/PDFPageOptions.ts b/src/api/PDFPageOptions.ts index 6ddd8357f..b5013d224 100644 --- a/src/api/PDFPageOptions.ts +++ b/src/api/PDFPageOptions.ts @@ -1,7 +1,13 @@ -import { Color } from 'src/api/colors'; -import PDFFont from 'src/api/PDFFont'; -import { Rotation } from 'src/api/rotations'; -import { LineCapStyle } from 'src/api/operators'; +import { Color } from './colors'; +import PDFFont from './PDFFont'; +import { Rotation } from './rotations'; +import { FillRule, LineCapStyle, TextRenderingMode } from './operators'; +import type { Space, TransformationMatrix } from '../types'; + +interface SvgOptions { + matrix?: TransformationMatrix; + clipSpaces?: Space[]; +} export enum BlendMode { Normal = 'Normal', @@ -18,7 +24,7 @@ export enum BlendMode { Exclusion = 'Exclusion', } -export interface PDFPageDrawTextOptions { +export interface PDFPageDrawTextOptions extends SvgOptions { color?: Color; opacity?: number; blendMode?: BlendMode; @@ -32,9 +38,12 @@ export interface PDFPageDrawTextOptions { lineHeight?: number; maxWidth?: number; wordBreaks?: string[]; + strokeWidth?: number; + strokeColor?: Color; + renderMode?: TextRenderingMode; } -export interface PDFPageDrawImageOptions { +export interface PDFPageDrawImageOptions extends SvgOptions { x?: number; y?: number; width?: number; @@ -60,7 +69,7 @@ export interface PDFPageDrawPageOptions { blendMode?: BlendMode; } -export interface PDFPageDrawSVGOptions { +export interface PDFPageDrawSVGOptions extends SvgOptions { x?: number; y?: number; scale?: number; @@ -74,9 +83,10 @@ export interface PDFPageDrawSVGOptions { borderDashPhase?: number; borderLineCap?: LineCapStyle; blendMode?: BlendMode; + fillRule?: FillRule; } -export interface PDFPageDrawLineOptions { +export interface PDFPageDrawLineOptions extends SvgOptions { start: { x: number; y: number }; end: { x: number; y: number }; thickness?: number; @@ -88,9 +98,11 @@ export interface PDFPageDrawLineOptions { blendMode?: BlendMode; } -export interface PDFPageDrawRectangleOptions { +export interface PDFPageDrawRectangleOptions extends SvgOptions { x?: number; y?: number; + rx?: number; + ry?: number; width?: number; height?: number; rotate?: Rotation; @@ -107,7 +119,7 @@ export interface PDFPageDrawRectangleOptions { blendMode?: BlendMode; } -export interface PDFPageDrawSquareOptions { +export interface PDFPageDrawSquareOptions extends SvgOptions { x?: number; y?: number; size?: number; @@ -125,7 +137,7 @@ export interface PDFPageDrawSquareOptions { blendMode?: BlendMode; } -export interface PDFPageDrawEllipseOptions { +export interface PDFPageDrawEllipseOptions extends SvgOptions { x?: number; y?: number; xScale?: number; @@ -142,7 +154,7 @@ export interface PDFPageDrawEllipseOptions { blendMode?: BlendMode; } -export interface PDFPageDrawCircleOptions { +export interface PDFPageDrawCircleOptions extends SvgOptions { x?: number; y?: number; size?: number; @@ -156,3 +168,13 @@ export interface PDFPageDrawCircleOptions { borderLineCap?: LineCapStyle; blendMode?: BlendMode; } + +export interface PDFPageDrawSVGElementOptions { + x?: number; + y?: number; + width?: number; + height?: number; + fontSize?: number; + fonts?: { [fontName: string]: PDFFont }; + blendMode?: BlendMode; +} diff --git a/src/api/PDFSvg.ts b/src/api/PDFSvg.ts new file mode 100644 index 000000000..c209dca77 --- /dev/null +++ b/src/api/PDFSvg.ts @@ -0,0 +1,10 @@ +import PDFImage from './PDFImage'; + +export default class PDFSvg { + svg: string; + images: Record; + constructor(svg: string, images: Record = {}) { + this.svg = svg; + this.images = images; + } +} diff --git a/src/api/colors.ts b/src/api/colors.ts index 6f2988c82..b7d55a7f1 100644 --- a/src/api/colors.ts +++ b/src/api/colors.ts @@ -5,8 +5,9 @@ import { setStrokingCmykColor, setStrokingGrayscaleColor, setStrokingRgbColor, -} from 'src/api/operators'; -import { assertRange, error } from 'src/utils'; +} from './operators'; +import { assertRange, assertIs, error } from '../utils'; +import ColorParser from 'color'; export enum ColorTypes { Grayscale = 'Grayscale', @@ -61,20 +62,27 @@ export const cmyk = ( return { type: ColorTypes.CMYK, cyan, magenta, yellow, key }; }; -const { Grayscale, RGB, CMYK } = ColorTypes; +export const colorString = (color: string): { rgb: Color; alpha?: number } => { + assertIs(color, 'color', ['string']); + const colorDescription = ColorParser(color).unitObject(); + return { + rgb: rgb(colorDescription.r, colorDescription.g, colorDescription.b), + alpha: colorDescription.alpha, + }; +}; // prettier-ignore -export const setFillingColor = (color: Color) => - color.type === Grayscale ? setFillingGrayscaleColor(color.gray) - : color.type === RGB ? setFillingRgbColor(color.red, color.green, color.blue) - : color.type === CMYK ? setFillingCmykColor(color.cyan, color.magenta, color.yellow, color.key) +export const setFillingColor = (color: Color) => + color.type === ColorTypes.Grayscale ? setFillingGrayscaleColor(color.gray) + : color.type === ColorTypes.RGB ? setFillingRgbColor(color.red, color.green, color.blue) + : color.type === ColorTypes.CMYK ? setFillingCmykColor(color.cyan, color.magenta, color.yellow, color.key) : error(`Invalid color: ${JSON.stringify(color)}`); // prettier-ignore -export const setStrokingColor = (color: Color) => - color.type === Grayscale ? setStrokingGrayscaleColor(color.gray) - : color.type === RGB ? setStrokingRgbColor(color.red, color.green, color.blue) - : color.type === CMYK ? setStrokingCmykColor(color.cyan, color.magenta, color.yellow, color.key) +export const setStrokingColor = (color: Color) => + color.type === ColorTypes.Grayscale ? setStrokingGrayscaleColor(color.gray) + : color.type === ColorTypes.RGB ? setStrokingRgbColor(color.red, color.green, color.blue) + : color.type === ColorTypes.CMYK ? setStrokingCmykColor(color.cyan, color.magenta, color.yellow, color.key) : error(`Invalid color: ${JSON.stringify(color)}`); // prettier-ignore @@ -83,14 +91,14 @@ export const componentsToColor = (comps?: number[], scale = 1) => ( comps[0] * scale, ) : comps?.length === 3 ? rgb( - comps[0] * scale, - comps[1] * scale, + comps[0] * scale, + comps[1] * scale, comps[2] * scale, ) : comps?.length === 4 ? cmyk( - comps[0] * scale, - comps[1] * scale, - comps[2] * scale, + comps[0] * scale, + comps[1] * scale, + comps[2] * scale, comps[3] * scale, ) : undefined @@ -98,7 +106,7 @@ export const componentsToColor = (comps?: number[], scale = 1) => ( // prettier-ignore export const colorToComponents = (color: Color) => - color.type === Grayscale ? [color.gray] - : color.type === RGB ? [color.red, color.green, color.blue] - : color.type === CMYK ? [color.cyan, color.magenta, color.yellow, color.key] + color.type === ColorTypes.Grayscale ? [color.gray] + : color.type === ColorTypes.RGB ? [color.red, color.green, color.blue] + : color.type === ColorTypes.CMYK ? [color.cyan, color.magenta, color.yellow, color.key] : error(`Invalid color: ${JSON.stringify(color)}`); diff --git a/src/api/form/PDFButton.ts b/src/api/form/PDFButton.ts index 31f23ca16..33a1735bf 100644 --- a/src/api/form/PDFButton.ts +++ b/src/api/form/PDFButton.ts @@ -1,27 +1,23 @@ -import PDFDocument from 'src/api/PDFDocument'; -import PDFPage from 'src/api/PDFPage'; -import PDFFont from 'src/api/PDFFont'; -import PDFImage from 'src/api/PDFImage'; -import { ImageAlignment } from 'src/api/image/alignment'; +import PDFDocument from '../PDFDocument'; +import PDFPage from '../PDFPage'; +import PDFFont from '../PDFFont'; +import PDFImage from '../PDFImage'; +import { ImageAlignment } from '../image/alignment'; import { AppearanceProviderFor, normalizeAppearance, defaultButtonAppearanceProvider, -} from 'src/api/form/appearances'; +} from './appearances'; import PDFField, { FieldAppearanceOptions, assertFieldAppearanceOptions, -} from 'src/api/form/PDFField'; -import { rgb } from 'src/api/colors'; -import { degrees } from 'src/api/rotations'; +} from './PDFField'; +import { rgb } from '../colors'; +import { degrees } from '../rotations'; -import { - PDFRef, - PDFStream, - PDFAcroPushButton, - PDFWidgetAnnotation, -} from 'src/core'; -import { assertIs, assertOrUndefined, assertPositive } from 'src/utils'; +import { PDFRef, PDFAcroPushButton, PDFWidgetAnnotation } from '../../core'; +import { assertIs, assertOrUndefined, assertPositive } from '../../utils'; +import { isPDFInstance, PDFClasses } from '../objects'; /** * Represents a button field of a [[PDFForm]]. @@ -33,6 +29,10 @@ import { assertIs, assertOrUndefined, assertPositive } from 'src/utils'; * have a text label describing the action that they perform when clicked. */ export default class PDFButton extends PDFField { + static className = () => PDFClasses.PDFButton; + myClass(): PDFClasses { + return PDFClasses.PDFButton; + } /** * > **NOTE:** You probably don't want to call this method directly. Instead, * > consider using the [[PDFForm.getButton]] method, which will create an @@ -199,8 +199,10 @@ export default class PDFButton extends PDFField { const widgets = this.acroField.getWidgets(); for (let idx = 0, len = widgets.length; idx < len; idx++) { const widget = widgets[idx]; - const hasAppearances = - widget.getAppearances()?.normal instanceof PDFStream; + const hasAppearances = isPDFInstance( + widget.getAppearances()?.normal, + PDFClasses.PDFStream, + ); if (!hasAppearances) return true; } diff --git a/src/api/form/PDFCheckBox.ts b/src/api/form/PDFCheckBox.ts index 1060b4276..90bd61c1b 100644 --- a/src/api/form/PDFCheckBox.ts +++ b/src/api/form/PDFCheckBox.ts @@ -1,16 +1,16 @@ -import PDFDocument from 'src/api/PDFDocument'; -import PDFPage from 'src/api/PDFPage'; +import PDFDocument from '../PDFDocument'; +import PDFPage from '../PDFPage'; import { AppearanceProviderFor, normalizeAppearance, defaultCheckBoxAppearanceProvider, -} from 'src/api/form/appearances'; -import { rgb } from 'src/api/colors'; -import { degrees } from 'src/api/rotations'; +} from './appearances'; +import { rgb } from '../colors'; +import { degrees } from '../rotations'; import PDFField, { FieldAppearanceOptions, assertFieldAppearanceOptions, -} from 'src/api/form/PDFField'; +} from './PDFField'; import { PDFName, @@ -18,8 +18,9 @@ import { PDFDict, PDFAcroCheckBox, PDFWidgetAnnotation, -} from 'src/core'; -import { assertIs, assertOrUndefined } from 'src/utils'; +} from '../../core'; +import { assertIs, assertOrUndefined } from '../../utils'; +import { isPDFInstance, PDFClasses } from '../objects'; /** * Represents a check box field of a [[PDFForm]]. @@ -31,6 +32,10 @@ import { assertIs, assertOrUndefined } from 'src/utils'; * square in shape and display a check mark when they are in the `on` state. */ export default class PDFCheckBox extends PDFField { + static className = () => PDFClasses.PDFCheckBox; + myClass(): PDFClasses { + return PDFClasses.PDFCheckBox; + } /** * > **NOTE:** You probably don't want to call this method directly. Instead, * > consider using the [[PDFForm.getCheckBox]] method, which will create an @@ -201,8 +206,8 @@ export default class PDFCheckBox extends PDFField { const state = widget.getAppearanceState(); const normal = widget.getAppearances()?.normal; - if (!(normal instanceof PDFDict)) return true; - if (state && !normal.has(state)) return true; + if (!isPDFInstance(normal, PDFClasses.PDFDict)) return true; + if (state && !(normal as PDFDict).has(state)) return true; } return false; diff --git a/src/api/form/PDFDropdown.ts b/src/api/form/PDFDropdown.ts index 27d9a7c3e..10dd480c7 100644 --- a/src/api/form/PDFDropdown.ts +++ b/src/api/form/PDFDropdown.ts @@ -1,28 +1,28 @@ -import PDFDocument from 'src/api/PDFDocument'; -import PDFPage from 'src/api/PDFPage'; -import PDFFont from 'src/api/PDFFont'; +import PDFDocument from '../PDFDocument'; +import PDFPage from '../PDFPage'; +import PDFFont from '../PDFFont'; import PDFField, { FieldAppearanceOptions, assertFieldAppearanceOptions, -} from 'src/api/form/PDFField'; +} from './PDFField'; import { AppearanceProviderFor, normalizeAppearance, defaultDropdownAppearanceProvider, -} from 'src/api/form/appearances'; -import { rgb } from 'src/api/colors'; -import { degrees } from 'src/api/rotations'; +} from './appearances'; +import { rgb } from '../colors'; +import { degrees } from '../rotations'; import { PDFHexString, PDFRef, PDFString, - PDFStream, PDFWidgetAnnotation, PDFAcroComboBox, AcroChoiceFlags, -} from 'src/core'; -import { assertIs, assertOrUndefined, assertPositive } from 'src/utils'; +} from '../../core'; +import { assertIs, assertOrUndefined, assertPositive } from '../../utils'; +import { isPDFInstance, PDFClasses } from '../objects'; /** * Represents a dropdown field of a [[PDFForm]]. @@ -37,6 +37,10 @@ import { assertIs, assertOrUndefined, assertPositive } from 'src/utils'; * choose an option from the list (see [[PDFDropdown.isEditable]]). */ export default class PDFDropdown extends PDFField { + static className = () => PDFClasses.PDFDropdown; + myClass(): PDFClasses { + return PDFClasses.PDFDropdown; + } /** * > **NOTE:** You probably don't want to call this method directly. Instead, * > consider using the [[PDFForm.getDropdown]] method, which will create an @@ -579,8 +583,10 @@ export default class PDFDropdown extends PDFField { const widgets = this.acroField.getWidgets(); for (let idx = 0, len = widgets.length; idx < len; idx++) { const widget = widgets[idx]; - const hasAppearances = - widget.getAppearances()?.normal instanceof PDFStream; + const hasAppearances = isPDFInstance( + widget.getAppearances()?.normal, + PDFClasses.PDFStream, + ); if (!hasAppearances) return true; } diff --git a/src/api/form/PDFField.ts b/src/api/form/PDFField.ts index cd3b3efe4..611c174d8 100644 --- a/src/api/form/PDFField.ts +++ b/src/api/form/PDFField.ts @@ -1,7 +1,7 @@ -import PDFDocument from 'src/api/PDFDocument'; -import PDFFont from 'src/api/PDFFont'; -import { AppearanceMapping } from 'src/api/form/appearances'; -import { Color, colorToComponents, setFillingColor } from 'src/api/colors'; +import PDFDocument from '../PDFDocument'; +import PDFFont from '../PDFFont'; +import { AppearanceMapping } from './appearances'; +import { Color, colorToComponents, setFillingColor } from '../colors'; import { Rotation, toDegrees, @@ -9,7 +9,7 @@ import { reduceRotation, adjustDimsForRotation, degrees, -} from 'src/api/rotations'; +} from '../rotations'; import { PDFRef, @@ -21,11 +21,12 @@ import { AcroFieldFlags, PDFAcroTerminal, AnnotationFlags, -} from 'src/core'; -import { assertIs, assertMultiple, assertOrUndefined } from 'src/utils'; +} from '../../core'; +import { assertIs, assertMultiple, assertOrUndefined } from '../../utils'; import { ImageAlignment } from '../image'; import PDFImage from '../PDFImage'; import { drawImage, rotateInPlace } from '../operations'; +import { PDFClasses } from '../objects'; export interface FieldAppearanceOptions { x?: number; @@ -82,6 +83,10 @@ export const assertFieldAppearanceOptions = ( * to be rendered. */ export default class PDFField { + static className = () => PDFClasses.PDFField; + myClass(): PDFClasses { + return PDFClasses.PDFField; + } /** The low-level PDFAcroTerminal wrapped by this field. */ readonly acroField: PDFAcroTerminal; diff --git a/src/api/form/PDFForm.ts b/src/api/form/PDFForm.ts index e92c833fc..f48e9496a 100644 --- a/src/api/form/PDFForm.ts +++ b/src/api/form/PDFForm.ts @@ -1,28 +1,28 @@ -import PDFDocument from 'src/api/PDFDocument'; -import PDFPage from 'src/api/PDFPage'; -import PDFField from 'src/api/form/PDFField'; -import PDFButton from 'src/api/form/PDFButton'; -import PDFCheckBox from 'src/api/form/PDFCheckBox'; -import PDFDropdown from 'src/api/form/PDFDropdown'; -import PDFOptionList from 'src/api/form/PDFOptionList'; -import PDFRadioGroup from 'src/api/form/PDFRadioGroup'; -import PDFSignature from 'src/api/form/PDFSignature'; -import PDFTextField from 'src/api/form/PDFTextField'; +import PDFDocument from '../PDFDocument'; +import PDFPage from '../PDFPage'; +import PDFField from './PDFField'; +import PDFButton from './PDFButton'; +import PDFCheckBox from './PDFCheckBox'; +import PDFDropdown from './PDFDropdown'; +import PDFOptionList from './PDFOptionList'; +import PDFRadioGroup from './PDFRadioGroup'; +import PDFSignature from './PDFSignature'; +import PDFTextField from './PDFTextField'; import { NoSuchFieldError, UnexpectedFieldTypeError, FieldAlreadyExistsError, InvalidFieldNamePartError, -} from 'src/api/errors'; -import PDFFont from 'src/api/PDFFont'; -import { StandardFonts } from 'src/api/StandardFonts'; -import { rotateInPlace } from 'src/api/operations'; +} from '../errors'; +import PDFFont from '../PDFFont'; +import { StandardFonts } from '../StandardFonts'; +import { rotateInPlace } from '../operations'; import { drawObject, popGraphicsState, pushGraphicsState, translate, -} from 'src/api/operators'; +} from '../operators'; import { PDFAcroForm, PDFAcroField, @@ -40,8 +40,9 @@ import { createPDFAcroFields, PDFName, PDFWidgetAnnotation, -} from 'src/core'; -import { assertIs, Cache, assertOrUndefined } from 'src/utils'; +} from '../../core'; +import { assertIs, Cache, assertOrUndefined } from '../../utils'; +import { isPDFInstance, PDFClasses } from '../objects'; export interface FlattenOptions { updateFieldAppearances: boolean; @@ -202,7 +203,7 @@ export default class PDFForm { getButton(name: string): PDFButton { assertIs(name, 'name', ['string']); const field = this.getField(name); - if (field instanceof PDFButton) return field; + if (isPDFInstance(field, PDFClasses.PDFButton)) return field as PDFButton; throw new UnexpectedFieldTypeError(name, PDFButton, field); } @@ -222,7 +223,8 @@ export default class PDFForm { getCheckBox(name: string): PDFCheckBox { assertIs(name, 'name', ['string']); const field = this.getField(name); - if (field instanceof PDFCheckBox) return field; + if (isPDFInstance(field, PDFClasses.PDFCheckBox)) + return field as PDFCheckBox; throw new UnexpectedFieldTypeError(name, PDFCheckBox, field); } @@ -243,7 +245,8 @@ export default class PDFForm { getDropdown(name: string): PDFDropdown { assertIs(name, 'name', ['string']); const field = this.getField(name); - if (field instanceof PDFDropdown) return field; + if (isPDFInstance(field, PDFClasses.PDFDropdown)) + return field as PDFDropdown; throw new UnexpectedFieldTypeError(name, PDFDropdown, field); } @@ -264,7 +267,8 @@ export default class PDFForm { getOptionList(name: string): PDFOptionList { assertIs(name, 'name', ['string']); const field = this.getField(name); - if (field instanceof PDFOptionList) return field; + if (isPDFInstance(field, PDFClasses.PDFOptionList)) + return field as PDFOptionList; throw new UnexpectedFieldTypeError(name, PDFOptionList, field); } @@ -285,7 +289,8 @@ export default class PDFForm { getRadioGroup(name: string): PDFRadioGroup { assertIs(name, 'name', ['string']); const field = this.getField(name); - if (field instanceof PDFRadioGroup) return field; + if (isPDFInstance(field, PDFClasses.PDFRadioGroup)) + return field as PDFRadioGroup; throw new UnexpectedFieldTypeError(name, PDFRadioGroup, field); } @@ -304,7 +309,8 @@ export default class PDFForm { getSignature(name: string): PDFSignature { assertIs(name, 'name', ['string']); const field = this.getField(name); - if (field instanceof PDFSignature) return field; + if (isPDFInstance(field, PDFClasses.PDFSignature)) + return field as PDFSignature; throw new UnexpectedFieldTypeError(name, PDFSignature, field); } @@ -324,7 +330,8 @@ export default class PDFForm { getTextField(name: string): PDFTextField { assertIs(name, 'name', ['string']); const field = this.getField(name); - if (field instanceof PDFTextField) return field; + if (isPDFInstance(field, PDFClasses.PDFTextField)) + return field as PDFTextField; throw new UnexpectedFieldTypeError(name, PDFTextField, field); } @@ -546,22 +553,26 @@ export default class PDFForm { const widgets = field.acroField.getWidgets(); for (let j = 0, lenWidgets = widgets.length; j < lenWidgets; j++) { - const widget = widgets[j]; - const page = this.findWidgetPage(widget); - const widgetRef = this.findWidgetAppearanceRef(field, widget); - - const xObjectKey = page.node.newXObject('FlatWidget', widgetRef); - - const rectangle = widget.getRectangle(); - const operators = [ - pushGraphicsState(), - translate(rectangle.x, rectangle.y), - ...rotateInPlace({ ...rectangle, rotation: 0 }), - drawObject(xObjectKey), - popGraphicsState(), - ].filter(Boolean) as PDFOperator[]; - - page.pushOperators(...operators); + try { + const widget = widgets[j]; + const page = this.findWidgetPage(widget); + const widgetRef = this.findWidgetAppearanceRef(field, widget); + + const xObjectKey = page.node.newXObject('FlatWidget', widgetRef); + + const rectangle = widget.getRectangle(); + const operators = [ + pushGraphicsState(), + translate(rectangle.x, rectangle.y), + ...rotateInPlace({ ...rectangle, rotation: 0 }), + drawObject(xObjectKey), + popGraphicsState(), + ].filter(Boolean) as PDFOperator[]; + + page.pushOperators(...operators); + } catch (err) { + console.error(err); + } } this.removeField(field); @@ -583,13 +594,17 @@ export default class PDFForm { const pages: Set = new Set(); for (let i = 0, len = widgets.length; i < len; i++) { - const widget = widgets[i]; - const widgetRef = this.findWidgetAppearanceRef(field, widget); + try { + const widget = widgets[i]; + const widgetRef = this.findWidgetAppearanceRef(field, widget); - const page = this.findWidgetPage(widget); - pages.add(page); + const page = this.findWidgetPage(widget); + pages.add(page); - page.node.removeAnnot(widgetRef); + page.node.removeAnnot(widgetRef); + } catch (err) { + console.error(err); + } } pages.forEach((page) => page.node.removeAnnot(field.ref)); @@ -598,8 +613,8 @@ export default class PDFForm { const kidsCount = fieldKids.size(); for (let childIndex = 0; childIndex < kidsCount; childIndex++) { const child = fieldKids.get(childIndex); - if (child instanceof PDFRef) { - this.doc.context.delete(child); + if (isPDFInstance(child, PDFClasses.PDFRef)) { + this.doc.context.delete(child as PDFRef); } } this.doc.context.delete(field.ref); @@ -724,23 +739,32 @@ export default class PDFForm { let refOrDict = widget.getNormalAppearance(); if ( - refOrDict instanceof PDFDict && - (field instanceof PDFCheckBox || field instanceof PDFRadioGroup) + isPDFInstance(field, PDFClasses.PDFCheckBox) || + isPDFInstance(field, PDFClasses.PDFRadioGroup) ) { - const value = field.acroField.getValue(); - const ref = refOrDict.get(value) ?? refOrDict.get(PDFName.of('Off')); - - if (ref instanceof PDFRef) { - refOrDict = ref; + if (isPDFInstance(refOrDict, PDFClasses.PDFRef)) { + refOrDict = this.doc.context.lookup(refOrDict, PDFDict); + } + if (isPDFInstance(refOrDict, PDFClasses.PDFDict)) { + const value = ( + field as PDFCheckBox | PDFRadioGroup + ).acroField.getValue(); + const ref = + (refOrDict as PDFDict).get(value) ?? + (refOrDict as PDFDict).get(PDFName.of('Off')); + + if (isPDFInstance(ref, PDFClasses.PDFRef)) { + refOrDict = ref as PDFRef; + } } } - if (!(refOrDict instanceof PDFRef)) { + if (!isPDFInstance(refOrDict, PDFClasses.PDFRef)) { const name = field.getName(); throw new Error(`Failed to extract appearance ref for: ${name}`); } - return refOrDict; + return refOrDict as PDFRef; } private findOrCreateNonTerminals(partialNames: string[]) { @@ -771,15 +795,15 @@ export default class PDFForm { partialName: string, parent: PDFAcroForm | PDFAcroNonTerminal, ): [PDFAcroNonTerminal, PDFRef] | undefined { - const fields = - parent instanceof PDFAcroForm - ? this.acroForm.getFields() - : createPDFAcroFields(parent.Kids()); + const fields = isPDFInstance(parent, PDFClasses.PDFAcroForm) + ? this.acroForm.getFields() + : createPDFAcroFields((parent as PDFAcroNonTerminal).Kids()); for (let idx = 0, len = fields.length; idx < len; idx++) { const [field, ref] = fields[idx]; if (field.getPartialName() === partialName) { - if (field instanceof PDFAcroNonTerminal) return [field, ref]; + if (isPDFInstance(field, PDFClasses.PDFAcroNonTerminal)) + return [field as PDFAcroNonTerminal, ref]; throw new FieldAlreadyExistsError(partialName); } } @@ -796,16 +820,21 @@ const convertToPDFField = ( ref: PDFRef, doc: PDFDocument, ): PDFField | undefined => { - if (field instanceof PDFAcroPushButton) return PDFButton.of(field, ref, doc); - if (field instanceof PDFAcroCheckBox) return PDFCheckBox.of(field, ref, doc); - if (field instanceof PDFAcroComboBox) return PDFDropdown.of(field, ref, doc); - if (field instanceof PDFAcroListBox) return PDFOptionList.of(field, ref, doc); - if (field instanceof PDFAcroText) return PDFTextField.of(field, ref, doc); - if (field instanceof PDFAcroRadioButton) { - return PDFRadioGroup.of(field, ref, doc); - } - if (field instanceof PDFAcroSignature) { - return PDFSignature.of(field, ref, doc); + if (isPDFInstance(field, PDFClasses.PDFAcroPushButton)) + return PDFButton.of(field as PDFAcroPushButton, ref, doc); + if (isPDFInstance(field, PDFClasses.PDFAcroCheckBox)) + return PDFCheckBox.of(field as PDFAcroCheckBox, ref, doc); + if (isPDFInstance(field, PDFClasses.PDFAcroComboBox)) + return PDFDropdown.of(field as PDFAcroComboBox, ref, doc); + if (isPDFInstance(field, PDFClasses.PDFAcroListBox)) + return PDFOptionList.of(field as PDFAcroListBox, ref, doc); + if (isPDFInstance(field, PDFClasses.PDFAcroText)) + return PDFTextField.of(field as PDFAcroText, ref, doc); + if (isPDFInstance(field, PDFClasses.PDFAcroRadioButton)) { + return PDFRadioGroup.of(field as PDFAcroRadioButton, ref, doc); + } + if (isPDFInstance(field, PDFClasses.PDFAcroSignature)) { + return PDFSignature.of(field as PDFAcroSignature, ref, doc); } return undefined; }; diff --git a/src/api/form/PDFOptionList.ts b/src/api/form/PDFOptionList.ts index 585c75d5e..cbf3f98d9 100644 --- a/src/api/form/PDFOptionList.ts +++ b/src/api/form/PDFOptionList.ts @@ -1,33 +1,33 @@ -import PDFDocument from 'src/api/PDFDocument'; -import PDFPage from 'src/api/PDFPage'; -import PDFFont from 'src/api/PDFFont'; +import PDFDocument from '../PDFDocument'; +import PDFPage from '../PDFPage'; +import PDFFont from '../PDFFont'; import PDFField, { FieldAppearanceOptions, assertFieldAppearanceOptions, -} from 'src/api/form/PDFField'; +} from './PDFField'; import { AppearanceProviderFor, normalizeAppearance, defaultOptionListAppearanceProvider, -} from 'src/api/form/appearances'; -import { rgb } from 'src/api/colors'; -import { degrees } from 'src/api/rotations'; +} from './appearances'; +import { rgb } from '../colors'; +import { degrees } from '../rotations'; import { PDFRef, PDFHexString, PDFString, - PDFStream, PDFAcroListBox, AcroChoiceFlags, PDFWidgetAnnotation, -} from 'src/core'; +} from '../../core'; import { assertIs, assertIsSubset, assertOrUndefined, assertPositive, -} from 'src/utils'; +} from '../../utils'; +import { isPDFInstance, PDFClasses } from '../objects'; /** * Represents an option list field of a [[PDFForm]]. @@ -41,6 +41,10 @@ import { * more than one option (see [[PDFOptionList.isMultiselect]]). */ export default class PDFOptionList extends PDFField { + static className = () => PDFClasses.PDFOptionList; + myClass(): PDFClasses { + return PDFClasses.PDFOptionList; + } /** * > **NOTE:** You probably don't want to call this method directly. Instead, * > consider using the [[PDFForm.getOptionList]] method, which will create @@ -498,8 +502,10 @@ export default class PDFOptionList extends PDFField { const widgets = this.acroField.getWidgets(); for (let idx = 0, len = widgets.length; idx < len; idx++) { const widget = widgets[idx]; - const hasAppearances = - widget.getAppearances()?.normal instanceof PDFStream; + const hasAppearances = isPDFInstance( + widget.getAppearances()?.normal, + PDFClasses.PDFStream, + ); if (!hasAppearances) return true; } diff --git a/src/api/form/PDFRadioGroup.ts b/src/api/form/PDFRadioGroup.ts index 26b5184bb..f25b52178 100644 --- a/src/api/form/PDFRadioGroup.ts +++ b/src/api/form/PDFRadioGroup.ts @@ -1,16 +1,16 @@ -import PDFDocument from 'src/api/PDFDocument'; -import PDFPage from 'src/api/PDFPage'; +import PDFDocument from '../PDFDocument'; +import PDFPage from '../PDFPage'; import PDFField, { FieldAppearanceOptions, assertFieldAppearanceOptions, -} from 'src/api/form/PDFField'; +} from './PDFField'; import { AppearanceProviderFor, normalizeAppearance, defaultRadioGroupAppearanceProvider, -} from 'src/api/form/appearances'; -import { rgb } from 'src/api/colors'; -import { degrees } from 'src/api/rotations'; +} from './appearances'; +import { rgb } from '../colors'; +import { degrees } from '../rotations'; import { PDFName, @@ -20,8 +20,9 @@ import { PDFWidgetAnnotation, PDFAcroRadioButton, AcroButtonFlags, -} from 'src/core'; -import { assertIs, assertOrUndefined, assertIsOneOf } from 'src/utils'; +} from '../../core'; +import { assertIs, assertOrUndefined, assertIsOneOf } from '../../utils'; +import { isPDFInstance, PDFClasses } from '../objects'; /** * Represents a radio group field of a [[PDFForm]]. @@ -41,6 +42,10 @@ import { assertIs, assertOrUndefined, assertIsOneOf } from 'src/utils'; * [[PDFRadioGroup.isMutuallyExclusive]]). */ export default class PDFRadioGroup extends PDFField { + static className = () => PDFClasses.PDFRadioGroup; + myClass(): PDFClasses { + return PDFClasses.PDFRadioGroup; + } /** * > **NOTE:** You probably don't want to call this method directly. Instead, * > consider using the [[PDFForm.getOptionList]] method, which will create an @@ -405,8 +410,8 @@ export default class PDFRadioGroup extends PDFField { const state = widget.getAppearanceState(); const normal = widget.getAppearances()?.normal; - if (!(normal instanceof PDFDict)) return true; - if (state && !normal.has(state)) return true; + if (!isPDFInstance(normal, PDFClasses.PDFDict)) return true; + if (state && !(normal as PDFDict).has(state)) return true; } return false; @@ -426,7 +431,7 @@ export default class PDFRadioGroup extends PDFField { // rg.updateAppearances((field: any, widget: any) => { // assert(field === rg); - // assert(widget instanceof PDFWidgetAnnotation); + // assert(isPDFInstance(widget, PDFClasses.PDFWidgetAnnotation)); // return { on: [...rectangle, ...circle], off: [...rectangle, ...circle] }; // }); diff --git a/src/api/form/PDFSignature.ts b/src/api/form/PDFSignature.ts index 83213b9fa..4911fa2dc 100644 --- a/src/api/form/PDFSignature.ts +++ b/src/api/form/PDFSignature.ts @@ -1,8 +1,9 @@ -import PDFDocument from 'src/api/PDFDocument'; -import PDFField from 'src/api/form/PDFField'; +import PDFDocument from '../PDFDocument'; +import PDFField from './PDFField'; -import { PDFRef, PDFAcroSignature } from 'src/core'; -import { assertIs } from 'src/utils'; +import { PDFRef, PDFAcroSignature } from '../../core'; +import { assertIs } from '../../utils'; +import { PDFClasses } from '../objects'; /** * Represents a signature field of a [[PDFForm]]. @@ -12,6 +13,10 @@ import { assertIs } from 'src/utils'; * reading the contents of existing digital signatures. */ export default class PDFSignature extends PDFField { + static className = () => PDFClasses.PDFSignature; + myClass(): PDFClasses { + return PDFClasses.PDFSignature; + } /** * > **NOTE:** You probably don't want to call this method directly. Instead, * > consider using the [[PDFForm.getSignature]] method, which will create an diff --git a/src/api/form/PDFTextField.ts b/src/api/form/PDFTextField.ts index 29543c8af..21982976c 100644 --- a/src/api/form/PDFTextField.ts +++ b/src/api/form/PDFTextField.ts @@ -1,41 +1,41 @@ -import PDFDocument from 'src/api/PDFDocument'; -import PDFPage from 'src/api/PDFPage'; -import PDFFont from 'src/api/PDFFont'; -import PDFImage from 'src/api/PDFImage'; +import PDFDocument from '../PDFDocument'; +import PDFPage from '../PDFPage'; +import PDFFont from '../PDFFont'; +import PDFImage from '../PDFImage'; import PDFField, { FieldAppearanceOptions, assertFieldAppearanceOptions, -} from 'src/api/form/PDFField'; +} from './PDFField'; import { AppearanceProviderFor, normalizeAppearance, defaultTextFieldAppearanceProvider, -} from 'src/api/form/appearances'; -import { rgb } from 'src/api/colors'; -import { degrees } from 'src/api/rotations'; +} from './appearances'; +import { rgb } from '../colors'; +import { degrees } from '../rotations'; import { RichTextFieldReadError, ExceededMaxLengthError, InvalidMaxLengthError, -} from 'src/api/errors'; -import { ImageAlignment } from 'src/api/image/alignment'; -import { TextAlignment } from 'src/api/text/alignment'; +} from '../errors'; +import { ImageAlignment } from '../image/alignment'; +import { TextAlignment } from '../text/alignment'; import { PDFHexString, PDFRef, - PDFStream, PDFAcroText, AcroTextFlags, PDFWidgetAnnotation, -} from 'src/core'; +} from '../../core'; import { assertIs, assertIsOneOf, assertOrUndefined, assertPositive, assertRangeOrUndefined, -} from 'src/utils'; +} from '../../utils'; +import { isPDFInstance, PDFClasses } from '../objects'; /** * Represents a text field of a [[PDFForm]]. @@ -47,6 +47,10 @@ import { * to be entered (see [[PDFTextField.isMultiline]]). */ export default class PDFTextField extends PDFField { + static className = () => PDFClasses.PDFTextField; + myClass(): PDFClasses { + return PDFClasses.PDFTextField; + } /** * > **NOTE:** You probably don't want to call this method directly. Instead, * > consider using the [[PDFForm.getTextField]] method, which will create an @@ -297,7 +301,7 @@ export default class PDFTextField extends PDFField { const fieldAlignment = this.getAlignment(); // prettier-ignore - const alignment = + const alignment = fieldAlignment === TextAlignment.Center ? ImageAlignment.Center : fieldAlignment === TextAlignment.Right ? ImageAlignment.Right : ImageAlignment.Left; @@ -606,7 +610,7 @@ export default class PDFTextField extends PDFField { */ enableCombing() { if (this.getMaxLength() === undefined) { - const msg = `PDFTextFields must have a max length in order to be combed`; + const msg = 'PDFTextFields must have a max length in order to be combed'; console.warn(msg); } @@ -760,8 +764,10 @@ export default class PDFTextField extends PDFField { const widgets = this.acroField.getWidgets(); for (let idx = 0, len = widgets.length; idx < len; idx++) { const widget = widgets[idx]; - const hasAppearances = - widget.getAppearances()?.normal instanceof PDFStream; + const hasAppearances = isPDFInstance( + widget.getAppearances()?.normal, + PDFClasses.PDFStream, + ); if (!hasAppearances) return true; } diff --git a/src/api/form/appearances.ts b/src/api/form/appearances.ts index 4047a9142..a1be46dc1 100644 --- a/src/api/form/appearances.ts +++ b/src/api/form/appearances.ts @@ -1,13 +1,13 @@ -import { PDFOperator, PDFWidgetAnnotation } from 'src/core'; -import PDFFont from 'src/api/PDFFont'; -import PDFButton from 'src/api/form/PDFButton'; -import PDFCheckBox from 'src/api/form/PDFCheckBox'; -import PDFDropdown from 'src/api/form/PDFDropdown'; -import PDFField from 'src/api/form/PDFField'; -import PDFOptionList from 'src/api/form/PDFOptionList'; -import PDFRadioGroup from 'src/api/form/PDFRadioGroup'; -import PDFSignature from 'src/api/form/PDFSignature'; -import PDFTextField from 'src/api/form/PDFTextField'; +import { PDFOperator, PDFWidgetAnnotation } from '../../core'; +import PDFFont from '../PDFFont'; +import PDFButton from '../form/PDFButton'; +import PDFCheckBox from '../form/PDFCheckBox'; +import PDFDropdown from '../form/PDFDropdown'; +import PDFField from '../form/PDFField'; +import PDFOptionList from '../form/PDFOptionList'; +import PDFRadioGroup from '../form/PDFRadioGroup'; +import PDFSignature from '../form/PDFSignature'; +import PDFTextField from '../form/PDFTextField'; import { drawCheckBox, rotateInPlace, @@ -15,7 +15,7 @@ import { drawButton, drawTextField, drawOptionList, -} from 'src/api/operations'; +} from '../operations'; import { rgb, componentsToColor, @@ -23,17 +23,17 @@ import { grayscale, cmyk, Color, -} from 'src/api/colors'; -import { reduceRotation, adjustDimsForRotation } from 'src/api/rotations'; +} from '../colors'; +import { reduceRotation, adjustDimsForRotation } from '../rotations'; import { layoutMultilineText, layoutCombedText, TextPosition, layoutSinglelineText, -} from 'src/api/text/layout'; -import { TextAlignment } from 'src/api/text/alignment'; -import { setFontAndSize } from 'src/api/operators'; -import { findLastMatch } from 'src/utils'; +} from '../text/layout'; +import { TextAlignment } from '../text/alignment'; +import { setFontAndSize } from '../operators'; +import { findLastMatch } from '../../utils'; /*********************** Appearance Provider Types ****************************/ @@ -90,7 +90,7 @@ export type AppearanceMapping = { normal: T; rollover?: T; down?: T }; type AppearanceOrMapping = T | AppearanceMapping; // prettier-ignore -export type AppearanceProviderFor = +export type AppearanceProviderFor = T extends PDFCheckBox ? CheckBoxAppearanceProvider : T extends PDFRadioGroup ? RadioGroupAppearanceProvider : T extends PDFButton ? ButtonAppearanceProvider @@ -102,7 +102,7 @@ export type AppearanceProviderFor = /********************* Appearance Provider Functions **************************/ -export const normalizeAppearance = ( +export const normalizeAppearance = ( appearance: T | AppearanceMapping, ): AppearanceMapping => { if ('normal' in appearance) return appearance; @@ -112,7 +112,8 @@ export const normalizeAppearance = ( // Examples: // `/Helv 12 Tf` -> ['/Helv 12 Tf', 'Helv', '12'] // `/HeBo 8.00 Tf` -> ['/HeBo 8 Tf', 'HeBo', '8.00'] -const tfRegex = /\/([^\0\t\n\f\r\ ]+)[\0\t\n\f\r\ ]+(\d*\.\d+|\d+)[\0\t\n\f\r\ ]+Tf/; +const tfRegex = + /\/([^\0\t\n\f\r ]+)[\0\t\n\f\r ]+(\d*\.\d+|\d+)[\0\t\n\f\r ]+Tf/; const getDefaultFontSize = (field: { getDefaultAppearance(): string | undefined; @@ -127,7 +128,8 @@ const getDefaultFontSize = (field: { // `0.3 g` -> ['0.3', 'g'] // `0.3 1 .3 rg` -> ['0.3', '1', '.3', 'rg'] // `0.3 1 .3 0 k` -> ['0.3', '1', '.3', '0', 'k'] -const colorRegex = /(\d*\.\d+|\d+)[\0\t\n\f\r\ ]*(\d*\.\d+|\d+)?[\0\t\n\f\r\ ]*(\d*\.\d+|\d+)?[\0\t\n\f\r\ ]*(\d*\.\d+|\d+)?[\0\t\n\f\r\ ]+(g|rg|k)/; +const colorRegex = + /(\d*\.\d+|\d+)[\0\t\n\f\r ]*(\d*\.\d+|\d+)?[\0\t\n\f\r ]*(\d*\.\d+|\d+)?[\0\t\n\f\r ]*(\d*\.\d+|\d+)?[\0\t\n\f\r ]+(g|rg|k)/; const getDefaultColor = (field: { getDefaultAppearance(): string | undefined; @@ -163,10 +165,9 @@ const updateDefaultAppearance = ( field.setDefaultAppearance(da); }; -export const defaultCheckBoxAppearanceProvider: AppearanceProviderFor = ( - checkBox, - widget, -) => { +export const defaultCheckBoxAppearanceProvider: AppearanceProviderFor< + PDFCheckBox +> = (checkBox, widget) => { // The `/DA` entry can be at the widget or field level - so we handle both const widgetColor = getDefaultColor(widget); const fieldColor = getDefaultColor(checkBox.acroField); @@ -245,10 +246,9 @@ export const defaultCheckBoxAppearanceProvider: AppearanceProviderFor = ( - radioGroup, - widget, -) => { +export const defaultRadioGroupAppearanceProvider: AppearanceProviderFor< + PDFRadioGroup +> = (radioGroup, widget) => { // The `/DA` entry can be at the widget or field level - so we handle both const widgetColor = getDefaultColor(widget); const fieldColor = getDefaultColor(radioGroup.acroField); @@ -326,11 +326,9 @@ export const defaultRadioGroupAppearanceProvider: AppearanceProviderFor = ( - button, - widget, - font, -) => { +export const defaultButtonAppearanceProvider: AppearanceProviderFor< + PDFButton +> = (button, widget, font) => { // The `/DA` entry can be at the widget or field level - so we handle both const widgetColor = getDefaultColor(widget); const fieldColor = getDefaultColor(button.acroField); @@ -416,11 +414,9 @@ export const defaultButtonAppearanceProvider: AppearanceProviderFor = }; }; -export const defaultTextFieldAppearanceProvider: AppearanceProviderFor = ( - textField, - widget, - font, -) => { +export const defaultTextFieldAppearanceProvider: AppearanceProviderFor< + PDFTextField +> = (textField, widget, font) => { // The `/DA` entry can be at the widget or field level - so we handle both const widgetColor = getDefaultColor(widget); const fieldColor = getDefaultColor(textField.acroField); @@ -508,11 +504,9 @@ export const defaultTextFieldAppearanceProvider: AppearanceProviderFor = ( - dropdown, - widget, - font, -) => { +export const defaultDropdownAppearanceProvider: AppearanceProviderFor< + PDFDropdown +> = (dropdown, widget, font) => { // The `/DA` entry can be at the widget or field level - so we handle both const widgetColor = getDefaultColor(widget); const fieldColor = getDefaultColor(dropdown.acroField); @@ -575,11 +569,9 @@ export const defaultDropdownAppearanceProvider: AppearanceProviderFor = ( - optionList, - widget, - font, -) => { +export const defaultOptionListAppearanceProvider: AppearanceProviderFor< + PDFOptionList +> = (optionList, widget, font) => { // The `/DA` entry can be at the widget or field level - so we handle both const widgetColor = getDefaultColor(widget); const fieldColor = getDefaultColor(optionList.acroField); diff --git a/src/api/form/index.ts b/src/api/form/index.ts index 12127bee7..87076dca4 100644 --- a/src/api/form/index.ts +++ b/src/api/form/index.ts @@ -1,10 +1,10 @@ -export * from 'src/api/form/appearances'; -export { default as PDFButton } from 'src/api/form/PDFButton'; -export { default as PDFCheckBox } from 'src/api/form/PDFCheckBox'; -export { default as PDFDropdown } from 'src/api/form/PDFDropdown'; -export { default as PDFField } from 'src/api/form/PDFField'; -export { default as PDFForm } from 'src/api/form/PDFForm'; -export { default as PDFOptionList } from 'src/api/form/PDFOptionList'; -export { default as PDFRadioGroup } from 'src/api/form/PDFRadioGroup'; -export { default as PDFSignature } from 'src/api/form/PDFSignature'; -export { default as PDFTextField } from 'src/api/form/PDFTextField'; +export * from './appearances'; +export { default as PDFButton } from './PDFButton'; +export { default as PDFCheckBox } from './PDFCheckBox'; +export { default as PDFDropdown } from './PDFDropdown'; +export { default as PDFField } from './PDFField'; +export { default as PDFForm } from './PDFForm'; +export { default as PDFOptionList } from './PDFOptionList'; +export { default as PDFRadioGroup } from './PDFRadioGroup'; +export { default as PDFSignature } from './PDFSignature'; +export { default as PDFTextField } from './PDFTextField'; diff --git a/src/api/image/index.ts b/src/api/image/index.ts index 171a63fb8..7186b6cbf 100644 --- a/src/api/image/index.ts +++ b/src/api/image/index.ts @@ -1 +1 @@ -export * from 'src/api/image/alignment'; +export * from './alignment'; diff --git a/src/api/index.ts b/src/api/index.ts index 677cd389d..8abc4008a 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -1,20 +1,22 @@ -export * from 'src/api/form'; -export * from 'src/api/text'; -export * from 'src/api/colors'; -export * from 'src/api/errors'; -export * from 'src/api/image'; -export * from 'src/api/objects'; -export * from 'src/api/operations'; -export * from 'src/api/operators'; -export * from 'src/api/rotations'; -export * from 'src/api/sizes'; -export * from 'src/api/PDFPageOptions'; -export * from 'src/api/PDFDocumentOptions'; -export * from 'src/api/StandardFonts'; -export { default as PDFDocument } from 'src/api/PDFDocument'; -export { default as PDFFont } from 'src/api/PDFFont'; -export { default as PDFImage } from 'src/api/PDFImage'; -export { default as PDFPage } from 'src/api/PDFPage'; -export { default as PDFEmbeddedPage } from 'src/api/PDFEmbeddedPage'; -export { default as PDFJavaScript } from 'src/api/PDFJavaScript'; -export { default as Embeddable } from 'src/api/Embeddable'; +export * from './form'; +export * from './text'; +export * from './colors'; +export * from './errors'; +export * from './image'; +export * from './objects'; +export * from './operations'; +export * from './operators'; +export * from './rotations'; +export * from './sizes'; +export * from './snapshot'; +export * from './PDFPageOptions'; +export * from './PDFDocumentOptions'; +export * from './StandardFonts'; +export { default as PDFDocument } from './PDFDocument'; +export { default as PDFFont } from './PDFFont'; +export { default as PDFImage } from './PDFImage'; +export { default as PDFPage } from './PDFPage'; +export { default as PDFEmbeddedPage } from './PDFEmbeddedPage'; +export { default as PDFJavaScript } from './PDFJavaScript'; +export { default as Embeddable } from './Embeddable'; +export { default as PDFSvg } from './PDFSvg'; diff --git a/src/api/objects.ts b/src/api/objects.ts index a6d4bbb7c..dc24378fa 100644 --- a/src/api/objects.ts +++ b/src/api/objects.ts @@ -1,10 +1,97 @@ -import { PDFName, PDFNumber } from 'src/core'; +import { PDFName, PDFNumber } from '../core'; export const asPDFName = (name: string | PDFName) => - name instanceof PDFName ? name : PDFName.of(name); + typeof name !== 'string' ? name : PDFName.of(name); export const asPDFNumber = (num: number | PDFNumber) => - num instanceof PDFNumber ? num : PDFNumber.of(num); + typeof num !== 'number' ? num : PDFNumber.of(num); export const asNumber = (num: number | PDFNumber) => - num instanceof PDFNumber ? num.asNumber() : num; + typeof num !== 'number' ? num.asNumber() : num; + +export enum PDFClasses { + PDFDict = 'PDFDict', + PDFObject = 'PDFObject', + PDFNumber = 'PDFNumber', + PDFName = 'PDFName', + PDFStream = 'PDFStream', + PDFWriter = 'PDFWriter', + PDFStreamWriter = 'PDFStreamWriter', + PDFString = 'PDFString', + PDFHexString = 'PDFHexString', + PDFDocument = 'PDFDocument', + PDFPageLeaf = 'PDFPageLeaf', + StandardFontEmbedder = 'StandardFontEmbedder', + PDFArray = 'PDFArray', + PDFButton = 'PDFButton', + PDFCheckBox = 'PDFCheckBox', + PDFDropdown = 'PDFDropdown', + PDFOptionList = 'PDFOptionList', + PDFRadioGroup = 'PDFRadioGroup', + PDFSignature = 'PDFSignature', + PDFTextField = 'PDFTextField', + PDFField = 'PDFField', + PDFRef = 'PDFRef', + PDFAcroForm = 'PDFAcroForm', + PDFAcroField = 'PDFAcroField', + PDFAcroNonTerminal = 'PDFAcroNonTerminal', + PDFAcroPushButton = 'PDFAcroPushButton', + PDFAcroCheckBox = 'PDFAcroCheckBox', + PDFAcroComboBox = 'PDFAcroComboBox', + PDFAcroListBox = 'PDFAcroListBox', + PDFAcroText = 'PDFAcroText', + PDFAcroRadioButton = 'PDFAcroRadioButton', + PDFAcroSignature = 'PDFAcroSignature', + AESBaseCipher = 'AESBaseCipher', + PDFBool = 'PDFBool', + PDFRawStream = 'PDFRawStream', + PDFContentStream = 'PDFContentStream', + Segment = 'Segment', + Rectangle = 'Rectangle', + Arc = 'Arc', + Circle = 'Circle', + Ellipse = 'Ellipse', + Line = 'Line', + Plot = 'Plot', + Point = 'Point', + PDFPageTree = 'PDFPageTree', + PDFInvalidObject = 'PDFInvalidObject', + PDFCatalog = 'PDFCatalog', + DefaultDocumentSnapshot = 'DefaultDocumentSnapshot', + PDFObjectStream = 'PDFObjectStream', + IncrementalDocumentSnapshot = 'IncrementalDocumentSnapshot', + PDFNull = 'PDFNull', +} + +/** + * Replaces instanceof operator by a "secure function" that uses clases internal identification. + * This allows complex environments, where objects comes from different library instances, to work as expected. + * @param {any} object Object to which compare the classname. + * @param {PDFClasses | typeof PDFClass} className Class name object is expected to be an instanca (or subclass instance) + * @returns {boolean} + */ +export const isPDFInstance = (object: any, className: PDFClasses): boolean => { + if (!object) return false; + if (!object.myClass) return false; // it's not an object from this library + if (typeof className === 'function') { + // is a constructor (PDFnNumber, PDFDict, etc) + try { + return isPDFInstance(object, (className as any).className()); + } catch (error) { + return false; + } + } + if (object.myClass() === className) return true; + // not a perfect match, check superclasses + let proto = Object.getPrototypeOf(object); + while (proto && proto.constructor.className) { + try { + if (proto.constructor.className() === className) return true; + proto = Object.getPrototypeOf(proto); + } catch (error) { + return false; + } + } + // not the class, nor a subclass + return false; +}; diff --git a/src/api/operations.ts b/src/api/operations.ts index 0e46e6fdf..5a87d8907 100644 --- a/src/api/operations.ts +++ b/src/api/operations.ts @@ -1,4 +1,4 @@ -import { Color, setFillingColor, setStrokingColor } from 'src/api/colors'; +import { Color, setFillingColor, setStrokingColor } from './colors'; import { beginText, closePath, @@ -30,12 +30,19 @@ import { endMarkedContent, clip, endPath, - appendBezierCurve, -} from 'src/api/operators'; -import { Rotation, degrees, toRadians } from 'src/api/rotations'; -import { svgPathToOperators } from 'src/api/svgPath'; -import { PDFHexString, PDFName, PDFNumber, PDFOperator } from 'src/core'; -import { asNumber } from 'src/api/objects'; + FillRule, + fillEvenOdd, + concatTransformationMatrix, + TextRenderingMode, + setTextRenderingMode, +} from './operators'; +import { Rotation, degrees, toDegrees, toRadians } from './rotations'; +import { svgPathToOperators } from './svgPath'; +import { PDFHexString, PDFName, PDFNumber, PDFOperator } from '../core'; +import { asNumber } from './objects'; +import type { Space, TransformationMatrix } from '../types'; +import { transformationToMatrix, combineMatrix } from './svg'; +import { identityMatrix } from '../types/matrix'; export interface DrawTextOptions { color: Color; @@ -47,8 +54,24 @@ export interface DrawTextOptions { x: number | PDFNumber; y: number | PDFNumber; graphicsState?: string | PDFName; + matrix?: TransformationMatrix; + clipSpaces?: Space[]; + strokeWidth?: number; + strokeColor?: Color; + renderMode?: TextRenderingMode; } +const clipSpace = ({ topLeft, topRight, bottomRight, bottomLeft }: Space) => [ + moveTo(topLeft.x, topLeft.y), + lineTo(topRight.x, topRight.y), + lineTo(bottomRight.x, bottomRight.y), + lineTo(bottomLeft.x, bottomLeft.y), + closePath(), + clip(), + endPath(), +]; +const clipSpaces = (spaces: Space[]) => spaces.flatMap(clipSpace); + export const drawText = ( line: PDFHexString, options: DrawTextOptions, @@ -59,6 +82,9 @@ export const drawText = ( beginText(), setFillingColor(options.color), setFontAndSize(options.font, options.size), + options.strokeWidth && setLineWidth(options.strokeWidth), + options.strokeColor && setStrokingColor(options.strokeColor), + options.renderMode && setTextRenderingMode(options.renderMode), rotateAndSkewTextRadiansAndTranslate( toRadians(options.rotate), toRadians(options.xSkew), @@ -82,10 +108,15 @@ export const drawLinesOfText = ( const operators = [ pushGraphicsState(), options.graphicsState && setGraphicsState(options.graphicsState), + ...(options.clipSpaces ? clipSpaces(options.clipSpaces) : []), + options.matrix && concatTransformationMatrix(...options.matrix), beginText(), setFillingColor(options.color), setFontAndSize(options.font, options.size), setLineHeight(options.lineHeight), + options.strokeWidth && setLineWidth(options.strokeWidth), + options.strokeColor && setStrokingColor(options.strokeColor), + options.renderMode && setTextRenderingMode(options.renderMode), rotateAndSkewTextRadiansAndTranslate( toRadians(options.rotate), toRadians(options.xSkew), @@ -114,11 +145,15 @@ export const drawImage = ( xSkew: Rotation; ySkew: Rotation; graphicsState?: string | PDFName; + matrix?: TransformationMatrix; + clipSpaces?: Space[]; }, ): PDFOperator[] => [ pushGraphicsState(), options.graphicsState && setGraphicsState(options.graphicsState), + ...(options.clipSpaces ? clipSpaces(options.clipSpaces) : []), + options.matrix && concatTransformationMatrix(...options.matrix), translate(options.x, options.y), rotateRadians(toRadians(options.rotate)), scale(options.width, options.height), @@ -160,10 +195,14 @@ export const drawLine = (options: { dashPhase?: number | PDFNumber; lineCap?: LineCapStyle; graphicsState?: string | PDFName; + matrix?: TransformationMatrix; + clipSpaces?: Space[]; }) => [ pushGraphicsState(), options.graphicsState && setGraphicsState(options.graphicsState), + ...(options.clipSpaces ? clipSpaces(options.clipSpaces) : []), + options.matrix && concatTransformationMatrix(...options.matrix), options.color && setStrokingColor(options.color), setLineWidth(options.thickness), setDashPattern(options.dashArray ?? [], options.dashPhase ?? 0), @@ -175,114 +214,96 @@ export const drawLine = (options: { popGraphicsState(), ].filter(Boolean) as PDFOperator[]; +const KAPPA = 4.0 * ((Math.sqrt(2) - 1.0) / 3.0); + export const drawRectangle = (options: { x: number | PDFNumber; y: number | PDFNumber; width: number | PDFNumber; height: number | PDFNumber; - borderWidth: number | PDFNumber; color: Color | undefined; - borderColor: Color | undefined; rotate: Rotation; xSkew: Rotation; ySkew: Rotation; + rx?: number; + ry?: number; + borderWidth: number | PDFNumber; + borderColor: Color | undefined; borderLineCap?: LineCapStyle; borderDashArray?: (number | PDFNumber)[]; borderDashPhase?: number | PDFNumber; graphicsState?: string | PDFName; -}) => - [ - pushGraphicsState(), - options.graphicsState && setGraphicsState(options.graphicsState), - options.color && setFillingColor(options.color), - options.borderColor && setStrokingColor(options.borderColor), - setLineWidth(options.borderWidth), - options.borderLineCap && setLineCap(options.borderLineCap), - setDashPattern(options.borderDashArray ?? [], options.borderDashPhase ?? 0), - translate(options.x, options.y), - rotateRadians(toRadians(options.rotate)), - skewRadians(toRadians(options.xSkew), toRadians(options.ySkew)), - moveTo(0, 0), - lineTo(0, options.height), - lineTo(options.width, options.height), - lineTo(options.width, 0), - closePath(), - - // prettier-ignore - options.color && options.borderWidth ? fillAndStroke() - : options.color ? fill() - : options.borderColor ? stroke() - : closePath(), - - popGraphicsState(), - ].filter(Boolean) as PDFOperator[]; - -const KAPPA = 4.0 * ((Math.sqrt(2) - 1.0) / 3.0); - -/** @deprecated */ -export const drawEllipsePath = (config: { - x: number | PDFNumber; - y: number | PDFNumber; - xScale: number | PDFNumber; - yScale: number | PDFNumber; -}): PDFOperator[] => { - let x = asNumber(config.x); - let y = asNumber(config.y); - const xScale = asNumber(config.xScale); - const yScale = asNumber(config.yScale); - - x -= xScale; - y -= yScale; - - const ox = xScale * KAPPA; - const oy = yScale * KAPPA; - const xe = x + xScale * 2; - const ye = y + yScale * 2; - const xm = x + xScale; - const ym = y + yScale; - - return [ - pushGraphicsState(), - moveTo(x, ym), - appendBezierCurve(x, ym - oy, xm - ox, y, xm, y), - appendBezierCurve(xm + ox, y, xe, ym - oy, xe, ym), - appendBezierCurve(xe, ym + oy, xm + ox, ye, xm, ye), - appendBezierCurve(xm - ox, ye, x, ym + oy, x, ym), - popGraphicsState(), - ]; -}; - -const drawEllipseCurves = (config: { - x: number | PDFNumber; - y: number | PDFNumber; - xScale: number | PDFNumber; - yScale: number | PDFNumber; - rotate: Rotation; -}): PDFOperator[] => { - const centerX = asNumber(config.x); - const centerY = asNumber(config.y); - const xScale = asNumber(config.xScale); - const yScale = asNumber(config.yScale); - - const x = -xScale; - const y = -yScale; - - const ox = xScale * KAPPA; - const oy = yScale * KAPPA; - const xe = x + xScale * 2; - const ye = y + yScale * 2; - const xm = x + xScale; - const ym = y + yScale; + matrix?: TransformationMatrix; + clipSpaces?: Space[]; +}) => { + const { width, height, xSkew, ySkew, rotate, matrix } = options; + const w = typeof width === 'number' ? width : width.asNumber(); + const h = typeof height === 'number' ? height : height.asNumber(); + const x = typeof options.x === 'number' ? options.x : options.x.asNumber(); + const y = typeof options.y === 'number' ? options.y : options.y.asNumber(); + + // Ensure rx and ry are within bounds + const rx = Math.max(0, Math.min(options.rx || 0, w / 2)); + const ry = Math.max(0, Math.min(options.ry || 0, h / 2)); + + // Generate the SVG path + const d = + rx > 0 || ry > 0 + ? [ + `M ${rx},0`, + `H ${w - rx}`, + `C ${w - rx * (1 - KAPPA)},0 ${w},${ry * (1 - KAPPA)} ${w},${ry}`, + `V ${h - ry}`, + `C ${w},${h - ry * (1 - KAPPA)} ${w - rx * (1 - KAPPA)},${h} ${w - rx},${h}`, + `H ${rx}`, + `C ${rx * (1 - KAPPA)},${h} 0,${h - ry * (1 - KAPPA)} 0,${h - ry}`, + `V ${ry}`, + `C 0,${ry * (1 - KAPPA)} ${rx * (1 - KAPPA)},0 ${rx},0`, + 'Z', + ].join(' ') + : `M 0,0 H ${w} V ${h} H 0 Z`; + + // the drawRectangle applies the rotation around its anchor point (bottom-left), it means that the translation should be applied before the rotation + // invert the y parameter because transformationToMatrix expects parameters from an svg space. The same is valid for rotate and ySkew + let fullMatrix = combineMatrix( + matrix || identityMatrix, + transformationToMatrix('translate', [x, -y]), + ); + + // Transformation to apply rotation and skew + if (rotate) { + fullMatrix = combineMatrix( + fullMatrix, + transformationToMatrix('rotate', [-toDegrees(rotate)]), + ); + } + if (xSkew) { + fullMatrix = combineMatrix( + fullMatrix, + transformationToMatrix('skewX', [toDegrees(xSkew)]), + ); + } + if (ySkew) { + fullMatrix = combineMatrix( + fullMatrix, + transformationToMatrix('skewY', [-toDegrees(ySkew)]), + ); + } - return [ - translate(centerX, centerY), - rotateRadians(toRadians(config.rotate)), - moveTo(x, ym), - appendBezierCurve(x, ym - oy, xm - ox, y, xm, y), - appendBezierCurve(xm + ox, y, xe, ym - oy, xe, ym), - appendBezierCurve(xe, ym + oy, xm + ox, ye, xm, ye), - appendBezierCurve(xm - ox, ye, x, ym + oy, x, ym), - ]; + // move the rectangle upward so that the (x, y) coord is bottom-left + fullMatrix = combineMatrix( + fullMatrix, + transformationToMatrix('translateY', [-h]), + ); + + return drawSvgPath(d, { + ...options, + x: 0, + y: 0, + rotate: degrees(0), // Already applied in matrix transform + scale: 1, + matrix: fullMatrix, + }); }; export const drawEllipse = (options: { @@ -298,41 +319,48 @@ export const drawEllipse = (options: { borderDashPhase?: number | PDFNumber; graphicsState?: string | PDFName; borderLineCap?: LineCapStyle; -}) => - [ - pushGraphicsState(), - options.graphicsState && setGraphicsState(options.graphicsState), - options.color && setFillingColor(options.color), - options.borderColor && setStrokingColor(options.borderColor), - setLineWidth(options.borderWidth), - options.borderLineCap && setLineCap(options.borderLineCap), - setDashPattern(options.borderDashArray ?? [], options.borderDashPhase ?? 0), + matrix?: TransformationMatrix; + clipSpaces?: Space[]; +}) => { + const xScale = asNumber(options.xScale); + const yScale = asNumber(options.yScale); + const x = asNumber(options.x); + const y = asNumber(options.y); - // The `drawEllipsePath` branch is only here for backwards compatibility. - // See https://github.com/Hopding/pdf-lib/pull/511#issuecomment-667685655. - ...(options.rotate === undefined - ? drawEllipsePath({ - x: options.x, - y: options.y, - xScale: options.xScale, - yScale: options.yScale, - }) - : drawEllipseCurves({ - x: options.x, - y: options.y, - xScale: options.xScale, - yScale: options.yScale, - rotate: options.rotate ?? degrees(0), - })), - - // prettier-ignore - options.color && options.borderWidth ? fillAndStroke() - : options.color ? fill() - : options.borderColor ? stroke() - : closePath(), + const KAPPA = 4.0 * ((Math.sqrt(2) - 1.0) / 3.0); + const ox = xScale * KAPPA; + const oy = yScale * KAPPA; - popGraphicsState(), - ].filter(Boolean) as PDFOperator[]; + // Path en sens mathématique (y vers le haut) + const d = [ + `M 0,${yScale}`, + `C ${ox},${yScale} ${xScale},${oy} ${xScale},0`, + `C ${xScale},${-oy} ${ox},${-yScale} 0,${-yScale}`, + `C ${-ox},${-yScale} ${-xScale},${-oy} ${-xScale},0`, + `C ${-xScale},${oy} ${-ox},${yScale} 0,${yScale}`, + 'Z', + ].join(' '); + + let fullMatrix = combineMatrix( + options.matrix || identityMatrix, + transformationToMatrix('translate', [x, -y]), + ); + if (options.rotate) { + fullMatrix = combineMatrix( + fullMatrix, + transformationToMatrix('rotate', [-toDegrees(options.rotate)]), + ); + } + + return drawSvgPath(d, { + ...options, + x: 0, + y: 0, + rotate: degrees(0), + scale: 1, // Laisse le flip vertical de drawSvgPath + matrix: fullMatrix, + }); +}; export const drawSvgPath = ( path: string, @@ -348,18 +376,28 @@ export const drawSvgPath = ( borderDashPhase?: number | PDFNumber; borderLineCap?: LineCapStyle; graphicsState?: string | PDFName; + fillRule?: FillRule; + matrix?: TransformationMatrix; + clipSpaces?: Space[]; }, -) => - [ +) => { + const drawingOperator = getDrawingOperator(options); + if (!drawingOperator) { + // no-op when there is no fill and no border color/width. + return []; + } + + return [ pushGraphicsState(), options.graphicsState && setGraphicsState(options.graphicsState), + ...(options.clipSpaces ? clipSpaces(options.clipSpaces) : []), + options.matrix && concatTransformationMatrix(...options.matrix), translate(options.x, options.y), rotateRadians(toRadians(options.rotate ?? degrees(0))), // SVG path Y axis is opposite pdf-lib's options.scale ? scale(options.scale, -options.scale) : scale(1, -1), - options.color && setFillingColor(options.color), options.borderColor && setStrokingColor(options.borderColor), options.borderWidth && setLineWidth(options.borderWidth), @@ -369,14 +407,11 @@ export const drawSvgPath = ( ...svgPathToOperators(path), - // prettier-ignore - options.color && options.borderWidth ? fillAndStroke() - : options.color ? fill() - : options.borderColor ? stroke() - : closePath(), + drawingOperator(), popGraphicsState(), ].filter(Boolean) as PDFOperator[]; +}; export const drawCheckMark = (options: { x: number | PDFNumber; @@ -798,3 +833,24 @@ export const drawOptionList = (options: { popGraphicsState(), ]; }; + +const getDrawingOperator = ({ + color, + borderWidth, + borderColor, + fillRule, +}: { + color?: Color; + borderWidth?: number | PDFNumber; + borderColor?: Color; + fillRule?: FillRule; +}) => { + if (color && borderColor && borderWidth !== 0) { + return fillAndStroke; + } else if (color) { + return fillRule === FillRule.EvenOdd ? fillEvenOdd : fill; + } else if (borderColor && borderWidth !== 0) { + return stroke; + } + return undefined; +}; diff --git a/src/api/operators.ts b/src/api/operators.ts index 62b5e3a24..b5cd4c6f3 100644 --- a/src/api/operators.ts +++ b/src/api/operators.ts @@ -1,12 +1,44 @@ -import { asNumber, asPDFName, asPDFNumber } from 'src/api/objects'; -import { degreesToRadians } from 'src/api/rotations'; +/** =============== There is a circular dependency =============== + * To avoid inclusion "undefined" elementos, enums are declared before + * imports. + */ +export enum LineCapStyle { + Butt = 0, + Round = 1, + Projecting = 2, +} + +export enum LineJoinStyle { + Miter = 0, + Round = 1, + Bevel = 2, +} + +export enum FillRule { + NonZero = 'f', + EvenOdd = 'f*', +} + +export enum TextRenderingMode { + Fill = 0, + Outline = 1, + FillAndOutline = 2, + Invisible = 3, + FillAndClip = 4, + OutlineAndClip = 5, + FillAndOutlineAndClip = 6, + Clip = 7, +} + +import { asNumber, asPDFName, asPDFNumber } from './objects'; +import { degreesToRadians } from './rotations'; import { PDFHexString, PDFName, PDFNumber, PDFOperator, PDFOperatorNames as Ops, -} from 'src/core'; +} from '../core'; /* ==================== Clipping Path Operators ==================== */ @@ -86,21 +118,9 @@ export const setDashPattern = ( export const restoreDashPattern = () => setDashPattern([], 0); -export enum LineCapStyle { - Butt = 0, - Round = 1, - Projecting = 2, -} - export const setLineCap = (style: LineCapStyle) => PDFOperator.of(Ops.SetLineCapStyle, [asPDFNumber(style)]); -export enum LineJoinStyle { - Miter = 0, - Round = 1, - Bevel = 2, -} - export const setLineJoin = (style: LineJoinStyle) => PDFOperator.of(Ops.SetLineJoinStyle, [asPDFNumber(style)]); @@ -187,6 +207,8 @@ export const stroke = () => PDFOperator.of(Ops.StrokePath); export const fill = () => PDFOperator.of(Ops.FillNonZero); +export const fillEvenOdd = () => PDFOperator.of(Ops.FillEvenOdd); + export const fillAndStroke = () => PDFOperator.of(Ops.FillNonZeroAndStroke); export const endPath = () => PDFOperator.of(Ops.EndPath); @@ -229,17 +251,6 @@ export const setLineHeight = (lineHeight: number | PDFNumber) => export const setTextRise = (rise: number | PDFNumber) => PDFOperator.of(Ops.SetTextRise, [asPDFNumber(rise)]); -export enum TextRenderingMode { - Fill = 0, - Outline = 1, - FillAndOutline = 2, - Invisible = 3, - FillAndClip = 4, - OutlineAndClip = 5, - FillAndOutlineAndClip = 6, - Clip = 7, -} - export const setTextRenderingMode = (mode: TextRenderingMode) => PDFOperator.of(Ops.SetTextRenderingMode, [asPDFNumber(mode)]); diff --git a/src/api/rotations.ts b/src/api/rotations.ts index bd727041e..a33bba7f2 100644 --- a/src/api/rotations.ts +++ b/src/api/rotations.ts @@ -1,4 +1,4 @@ -import { assertIs, error } from 'src/utils'; +import { assertIs, error } from '../utils'; export enum RotationTypes { Degrees = 'degrees', @@ -27,21 +27,19 @@ export const degrees = (degreeAngle: number): Degrees => { return { type: RotationTypes.Degrees, angle: degreeAngle }; }; -const { Radians, Degrees } = RotationTypes; - export const degreesToRadians = (degree: number) => (degree * Math.PI) / 180; export const radiansToDegrees = (radian: number) => (radian * 180) / Math.PI; // prettier-ignore -export const toRadians = (rotation: Rotation) => - rotation.type === Radians ? rotation.angle - : rotation.type === Degrees ? degreesToRadians(rotation.angle) +export const toRadians = (rotation: Rotation) => + rotation.type === RotationTypes.Radians ? rotation.angle + : rotation.type === RotationTypes.Degrees ? degreesToRadians(rotation.angle) : error(`Invalid rotation: ${JSON.stringify(rotation)}`); // prettier-ignore -export const toDegrees = (rotation: Rotation) => - rotation.type === Radians ? radiansToDegrees(rotation.angle) - : rotation.type === Degrees ? rotation.angle +export const toDegrees = (rotation: Rotation) => + rotation.type === RotationTypes.Radians ? radiansToDegrees(rotation.angle) + : rotation.type === RotationTypes.Degrees ? rotation.angle : error(`Invalid rotation: ${JSON.stringify(rotation)}`); export const reduceRotation = (degreeAngle = 0) => { diff --git a/src/api/snapshot/DefaultDocumentSnapshot.ts b/src/api/snapshot/DefaultDocumentSnapshot.ts new file mode 100644 index 000000000..4c16d303c --- /dev/null +++ b/src/api/snapshot/DefaultDocumentSnapshot.ts @@ -0,0 +1,48 @@ +import type { PDFObject, PDFRef } from '../../core'; +import { PDFClasses } from '../objects'; +import type { DocumentSnapshot } from './DocumentSnapshot'; + +export class DefaultDocumentSnapshot implements DocumentSnapshot { + static className = () => PDFClasses.DefaultDocumentSnapshot; + myClass(): PDFClasses { + return PDFClasses.DefaultDocumentSnapshot; + } + + pdfSize = 0; + prevStartXRef = 0; + deletedCount = 0; + + shouldSave(_objectNumber: number): boolean { + return true; + } + + markRefForSave(_ref: PDFRef): void { + throw new Error('This method should not be called.'); + } + + markRefsForSave(_refs: PDFRef[]): void { + throw new Error('This method should not be called.'); + } + + markObjForSave(_obj: PDFObject): void { + throw new Error('This method should not be called.'); + } + + markObjsForSave(_objs: PDFObject[]): void { + throw new Error('This method should not be called.'); + } + + markDeletedObj(_obj: PDFObject): void { + throw new Error('This method should not be called.'); + } + + markDeletedRef(_ref: PDFRef): void { + throw new Error('This method should not be called.'); + } + + deletedRef(_index: number): PDFRef | null { + throw new Error('This method should not be called.'); + } +} + +export const defaultDocumentSnapshot = new DefaultDocumentSnapshot(); diff --git a/src/api/snapshot/DocumentSnapshot.ts b/src/api/snapshot/DocumentSnapshot.ts new file mode 100644 index 000000000..fa5f3b8d5 --- /dev/null +++ b/src/api/snapshot/DocumentSnapshot.ts @@ -0,0 +1,23 @@ +import type { PDFObject, PDFRef } from '../../core'; +import { PDFClasses } from '../objects'; + +export interface DocumentSnapshot { + pdfSize: number; + prevStartXRef: number; + deletedCount: number; + + myClass: () => PDFClasses; + + shouldSave: (objectNumber: number) => boolean; + + markRefForSave: (ref: PDFRef) => void; + markRefsForSave: (refs: PDFRef[]) => void; + + markObjForSave: (obj: PDFObject) => void; + markObjsForSave: (objs: PDFObject[]) => void; + + markDeletedRef: (ref: PDFRef) => void; + markDeletedObj: (obj: PDFObject) => void; + + deletedRef: (index: number) => PDFRef | null; +} diff --git a/src/api/snapshot/IncrementalDocumentSnapshot.ts b/src/api/snapshot/IncrementalDocumentSnapshot.ts new file mode 100644 index 000000000..846f91a21 --- /dev/null +++ b/src/api/snapshot/IncrementalDocumentSnapshot.ts @@ -0,0 +1,79 @@ +import type { PDFContext, PDFObject, PDFRef } from '../../core'; +import { PDFClasses } from '../objects'; +import type { DocumentSnapshot } from './DocumentSnapshot'; + +export class IncrementalDocumentSnapshot implements DocumentSnapshot { + pdfSize: number; + prevStartXRef: number; + deletedCount: number = 0; + + private deleted: PDFRef[] = []; + private lastObjectNumber: number; + private changedObjects: Set; + + context: PDFContext; + + constructor( + lastObjectNumber: number, + indirectObjects: Set, + pdfSize: number, + prevStartXRef: number, + context: PDFContext, + ) { + this.lastObjectNumber = lastObjectNumber; + this.changedObjects = indirectObjects; + this.pdfSize = pdfSize; + this.prevStartXRef = prevStartXRef; + this.context = context; + } + + static className = () => PDFClasses.IncrementalDocumentSnapshot; + myClass(): PDFClasses { + return PDFClasses.IncrementalDocumentSnapshot; + } + + shouldSave(objectNumber: number): boolean { + if (objectNumber > this.lastObjectNumber) return true; + return this.changedObjects.has(objectNumber); + } + + markRefForSave(ref: PDFRef): void { + this.markRefsForSave([ref]); + } + + markRefsForSave(refs: PDFRef[]): void { + refs.forEach((ref) => { + if (ref) this.changedObjects.add(ref.objectNumber); + }); + } + + markObjForSave(obj: PDFObject): void { + this.markObjsForSave([obj]); + } + + markObjsForSave(objs: PDFObject[]): void { + this.markRefsForSave( + objs + .map((obj) => this.context.getRef(obj)) + .filter((ref) => ref !== undefined) as PDFRef[], + ); + } + + markDeletedRef(ref: PDFRef): void { + if ( + this.deleted.findIndex((dref) => dref.objectNumber === ref.objectNumber) < + 0 + ) + this.deletedCount = this.deleted.push(ref); + } + + markDeletedObj(obj: PDFObject): void { + const oref = this.context.getRef(obj); + if (oref) this.markDeletedRef(oref); + } + + deletedRef(index: number): PDFRef | null { + if (index < 0 || index >= this.deleted.length) return null; + return this.deleted[index]; + } +} diff --git a/src/api/snapshot/index.ts b/src/api/snapshot/index.ts new file mode 100644 index 000000000..d3b02ac2f --- /dev/null +++ b/src/api/snapshot/index.ts @@ -0,0 +1,3 @@ +export * from './DocumentSnapshot'; +export * from './DefaultDocumentSnapshot'; +export * from './IncrementalDocumentSnapshot'; diff --git a/src/api/svg.ts b/src/api/svg.ts new file mode 100644 index 000000000..06a624a23 --- /dev/null +++ b/src/api/svg.ts @@ -0,0 +1,1074 @@ +import { + parse as parseHtml, + HTMLElement, + Attributes, + Node, + NodeType, +} from 'node-html-better-parser'; +import { Color, colorString } from './colors'; +import { Degrees, degreesToRadians } from './rotations'; +import PDFFont from './PDFFont'; +import PDFPage from './PDFPage'; +import PDFSvg from './PDFSvg'; +import { BlendMode, PDFPageDrawSVGElementOptions } from './PDFPageOptions'; +import { LineCapStyle, LineJoinStyle, FillRule } from './operators'; +import { TransformationMatrix, identityMatrix } from '../types/matrix'; +import { Coordinates, Space } from '../types'; + +interface Position { + x: number; + y: number; +} + +interface Size { + width: number; + height: number; +} + +type Box = Position & Size; + +type SVGStyle = Record; + +type InheritedAttributes = { + width: number; + height: number; + fill?: Color; + fillOpacity?: number; + stroke?: Color; + strokeWidth?: number; + strokeOpacity?: number; + strokeLineCap?: LineCapStyle; + fillRule?: FillRule; + strokeLineJoin?: LineJoinStyle; + fontFamily?: string; + fontStyle?: string; + fontWeight?: string; + fontSize?: number; + rotation?: Degrees; + viewBox: Box; + blendMode?: BlendMode; +}; +type SVGAttributes = { + rotate?: Degrees; + scale?: number; + skewX?: Degrees; + skewY?: Degrees; + width?: number; + height?: number; + x?: number; + y?: number; + cx?: number; + cy?: number; + r?: number; + rx?: number; + ry?: number; + x1?: number; + y1?: number; + x2?: number; + y2?: number; + d?: string; + src?: string; + textAnchor?: string; + preserveAspectRatio?: string; + strokeWidth?: number; + dominantBaseline?: + | 'auto' + | 'text-bottom' + | 'alphabetic' + | 'ideographic' + | 'middle' + | 'central' + | 'mathematical' + | 'hanging' + | 'text-top' + | 'use-script' + | 'no-change' + | 'reset-size' + | 'text-after-edge' + | 'text-before-edge'; + points?: string; +}; + +type TransformAttributes = { + matrix: TransformationMatrix; + clipSpaces: Space[]; +}; + +export type SVGElement = HTMLElement & { + svgAttributes: InheritedAttributes & SVGAttributes & TransformAttributes; +}; + +interface SVGElementToDrawMap { + [cmd: string]: (a: SVGElement) => void; +} + +export const combineMatrix = ( + [a, b, c, d, e, f]: TransformationMatrix, + [a2, b2, c2, d2, e2, f2]: TransformationMatrix, +): TransformationMatrix => [ + a * a2 + c * b2, + b * a2 + d * b2, + a * c2 + c * d2, + b * c2 + d * d2, + a * e2 + c * f2 + e, + b * e2 + d * f2 + f, +]; + +const applyTransformation = ( + [a, b, c, d, e, f]: TransformationMatrix, + { x, y }: Coordinates, +): Coordinates => ({ + x: a * x + c * y + e, + y: b * x + d * y + f, +}); + +type TransformationName = + | 'scale' + | 'scaleX' + | 'scaleY' + | 'translate' + | 'translateX' + | 'translateY' + | 'rotate' + | 'skewX' + | 'skewY' + | 'matrix'; +export const transformationToMatrix = ( + name: TransformationName, + args: number[], +): TransformationMatrix => { + switch (name) { + case 'scale': + case 'scaleX': + case 'scaleY': { + // [sx 0 0 sy 0 0] + const [sx, sy = sx] = args; + return [ + name === 'scaleY' ? 1 : sx, + 0, + 0, + name === 'scaleX' ? 1 : sy, + 0, + 0, + ]; + } + case 'translate': + case 'translateX': + case 'translateY': { + // [1 0 0 1 tx ty] + const [tx, ty = tx] = args; + // -ty is necessary because the pdf's y axis is inverted + return [ + 1, + 0, + 0, + 1, + name === 'translateY' ? 0 : tx, + name === 'translateX' ? 0 : -ty, + ]; + } + case 'rotate': { + // [cos(a) sin(a) -sin(a) cos(a) 0 0] + const [a, x = 0, y = 0] = args; + const t1 = transformationToMatrix('translate', [x, y]); + const t2 = transformationToMatrix('translate', [-x, -y]); + // -args[0] -> the '-' operator is necessary because the pdf rotation system is inverted + const aRadians = degreesToRadians(-a); + const r: TransformationMatrix = [ + Math.cos(aRadians), + Math.sin(aRadians), + -Math.sin(aRadians), + Math.cos(aRadians), + 0, + 0, + ]; + // rotation around a point is the combination of: translate * rotate * (-translate) + return combineMatrix(combineMatrix(t1, r), t2); + } + case 'skewY': + case 'skewX': { + // [1 tan(a) 0 1 0 0] + // [1 0 tan(a) 1 0 0] + // -args[0] -> the '-' operator is necessary because the pdf rotation system is inverted + const a = degreesToRadians(-args[0]); + const skew = Math.tan(a); + const skewX = name === 'skewX' ? skew : 0; + const skewY = name === 'skewY' ? skew : 0; + return [1, skewY, skewX, 1, 0, 0]; + } + case 'matrix': { + const [a, b, c, d, e, f] = args; + const r = transformationToMatrix('scale', [1, -1]); + const m: TransformationMatrix = [a, b, c, d, e, f]; + return combineMatrix(combineMatrix(r, m), r); + } + default: + return identityMatrix; + } +}; + +const combineTransformation = ( + matrix: TransformationMatrix, + name: TransformationName, + args: number[], +) => combineMatrix(matrix, transformationToMatrix(name, args)); + +const StrokeLineCapMap: Record = { + butt: LineCapStyle.Butt, + round: LineCapStyle.Round, + square: LineCapStyle.Projecting, +}; + +const FillRuleMap: Record = { + evenodd: FillRule.EvenOdd, + nonzero: FillRule.NonZero, +}; + +const StrokeLineJoinMap: Record = { + bevel: LineJoinStyle.Bevel, + miter: LineJoinStyle.Miter, + round: LineJoinStyle.Round, +}; + +// TODO: Improve type system to require the correct props for each tagName. +/** methods to draw SVGElements onto a PDFPage */ +const runnersToPage = ( + page: PDFPage, + options: PDFPageDrawSVGElementOptions & { images?: PDFSvg['images'] }, +): SVGElementToDrawMap => ({ + text(element) { + const anchor = element.svgAttributes.textAnchor; + const dominantBaseline = element.svgAttributes.dominantBaseline; + const text = element.text.trim().replace(/\s/g, ' '); + const fontSize = element.svgAttributes.fontSize || 12; + + /** This will find the best font for the provided style in the list */ + const getBestFont = ( + style: InheritedAttributes, + fonts: { [fontName: string]: PDFFont }, + ) => { + const family = style.fontFamily; + if (!family) return undefined; + const isBold = + style.fontWeight === 'bold' || Number(style.fontWeight) >= 700; + const isItalic = style.fontStyle === 'italic'; + const getFont = (bold: boolean, italic: boolean, fontFamily: string) => + fonts[fontFamily + (bold ? '_bold' : '') + (italic ? '_italic' : '')]; + const key = Object.keys(fonts).find((fontFamily) => + fontFamily.startsWith(family), + ); + return ( + getFont(isBold, isItalic, family) || + getFont(isBold, false, family) || + getFont(false, isItalic, family) || + getFont(false, false, family) || + (key ? fonts[key] : undefined) + ); + }; + + const font = + options.fonts && getBestFont(element.svgAttributes, options.fonts); + const textWidth = (font || page.getFont()[0]).widthOfTextAtSize( + text, + fontSize, + ); + + const textHeight = (font || page.getFont()[0]).heightAtSize(fontSize); + const overLineHeight = (font || page.getFont()[0]).heightAtSize(fontSize, { + descender: false, + }); + const offsetX = + anchor === 'middle' ? textWidth / 2 : anchor === 'end' ? textWidth : 0; + + let offsetY = 0; + switch (dominantBaseline) { + case 'middle': + case 'central': + offsetY = overLineHeight - textHeight / 2; + break; + case 'mathematical': + offsetY = fontSize * 0.6; // Mathematical (approximation) + break; + case 'hanging': + offsetY = overLineHeight; // Hanging baseline is at the top + break; + case 'text-before-edge': + offsetY = fontSize; // Top of the text + break; + case 'ideographic': + case 'text-after-edge': + offsetY = overLineHeight - textHeight; // After edge (similar to text-bottom) + break; + case 'text-top': + case 'text-bottom': + case 'auto': + case 'use-script': + case 'no-change': + case 'reset-size': + case 'alphabetic': + default: + offsetY = 0; // Default to alphabetic if not specified + break; + } + page.drawText(text, { + x: -offsetX, + y: -offsetY, + font, + // TODO: the font size should be correctly scaled too + size: fontSize, + color: element.svgAttributes.fill, + opacity: element.svgAttributes.fillOpacity, + matrix: element.svgAttributes.matrix, + clipSpaces: element.svgAttributes.clipSpaces, + blendMode: element.svgAttributes.blendMode || options.blendMode, + }); + }, + line(element) { + page.drawLine({ + start: { + x: element.svgAttributes.x1 || 0, + y: -element.svgAttributes.y1! || 0, + }, + end: { + x: element.svgAttributes.x2! || 0, + y: -element.svgAttributes.y2! || 0, + }, + thickness: element.svgAttributes.strokeWidth, + color: element.svgAttributes.stroke, + opacity: element.svgAttributes.strokeOpacity, + lineCap: element.svgAttributes.strokeLineCap, + matrix: element.svgAttributes.matrix, + clipSpaces: element.svgAttributes.clipSpaces, + blendMode: element.svgAttributes.blendMode || options.blendMode, + }); + }, + path(element) { + if (!element.svgAttributes.d) return; + // See https://jsbin.com/kawifomupa/edit?html,output and + page.drawSvgPath(element.svgAttributes.d, { + x: 0, + y: 0, + borderColor: element.svgAttributes.stroke, + borderWidth: element.svgAttributes.strokeWidth, + borderOpacity: element.svgAttributes.strokeOpacity, + borderLineCap: element.svgAttributes.strokeLineCap, + color: element.svgAttributes.fill, + opacity: element.svgAttributes.fillOpacity, + fillRule: element.svgAttributes.fillRule, + // drawSvgPath already handle the page y coord correctly, so we can undo the svg parsing correction + matrix: combineTransformation( + element.svgAttributes.matrix, + 'scale', + [1, -1], + ), + clipSpaces: element.svgAttributes.clipSpaces, + blendMode: element.svgAttributes.blendMode || options.blendMode, + }); + }, + image(element) { + const { src } = element.svgAttributes; + if (!(src && options.images?.[src])) return; + const img = options.images?.[src]!; + + const { x, y, width, height } = getFittingRectangle( + img.width, + img.height, + element.svgAttributes.width || img.width, + element.svgAttributes.height || img.height, + element.svgAttributes.preserveAspectRatio, + ); + page.drawImage(img, { + x, + y: -y - height, + width, + height, + opacity: element.svgAttributes.fillOpacity, + matrix: element.svgAttributes.matrix, + clipSpaces: element.svgAttributes.clipSpaces, + blendMode: element.svgAttributes.blendMode || options.blendMode, + }); + }, + rect(element) { + if (!element.svgAttributes.fill && !element.svgAttributes.stroke) return; + page.drawRectangle({ + x: 0, + y: 0, + width: element.svgAttributes.width, + height: element.svgAttributes.height, + rx: element.svgAttributes.rx, + ry: element.svgAttributes.ry, + borderColor: element.svgAttributes.stroke, + borderWidth: element.svgAttributes.strokeWidth, + borderOpacity: element.svgAttributes.strokeOpacity, + borderLineCap: element.svgAttributes.strokeLineCap, + color: element.svgAttributes.fill, + opacity: element.svgAttributes.fillOpacity, + matrix: combineTransformation( + element.svgAttributes.matrix, + 'translateY', + [element.svgAttributes.height], + ), + clipSpaces: element.svgAttributes.clipSpaces, + blendMode: element.svgAttributes.blendMode || options.blendMode, + }); + }, + ellipse(element) { + page.drawEllipse({ + x: element.svgAttributes.cx || 0, + y: -(element.svgAttributes.cy || 0), + xScale: element.svgAttributes.rx, + yScale: element.svgAttributes.ry, + borderColor: element.svgAttributes.stroke, + borderWidth: element.svgAttributes.strokeWidth, + borderOpacity: element.svgAttributes.strokeOpacity, + borderLineCap: element.svgAttributes.strokeLineCap, + color: element.svgAttributes.fill, + opacity: element.svgAttributes.fillOpacity, + matrix: element.svgAttributes.matrix, + clipSpaces: element.svgAttributes.clipSpaces, + blendMode: element.svgAttributes.blendMode || options.blendMode, + }); + }, + circle(element) { + return runnersToPage(page, options).ellipse(element); + }, +}); + +const styleOrAttribute = ( + attributes: Attributes, + style: SVGStyle, + attribute: string, + def?: string, +): string => { + const value = style[attribute] || attributes[attribute]; + if (!value && typeof def !== 'undefined') return def; + return value; +}; + +const parseStyles = (style: string): SVGStyle => { + const cssRegex = /([^:\s]+)*\s*:\s*([^;]+)/g; + const css: SVGStyle = {}; + let match = cssRegex.exec(style); + while (match !== null) { + css[match[1]] = match[2]; + match = cssRegex.exec(style); + } + return css; +}; + +const parseColor = ( + color: string, + inherited?: { rgb: Color; alpha?: string }, +): { rgb: Color; alpha?: string } | undefined => { + if (!color || color.length === 0) return undefined; + if (['none', 'transparent'].includes(color)) return undefined; + if (color === 'currentColor') return inherited || parseColor('#000000'); + const parsedColor = colorString(color); + return { + rgb: parsedColor.rgb, + alpha: parsedColor.alpha ? parsedColor.alpha + '' : undefined, + }; +}; + +type ParsedAttributes = { + inherited: InheritedAttributes; + tagName: string; + svgAttributes: SVGAttributes; + matrix: TransformationMatrix; +}; + +const parseAttributes = ( + element: HTMLElement, + inherited: InheritedAttributes, + matrix: TransformationMatrix, +): ParsedAttributes => { + const attributes = element.attributes; + const style = parseStyles(attributes.style); + const widthRaw = styleOrAttribute(attributes, style, 'width', ''); + const heightRaw = styleOrAttribute(attributes, style, 'height', ''); + const fillRaw = parseColor(styleOrAttribute(attributes, style, 'fill')); + const fillOpacityRaw = styleOrAttribute(attributes, style, 'fill-opacity'); + const opacityRaw = styleOrAttribute(attributes, style, 'opacity'); + const strokeRaw = parseColor(styleOrAttribute(attributes, style, 'stroke')); + const strokeOpacityRaw = styleOrAttribute( + attributes, + style, + 'stroke-opacity', + ); + const strokeLineCapRaw = styleOrAttribute( + attributes, + style, + 'stroke-linecap', + ); + const strokeLineJoinRaw = styleOrAttribute( + attributes, + style, + 'stroke-linejoin', + ); + const fillRuleRaw = styleOrAttribute(attributes, style, 'fill-rule'); + const strokeWidthRaw = styleOrAttribute(attributes, style, 'stroke-width'); + const fontFamilyRaw = styleOrAttribute(attributes, style, 'font-family'); + const fontStyleRaw = styleOrAttribute(attributes, style, 'font-style'); + const fontWeightRaw = styleOrAttribute(attributes, style, 'font-weight'); + const fontSizeRaw = styleOrAttribute(attributes, style, 'font-size'); + const blendModeRaw = styleOrAttribute(attributes, style, 'mix-blend-mode'); + + const width = parseFloatValue(widthRaw, inherited.width); + const height = parseFloatValue(heightRaw, inherited.height); + const x = parseFloatValue(attributes.x, inherited.width); + const y = parseFloatValue(attributes.y, inherited.height); + const x1 = parseFloatValue(attributes.x1, inherited.width); + const x2 = parseFloatValue(attributes.x2, inherited.width); + const y1 = parseFloatValue(attributes.y1, inherited.height); + const y2 = parseFloatValue(attributes.y2, inherited.height); + const cx = parseFloatValue(attributes.cx, inherited.width); + const cy = parseFloatValue(attributes.cy, inherited.height); + const rx = parseFloatValue(attributes.rx || attributes.r, inherited.width); + const ry = parseFloatValue(attributes.ry || attributes.r, inherited.height); + + const newInherited: InheritedAttributes = { + fontFamily: fontFamilyRaw || inherited.fontFamily, + fontStyle: fontStyleRaw || inherited.fontStyle, + fontWeight: fontWeightRaw || inherited.fontWeight, + fontSize: parseFloatValue(fontSizeRaw) ?? inherited.fontSize, + fill: fillRaw?.rgb || inherited.fill, + fillOpacity: + parseFloatValue(fillOpacityRaw || opacityRaw || fillRaw?.alpha) ?? + inherited.fillOpacity, + fillRule: FillRuleMap[fillRuleRaw] || inherited.fillRule, + stroke: strokeRaw?.rgb || inherited.stroke, + strokeWidth: parseFloatValue(strokeWidthRaw) ?? inherited.strokeWidth, + strokeOpacity: + parseFloatValue(strokeOpacityRaw || opacityRaw || strokeRaw?.alpha) ?? + inherited.strokeOpacity, + strokeLineCap: + StrokeLineCapMap[strokeLineCapRaw] || inherited.strokeLineCap, + strokeLineJoin: + StrokeLineJoinMap[strokeLineJoinRaw] || inherited.strokeLineJoin, + width: width || inherited.width, + height: height || inherited.height, + rotation: inherited.rotation, + viewBox: + element.tagName === 'svg' && element.attributes.viewBox + ? parseViewBox(element.attributes.viewBox)! + : inherited.viewBox, + blendMode: parseBlendMode(blendModeRaw) || inherited.blendMode, + }; + + const svgAttributes: SVGAttributes = { + src: attributes.src || attributes.href || attributes['xlink:href'], + textAnchor: attributes['text-anchor'], + dominantBaseline: attributes[ + 'dominant-baseline' + ] as SVGAttributes['dominantBaseline'], + preserveAspectRatio: attributes.preserveAspectRatio, + }; + + let transformList = attributes.transform || ''; + // Handle transformations set as direct attributes + [ + 'translate', + 'translateX', + 'translateY', + 'skewX', + 'skewY', + 'rotate', + 'scale', + 'scaleX', + 'scaleY', + 'matrix', + ].forEach((name) => { + if (attributes[name]) { + transformList = attributes[name] + ' ' + transformList; + } + }); + + // Convert x/y as if it was a translation + if (x || y) { + transformList = transformList + `translate(${x || 0} ${y || 0}) `; + } + let newMatrix = matrix; + // Apply the transformations + if (transformList) { + const regexTransform = /(\w+)\((.+?)\)/g; + let parsed = regexTransform.exec(transformList); + while (parsed !== null) { + const [, name, rawArgs] = parsed; + const args = (rawArgs || '') + .split(/\s*,\s*|\s+/) + .filter((value) => value.length > 0) + .map((value) => parseFloat(value)); + newMatrix = combineTransformation( + newMatrix, + name as TransformationName, + args, + ); + parsed = regexTransform.exec(transformList); + } + } + + svgAttributes.x = x; + svgAttributes.y = y; + + if (attributes.cx || attributes.cy) { + svgAttributes.cx = cx; + svgAttributes.cy = cy; + } + if (attributes.rx || attributes.ry || attributes.r) { + svgAttributes.rx = rx; + svgAttributes.ry = ry; + } + if (attributes.x1 || attributes.y1) { + svgAttributes.x1 = x1; + svgAttributes.y1 = y1; + } + if (attributes.x2 || attributes.y2) { + svgAttributes.x2 = x2; + svgAttributes.y2 = y2; + } + if (attributes.width || attributes.height) { + svgAttributes.width = width ?? inherited.width; + svgAttributes.height = height ?? inherited.height; + } + + if (attributes.d) { + newMatrix = combineTransformation(newMatrix, 'scale', [1, -1]); + svgAttributes.d = attributes.d; + } + + if (newInherited.fontFamily) { + // Handle complex fontFamily like `"Linux Libertine O", serif` + const inner = newInherited.fontFamily.match(/^"(.*?)"|^'(.*?)'/); + if (inner) newInherited.fontFamily = inner[1] || inner[2]; + } + + if (newInherited.strokeWidth) { + svgAttributes.strokeWidth = newInherited.strokeWidth; + } + + return { + inherited: newInherited, + svgAttributes, + tagName: element.tagName, + matrix: newMatrix, + }; +}; + +const getFittingRectangle = ( + originalWidth: number, + originalHeight: number, + targetWidth: number, + targetHeight: number, + preserveAspectRatio?: string, +) => { + if (preserveAspectRatio === 'none') { + return { x: 0, y: 0, width: targetWidth, height: targetHeight }; + } + const originalRatio = originalWidth / originalHeight; + const targetRatio = targetWidth / targetHeight; + const width = + targetRatio > originalRatio ? originalRatio * targetHeight : targetWidth; + const height = + targetRatio >= originalRatio ? targetHeight : targetWidth / originalRatio; + const dx = targetWidth - width; + const dy = targetHeight - height; + const [x, y] = (() => { + switch (preserveAspectRatio) { + case 'xMinYMin': + return [0, 0]; + case 'xMidYMin': + return [dx / 2, 0]; + case 'xMaxYMin': + return [dx, dy / 2]; + case 'xMinYMid': + return [0, dy]; + case 'xMaxYMid': + return [dx, dy / 2]; + case 'xMinYMax': + return [0, dy]; + case 'xMidYMax': + return [dx / 2, dy]; + case 'xMaxYMax': + return [dx, dy]; + case 'xMidYMid': + default: + return [dx / 2, dy / 2]; + } + })(); + return { x, y, width, height }; +}; + +// this function should reproduce the behavior described here: https://www.w3.org/TR/SVG11/coords.html#ViewBoxAttribute +const getAspectRatioTransformation = ( + matrix: TransformationMatrix, + originalWidth: number, + originalHeight: number, + targetWidth: number, + targetHeight: number, + preserveAspectRatioProp = 'xMidYMid', +): { + clipBox: TransformationMatrix; + content: TransformationMatrix; +} => { + const [preserveAspectRatio, meetOrSlice = 'meet'] = + preserveAspectRatioProp.split(' '); + const scaleX = targetWidth / originalWidth; + const scaleY = targetHeight / originalHeight; + const boxScale = combineTransformation(matrix, 'scale', [scaleX, scaleY]); + if (preserveAspectRatio === 'none') { + return { + clipBox: boxScale, + content: boxScale, + }; + } + + const scale = + meetOrSlice === 'slice' + ? Math.max(scaleX, scaleY) + : // since 'meet' is the default value, any value other than 'slice' should be handled as 'meet' + Math.min(scaleX, scaleY); + const dx = targetWidth - originalWidth * scale; + const dy = targetHeight - originalHeight * scale; + const [x, y] = (() => { + switch (preserveAspectRatio) { + case 'xMinYMin': + return [0, 0]; + case 'xMidYMin': + return [dx / 2, 0]; + case 'xMaxYMin': + return [dx, dy / 2]; + case 'xMinYMid': + return [0, dy]; + case 'xMaxYMid': + return [dx, dy / 2]; + case 'xMinYMax': + return [0, dy]; + case 'xMidYMax': + return [dx / 2, dy]; + case 'xMaxYMax': + return [dx, dy]; + case 'xMidYMid': + default: + return [dx / 2, dy / 2]; + } + })(); + + const contentTransform = combineTransformation( + combineTransformation(matrix, 'translate', [x, y]), + 'scale', + [scale], + ); + + return { + clipBox: boxScale, + content: contentTransform, + }; +}; + +const parseHTMLNode = ( + node: Node, + inherited: InheritedAttributes, + matrix: TransformationMatrix, + clipSpaces: Space[], +): SVGElement[] => { + if (node.nodeType === NodeType.COMMENT_NODE) return []; + else if (node.nodeType === NodeType.TEXT_NODE) return []; + else if (node.tagName === 'g') { + return parseGroupNode( + node as HTMLElement & { tagName: 'g' }, + inherited, + matrix, + clipSpaces, + ); + } else if (node.tagName === 'svg') { + return parseSvgNode( + node as HTMLElement & { tagName: 'svg' }, + inherited, + matrix, + clipSpaces, + ); + } else { + if (node.tagName === 'polygon') { + node.tagName = 'path'; + node.attributes.d = `M${node.attributes.points}Z`; + delete node.attributes.points; + } + const attributes = parseAttributes(node, inherited, matrix); + const svgAttributes = { + ...attributes.inherited, + ...attributes.svgAttributes, + matrix: attributes.matrix, + clipSpaces, + }; + Object.assign(node, { svgAttributes }); + return [node as SVGElement]; + } +}; + +const parseSvgNode = ( + node: HTMLElement & { tagName: 'svg' }, + inherited: InheritedAttributes, + matrix: TransformationMatrix, + clipSpaces: Space[], +): SVGElement[] => { + // if the width/height aren't set, the svg will have the same dimension as the current drawing space + /* tslint:disable:no-unused-expression */ + node.attributes.width ?? + node.setAttribute('width', inherited.viewBox.width + ''); + node.attributes.height ?? + node.setAttribute('height', inherited.viewBox.height + ''); + /* tslint:enable:no-unused-expression */ + const attributes = parseAttributes(node, inherited, matrix); + const result: SVGElement[] = []; + const viewBox = node.attributes.viewBox + ? parseViewBox(node.attributes.viewBox)! + : node.attributes.width && node.attributes.height + ? parseViewBox(`0 0 ${node.attributes.width} ${node.attributes.height}`)! + : inherited.viewBox; + const x = parseFloat(node.attributes.x) || 0; + const y = parseFloat(node.attributes.y) || 0; + + let newMatrix = combineTransformation(matrix, 'translate', [x, y]); + + const { clipBox: clipBoxTransform, content: contentTransform } = + getAspectRatioTransformation( + newMatrix, + viewBox.width, + viewBox.height, + parseFloat(node.attributes.width), + parseFloat(node.attributes.height), + node.attributes.preserveAspectRatio, + ); + + const topLeft = applyTransformation(clipBoxTransform, { + x: 0, + y: 0, + }); + + const topRight = applyTransformation(clipBoxTransform, { + x: viewBox.width, + y: 0, + }); + + const bottomRight = applyTransformation(clipBoxTransform, { + x: viewBox.width, + y: -viewBox.height, + }); + + const bottomLeft = applyTransformation(clipBoxTransform, { + x: 0, + y: -viewBox.height, + }); + + const baseClipSpace: Space = { + topLeft, + topRight, + bottomRight, + bottomLeft, + }; + + newMatrix = combineTransformation(contentTransform, 'translate', [ + -viewBox.x, + -viewBox.y, + ]); + + node.childNodes.forEach((child) => { + const parsedNodes = parseHTMLNode( + child, + { ...attributes.inherited, viewBox }, + newMatrix, + [...clipSpaces, baseClipSpace], + ); + result.push(...parsedNodes); + }); + return result; +}; + +const parseGroupNode = ( + node: HTMLElement & { tagName: 'g' }, + inherited: InheritedAttributes, + matrix: TransformationMatrix, + clipSpaces: Space[], +): SVGElement[] => { + const attributes = parseAttributes(node, inherited, matrix); + const result: SVGElement[] = []; + node.childNodes.forEach((child) => { + result.push( + ...parseHTMLNode( + child, + attributes.inherited, + attributes.matrix, + clipSpaces, + ), + ); + }); + return result; +}; + +const parseFloatValue = (value?: string, reference = 1) => { + if (!value) return undefined; + const v = parseFloat(value); + if (isNaN(v)) return undefined; + if (value.endsWith('%')) return (v * reference) / 100; + return v; +}; + +const parseBlendMode = (blendMode?: string): BlendMode | undefined => { + switch (blendMode) { + case 'normal': + return BlendMode.Normal; + case 'multiply': + return BlendMode.Multiply; + case 'screen': + return BlendMode.Screen; + case 'overlay': + return BlendMode.Overlay; + case 'darken': + return BlendMode.Darken; + case 'lighten': + return BlendMode.Lighten; + case 'color-dodge': + return BlendMode.ColorDodge; + case 'color-burn': + return BlendMode.ColorBurn; + case 'hard-light': + return BlendMode.HardLight; + case 'soft-light': + return BlendMode.SoftLight; + case 'difference': + return BlendMode.Difference; + case 'exclusion': + return BlendMode.Exclusion; + default: + return undefined; + } +}; + +const parseViewBox = (viewBox?: string): Box | undefined => { + if (!viewBox) return; + const [xViewBox = 0, yViewBox = 0, widthViewBox = 1, heightViewBox = 1] = ( + viewBox || '' + ) + .split(' ') + .map((val) => parseFloatValue(val)); + return { + x: xViewBox, + y: yViewBox, + width: widthViewBox, + height: heightViewBox, + }; +}; + +const parse = ( + svg: string, + { width, height, fontSize }: PDFPageDrawSVGElementOptions, + size: Size, + matrix: TransformationMatrix, +): SVGElement[] => { + const htmlElement = parseHtml(svg).firstChild as HTMLElement; + if (width) htmlElement.setAttribute('width', width + ''); + if (height) htmlElement.setAttribute('height', height + ''); + if (fontSize) htmlElement.setAttribute('font-size', fontSize + ''); + // TODO: what should be the default viewBox? + return parseHTMLNode( + htmlElement, + { + ...size, + viewBox: parseViewBox(htmlElement.attributes.viewBox || '0 0 1 1')!, + }, + matrix, + [], + ); +}; + +export const drawSvg = ( + page: PDFPage, + svg: PDFSvg | string, + options: PDFPageDrawSVGElementOptions, +) => { + const pdfSvg = typeof svg === 'string' ? new PDFSvg(svg) : svg; + if (!pdfSvg.svg) return; + const size = page.getSize(); + const svgNode = parseHtml(pdfSvg.svg).querySelector('svg'); + if (!svgNode) { + return console.error('This is not an svg. Ignoring: ' + pdfSvg.svg); + } + + const attributes = svgNode.attributes; + const style = parseStyles(attributes.style); + + const widthRaw = styleOrAttribute(attributes, style, 'width', ''); + const heightRaw = styleOrAttribute(attributes, style, 'height', ''); + + const width = + options.width !== undefined ? options.width : parseFloat(widthRaw); + const height = + options.height !== undefined ? options.height : parseFloat(heightRaw); + + // it's important to add the viewBox to allow svg resizing through the options + if (!attributes.viewBox) { + svgNode.setAttribute( + 'viewBox', + `0 0 ${widthRaw || width} ${heightRaw || height}`, + ); + } + + if (options.width || options.height) { + if (width !== undefined) style.width = width + (isNaN(width) ? '' : 'px'); + if (height !== undefined) { + style.height = height + (isNaN(height) ? '' : 'px'); + } + svgNode.setAttribute( + 'style', + Object.entries(style) // tslint:disable-line + .map(([key, val]) => `${key}:${val};`) + .join(''), + ); + } + + const baseTransformation: TransformationMatrix = [ + 1, + 0, + 0, + 1, + options.x || 0, + options.y || 0, + ]; + + const elements = parse(svgNode.outerHTML, options, size, baseTransformation); + + const runners = runnersToPage(page, { ...options, images: pdfSvg.images }); + elements.forEach((elt) => { + // uncomment these lines to draw the clipSpaces + // elt.svgAttributes.clipSpaces.forEach(space => { + // page.drawLine({ + // start: space.topLeft, + // end: space.topRight, + // color: parseColor('#000000')?.rgb, + // thickness: 1 + // }) + + // page.drawLine({ + // start: space.topRight, + // end: space.bottomRight, + // color: parseColor('#000000')?.rgb, + // thickness: 1 + // }) + + // page.drawLine({ + // start: space.bottomRight, + // end: space.bottomLeft, + // color: parseColor('#000000')?.rgb, + // thickness: 1 + // }) + + // page.drawLine({ + // start: space.bottomLeft, + // end: space.topLeft, + // color: parseColor('#000000')?.rgb, + // thickness: 1 + // }) + // }) + runners[elt.tagName]?.(elt); + }); +}; diff --git a/src/api/svgPath.ts b/src/api/svgPath.ts index de0e91a56..bf8b236b1 100644 --- a/src/api/svgPath.ts +++ b/src/api/svgPath.ts @@ -9,8 +9,8 @@ import { closePath, lineTo, moveTo, -} from 'src/api/operators'; -import { PDFOperator } from 'src/core'; +} from './operators'; +import { PDFOperator } from '../core'; let cx: number = 0; let cy: number = 0; @@ -273,8 +273,6 @@ const runners: CmdToOperatorsMap = { } const cmd = appendQuadraticCurve(px, py, a[0], a[1]); - px = cx - (px - cx); - py = cy - (py - cy); cx = a[0]; cy = a[1]; return cmd; diff --git a/src/api/text/index.ts b/src/api/text/index.ts index 65ee8d41c..b09d70e69 100644 --- a/src/api/text/index.ts +++ b/src/api/text/index.ts @@ -1,2 +1,2 @@ -export * from 'src/api/text/alignment'; -export * from 'src/api/text/layout'; +export * from './alignment'; +export * from './layout'; diff --git a/src/api/text/layout.ts b/src/api/text/layout.ts index caf4b13d0..984a73545 100644 --- a/src/api/text/layout.ts +++ b/src/api/text/layout.ts @@ -1,15 +1,15 @@ -import PDFFont from 'src/api/PDFFont'; -import { CombedTextLayoutError } from 'src/api/errors'; -import { TextAlignment } from 'src/api/text/alignment'; +import PDFFont from '../PDFFont'; +import { CombedTextLayoutError } from '../errors'; +import { TextAlignment } from './alignment'; -import { PDFHexString } from 'src/core'; +import { PDFHexString } from '../../core'; import { cleanText, lineSplit, mergeLines, charAtIndex, charSplit, -} from 'src/utils'; +} from '../../utils'; export interface TextPosition { text: string; diff --git a/src/core/PDFContext.ts b/src/core/PDFContext.ts index 0544aa214..d6fd77327 100644 --- a/src/core/PDFContext.ts +++ b/src/core/PDFContext.ts @@ -1,24 +1,29 @@ import pako from 'pako'; - -import PDFHeader from 'src/core/document/PDFHeader'; -import { UnexpectedObjectTypeError } from 'src/core/errors'; -import PDFArray from 'src/core/objects/PDFArray'; -import PDFBool from 'src/core/objects/PDFBool'; -import PDFDict from 'src/core/objects/PDFDict'; -import PDFHexString from 'src/core/objects/PDFHexString'; -import PDFName from 'src/core/objects/PDFName'; -import PDFNull from 'src/core/objects/PDFNull'; -import PDFNumber from 'src/core/objects/PDFNumber'; -import PDFObject from 'src/core/objects/PDFObject'; -import PDFRawStream from 'src/core/objects/PDFRawStream'; -import PDFRef from 'src/core/objects/PDFRef'; -import PDFStream from 'src/core/objects/PDFStream'; -import PDFString from 'src/core/objects/PDFString'; -import PDFOperator from 'src/core/operators/PDFOperator'; -import Ops from 'src/core/operators/PDFOperatorNames'; -import PDFContentStream from 'src/core/structures/PDFContentStream'; -import { typedArrayFor } from 'src/utils'; -import { SimpleRNG } from 'src/utils/rng'; +import type { DocumentSnapshot } from '../api/snapshot/DocumentSnapshot'; +import { isPDFInstance, PDFClasses } from '../api/objects'; + +import PDFHeader from './document/PDFHeader'; +import { UnexpectedObjectTypeError } from './errors'; +import PDFArray from './objects/PDFArray'; +import PDFBool from './objects/PDFBool'; +import PDFDict from './objects/PDFDict'; +import PDFHexString from './objects/PDFHexString'; +import PDFName from './objects/PDFName'; +import PDFNull from './objects/PDFNull'; +import PDFNumber from './objects/PDFNumber'; +import PDFObject from './objects/PDFObject'; +import PDFRawStream from './objects/PDFRawStream'; +import PDFRef from './objects/PDFRef'; +import PDFStream from './objects/PDFStream'; +import PDFString from './objects/PDFString'; +import PDFOperator from './operators/PDFOperator'; +import Ops from './operators/PDFOperatorNames'; +import PDFContentStream from './structures/PDFContentStream'; +import PDFSecurity from './security/PDFSecurity'; +import { typedArrayFor } from '../utils'; +import { SimpleRNG } from '../utils/rng'; +import PDFCrossRefSection from './document/PDFCrossRefSection'; +import type { Entry } from './document/PDFCrossRefSection'; type LookupKey = PDFRef | PDFObject | undefined; @@ -39,40 +44,85 @@ type Literal = | null | undefined; +interface LiteralConfig { + deep?: boolean; + literalRef?: boolean; + literalStreamDict?: boolean; + literalString?: boolean; +} + const byAscendingObjectNumber = ( [a]: [PDFRef, PDFObject], [b]: [PDFRef, PDFObject], ) => a.objectNumber - b.objectNumber; class PDFContext { - static create = () => new PDFContext(); + isDecrypted = true; + static create = (withObjectVersions: boolean = false) => + new PDFContext(withObjectVersions); largestObjectNumber: number; header: PDFHeader; trailerInfo: { + Size?: PDFNumber; Root?: PDFObject; Encrypt?: PDFObject; Info?: PDFObject; ID?: PDFObject; }; rng: SimpleRNG; + pdfFileDetails: { + pdfSize: number; + prevStartXRef: number; + useObjectStreams: boolean; + originalBytes?: Uint8Array; + }; + snapshot?: DocumentSnapshot; + xrefs: PDFCrossRefSection[] = []; + private _preserveObjectsVersions: boolean; + public get preserveObjectsVersions(): boolean { + return this._preserveObjectsVersions; + } + + security?: PDFSecurity; - private readonly indirectObjects: Map; + private readonly indirectObjects: Map; + private readonly objectsPreviousVersions: Map; private pushGraphicsStateContentStreamRef?: PDFRef; private popGraphicsStateContentStreamRef?: PDFRef; - private constructor() { + private constructor(preserveObjectsVersions?: boolean) { + this._preserveObjectsVersions = preserveObjectsVersions + ? preserveObjectsVersions + : false; this.largestObjectNumber = 0; this.header = PDFHeader.forVersion(1, 7); this.trailerInfo = {}; this.indirectObjects = new Map(); + this.objectsPreviousVersions = new Map(); this.rng = SimpleRNG.withSeed(1); + this.pdfFileDetails = { + pdfSize: 0, + prevStartXRef: 0, + useObjectStreams: false, + }; } assign(ref: PDFRef, object: PDFObject): void { - this.indirectObjects.set(ref, object); + if (this.preserveObjectsVersions) { + const prevOV = this.indirectObjects.get(ref.toString()); + if (prevOV) { + const prevList = this.objectsPreviousVersions.get(ref.toString()); + if (!prevList) { + this.objectsPreviousVersions.set(ref.toString(), [prevOV[1]]); + } else { + prevList.unshift(prevOV[1]); + } + } + } + this.indirectObjects.set(ref.toString(), [ref, object]); if (ref.objectNumber > this.largestObjectNumber) { this.largestObjectNumber = ref.objectNumber; } @@ -80,7 +130,9 @@ class PDFContext { nextRef(): PDFRef { this.largestObjectNumber += 1; - return PDFRef.of(this.largestObjectNumber); + const ref = PDFRef.of(this.largestObjectNumber); + if (this.snapshot) this.snapshot.markRefForSave(ref); + return ref; } register(object: PDFObject): PDFRef { @@ -90,7 +142,20 @@ class PDFContext { } delete(ref: PDFRef): boolean { - return this.indirectObjects.delete(ref); + if (this.snapshot) this.snapshot.markDeletedRef(ref); + if (this.preserveObjectsVersions) { + const object = this.indirectObjects.get(ref.toString()); + if (object) { + // check is not already deleted + const verlist = this.objectsPreviousVersions.get(ref.toString()); + if (verlist) { + verlist.unshift(object[1]); + } else { + this.objectsPreviousVersions.set(ref.toString(), [object[1]]); + } + } + } + return this.indirectObjects.delete(ref.toString()); } lookupMaybe(ref: LookupKey, type: typeof PDFArray): PDFArray | undefined; @@ -117,17 +182,27 @@ class PDFContext { // removed in next breaking API change. const preservePDFNull = types.includes(PDFNull); - const result = ref instanceof PDFRef ? this.indirectObjects.get(ref) : ref; - - if (!result || (result === PDFNull && !preservePDFNull)) return undefined; + let result; + if (isPDFInstance(ref, PDFClasses.PDFRef)) { + const iobj = this.indirectObjects.get((ref as PDFRef).toString()); + result = iobj ? iobj[1] : undefined; + } else { + result = ref; + } + if ( + !result || + (isPDFInstance(result, PDFClasses.PDFNull) && !preservePDFNull) + ) + return undefined; for (let idx = 0, len = types.length; idx < len; idx++) { const type = types[idx]; - if (type === PDFNull) { - if (result === PDFNull) return result; - } else { - if (result instanceof type) return result; - } + if ( + isPDFInstance(type, PDFClasses.PDFNull) && + isPDFInstance(result, PDFClasses.PDFNull) + ) + return result; + if (isPDFInstance(result, type)) return result; } throw new UnexpectedObjectTypeError(types, result); } @@ -150,24 +225,36 @@ class PDFContext { ): PDFString | PDFHexString; lookup(ref: LookupKey, ...types: any[]) { - const result = ref instanceof PDFRef ? this.indirectObjects.get(ref) : ref; + let result; + if (isPDFInstance(ref, PDFClasses.PDFRef)) { + const iobj = this.indirectObjects.get((ref as PDFRef).toString()); + result = iobj ? iobj[1] : undefined; + } else { + result = ref; + } if (types.length === 0) return result; for (let idx = 0, len = types.length; idx < len; idx++) { const type = types[idx]; - if (type === PDFNull) { - if (result === PDFNull) return result; - } else { - if (result instanceof type) return result; - } + if ( + isPDFInstance(type, PDFClasses.PDFNull) && + isPDFInstance(result, PDFClasses.PDFNull) + ) + return result; + if (isPDFInstance(result, type)) return result; } throw new UnexpectedObjectTypeError(types, result); } + getRef(pdfObject: PDFObject | PDFRef): PDFRef | undefined { + if (isPDFInstance(pdfObject, PDFClasses.PDFRef)) return pdfObject as PDFRef; + return this.getObjectRef(pdfObject); + } + getObjectRef(pdfObject: PDFObject): PDFRef | undefined { - const entries = Array.from(this.indirectObjects.entries()); + const entries = Array.from(this.indirectObjects.values()); for (let idx = 0, len = entries.length; idx < len; idx++) { const [ref, object] = entries[idx]; if (object === pdfObject) { @@ -179,7 +266,7 @@ class PDFContext { } enumerateIndirectObjects(): [PDFRef, PDFObject][] { - return Array.from(this.indirectObjects.entries()).sort( + return Array.from(this.indirectObjects.values()).sort( byAscendingObjectNumber, ); } @@ -192,7 +279,7 @@ class PDFContext { obj(literal: LiteralArray): PDFArray; obj(literal: Literal) { - if (literal instanceof PDFObject) { + if (isPDFInstance(literal, PDFClasses.PDFObject)) { return literal; } else if (literal === null || literal === undefined) { return PDFNull; @@ -202,6 +289,8 @@ class PDFContext { return PDFNumber.of(literal); } else if (typeof literal === 'boolean') { return literal ? PDFBool.True : PDFBool.False; + } else if (literal instanceof Uint8Array) { + return PDFHexString.fromBytes(literal); } else if (Array.isArray(literal)) { const array = PDFArray.withContext(this); for (let idx = 0, len = literal.length; idx < len; idx++) { @@ -220,6 +309,69 @@ class PDFContext { } } + /* + * @param obj The input PDFObject to convert to a literal. + * @param cfg The configuration to be used when converting the object. + * @param cfg.deep Recursively call this function on all encountered PDFArray elements and PDFDict values. + * @param cfg.literalRef Also convert PDFRef to a (literal) object number. + * @param cfg.literalStreamDict Also convert PDFStream to its associated dictionary's (literal) representation. + * @param cfg.literalString Also convert PDFString and PDFHexString to a (literal) string value. + * @returns Resolves with a document loaded from the input. + */ + getLiteral(obj: PDFArray, cfg?: LiteralConfig): LiteralArray; + getLiteral(obj: PDFBool, cfg?: LiteralConfig): boolean; + getLiteral(obj: PDFDict, cfg?: LiteralConfig): LiteralObject; + getLiteral(obj: PDFHexString, cfg?: LiteralConfig): PDFHexString | string; + getLiteral(obj: PDFName, cfg?: LiteralConfig): string; + getLiteral(obj: typeof PDFNull, cfg?: LiteralConfig): null; + getLiteral(obj: PDFNumber, cfg?: LiteralConfig): number; + getLiteral(obj: PDFRef, cfg?: LiteralConfig): PDFRef | number; + getLiteral(obj: PDFStream, cfg?: LiteralConfig): PDFStream | LiteralObject; + getLiteral(obj: PDFString, cfg?: LiteralConfig): PDFString | string; + getLiteral(obj: PDFObject, cfg?: LiteralConfig): PDFObject; + getLiteral( + obj: PDFObject, + { + deep = true, + literalRef = false, + literalStreamDict = false, + literalString = false, + }: LiteralConfig = {}, + ): Literal | PDFObject { + const cfg = { deep, literalRef, literalStreamDict, literalString }; + if (isPDFInstance(obj, PDFClasses.PDFArray)) { + const lit = (obj as PDFArray).asArray(); + return deep ? lit.map((value) => this.getLiteral(value, cfg)) : lit; + } else if (isPDFInstance(obj, PDFClasses.PDFBool)) { + return (obj as PDFBool).asBoolean(); + } else if (isPDFInstance(obj, PDFClasses.PDFDict)) { + const lit: LiteralObject = {}; + const entries = (obj as PDFDict).entries(); + for (let idx = 0, len = entries.length; idx < len; idx++) { + const [name, value] = entries[idx]; + lit[this.getLiteral(name)] = deep ? this.getLiteral(value, cfg) : value; + } + return lit; + } else if (isPDFInstance(obj, PDFClasses.PDFName)) { + return (obj as PDFName).decodeText(); + } else if (obj === PDFNull) { + return null; + } else if (isPDFInstance(obj, PDFClasses.PDFNumber)) { + return (obj as PDFNumber).asNumber(); + } else if (isPDFInstance(obj, PDFClasses.PDFRef) && literalRef) { + return (obj as PDFRef).objectNumber; + } else if (isPDFInstance(obj, PDFClasses.PDFStream) && literalStreamDict) { + return this.getLiteral((obj as PDFStream).dict, cfg); + } else if ( + (isPDFInstance(obj, PDFClasses.PDFString) || + isPDFInstance(obj, PDFClasses.PDFHexString)) && + literalString + ) { + return (obj as PDFString | PDFHexString).asString(); + } + return obj; + } + stream( contents: string | Uint8Array, dict: LiteralObject = {}, @@ -294,6 +446,66 @@ class PDFContext { addRandomSuffix(prefix: string, suffixLength = 4): string { return `${prefix}-${Math.floor(this.rng.nextInt() * 10 ** suffixLength)}`; } + + registerObjectChange(obj: PDFObject) { + if (!this.snapshot) return; + + const ref = this.getObjectRef(obj); + if (ref) { + this.snapshot.markRefForSave(ref); + return; + } + + const containingRef = this.findContainingIndirectObject(obj); + if (containingRef) { + this.snapshot.markRefForSave(containingRef); + } + } + + private findContainingIndirectObject(target: PDFObject): PDFRef | undefined { + const entries = Array.from(this.indirectObjects.values()); + for (let idx = 0, len = entries.length; idx < len; idx++) { + const [ref, object] = entries[idx]; + if (this.objectContains(object, target)) { + return ref; + } + } + return undefined; + } + + private objectContains(container: PDFObject, target: PDFObject): boolean { + if (container === target) return true; + + if (isPDFInstance(container, PDFClasses.PDFDict)) { + const values = (container as PDFDict).values(); + for (let i = 0, len = values.length; i < len; i++) { + if (this.objectContains(values[i], target)) return true; + } + } else if (isPDFInstance(container, PDFClasses.PDFArray)) { + for (let i = 0, len = (container as PDFArray).size(); i < len; i++) { + if (this.objectContains((container as PDFArray).get(i), target)) + return true; + } + } else if (isPDFInstance(container, PDFClasses.PDFStream)) { + if (this.objectContains((container as PDFStream).dict, target)) + return true; + } + + return false; + } + + getObjectVersions(ref: PDFRef): PDFObject[] { + if (!this.preserveObjectsVersions) return []; + const list = this.objectsPreviousVersions.get(ref.toString()); + if (list) return list; + return []; + } + + listXrefEntries(xrefIndex: number = -1): Entry[] { + if (xrefIndex < 0) xrefIndex = this.xrefs.length - 1; + if (xrefIndex < 0 || xrefIndex >= this.xrefs.length) return []; + return this.xrefs[xrefIndex].listRefs(); + } } export default PDFContext; diff --git a/src/core/PDFObjectCopier.ts b/src/core/PDFObjectCopier.ts index 0326ddccf..c9978f8f0 100644 --- a/src/core/PDFObjectCopier.ts +++ b/src/core/PDFObjectCopier.ts @@ -1,11 +1,12 @@ -import PDFArray from 'src/core/objects/PDFArray'; -import PDFDict from 'src/core/objects/PDFDict'; -import PDFName from 'src/core/objects/PDFName'; -import PDFObject from 'src/core/objects/PDFObject'; -import PDFRef from 'src/core/objects/PDFRef'; -import PDFStream from 'src/core/objects/PDFStream'; -import PDFContext from 'src/core/PDFContext'; -import PDFPageLeaf from 'src/core/structures/PDFPageLeaf'; +import { isPDFInstance, PDFClasses } from '../api/objects'; +import PDFArray from './objects/PDFArray'; +import PDFDict from './objects/PDFDict'; +import PDFName from './objects/PDFName'; +import PDFObject from './objects/PDFObject'; +import PDFRef from './objects/PDFRef'; +import PDFStream from './objects/PDFStream'; +import PDFContext from './PDFContext'; +import PDFPageLeaf from './structures/PDFPageLeaf'; /** * PDFObjectCopier copies PDFObjects from a src context to a dest context. @@ -43,11 +44,11 @@ class PDFObjectCopier { // prettier-ignore copy = (object: T): T => ( - object instanceof PDFPageLeaf ? this.copyPDFPage(object) - : object instanceof PDFDict ? this.copyPDFDict(object) - : object instanceof PDFArray ? this.copyPDFArray(object) - : object instanceof PDFStream ? this.copyPDFStream(object) - : object instanceof PDFRef ? this.copyPDFIndirectObject(object) + isPDFInstance(object, PDFClasses.PDFPageLeaf) ? this.copyPDFPage(object as any as PDFPageLeaf) + : isPDFInstance(object, PDFClasses.PDFDict) ? this.copyPDFDict(object as any as PDFDict) + : isPDFInstance(object, PDFClasses.PDFArray) ? this.copyPDFArray(object as any as PDFArray) + : isPDFInstance(object, PDFClasses.PDFStream) ? this.copyPDFStream(object as any as PDFStream) + : isPDFInstance(object, PDFClasses.PDFRef) ? this.copyPDFIndirectObject(object as any as PDFRef) : object.clone() ) as T; diff --git a/src/core/acroform/PDFAcroButton.ts b/src/core/acroform/PDFAcroButton.ts index 95417d6a8..97b5d74fa 100644 --- a/src/core/acroform/PDFAcroButton.ts +++ b/src/core/acroform/PDFAcroButton.ts @@ -1,11 +1,12 @@ -import PDFObject from 'src/core/objects/PDFObject'; -import PDFString from 'src/core/objects/PDFString'; -import PDFHexString from 'src/core/objects/PDFHexString'; -import PDFArray from 'src/core/objects/PDFArray'; -import PDFName from 'src/core/objects/PDFName'; -import PDFRef from 'src/core/objects/PDFRef'; -import PDFAcroTerminal from 'src/core/acroform/PDFAcroTerminal'; -import { IndexOutOfBoundsError } from 'src/core/errors'; +import PDFObject from '../objects/PDFObject'; +import PDFString from '../objects/PDFString'; +import PDFHexString from '../objects/PDFHexString'; +import PDFArray from '../objects/PDFArray'; +import PDFName from '../objects/PDFName'; +import PDFRef from '../objects/PDFRef'; +import PDFAcroTerminal from './PDFAcroTerminal'; +import { IndexOutOfBoundsError } from '../errors'; +import { isPDFInstance, PDFClasses } from '../../api/objects'; class PDFAcroButton extends PDFAcroTerminal { Opt(): PDFString | PDFHexString | PDFArray | undefined { @@ -26,15 +27,21 @@ class PDFAcroButton extends PDFAcroTerminal { if (!opt) return undefined; - if (opt instanceof PDFString || opt instanceof PDFHexString) { - return [opt]; + if ( + isPDFInstance(opt, PDFClasses.PDFString) || + isPDFInstance(opt, PDFClasses.PDFHexString) + ) { + return [opt as PDFString | PDFHexString]; } const values: (PDFString | PDFHexString)[] = []; - for (let idx = 0, len = opt.size(); idx < len; idx++) { - const value = opt.lookup(idx); - if (value instanceof PDFString || value instanceof PDFHexString) { - values.push(value); + for (let idx = 0, len = (opt as PDFArray).size(); idx < len; idx++) { + const value = (opt as PDFArray).lookup(idx); + if ( + isPDFInstance(value, PDFClasses.PDFString) || + isPDFInstance(value, PDFClasses.PDFHexString) + ) { + values.push(value as PDFString | PDFHexString); } } @@ -46,14 +53,17 @@ class PDFAcroButton extends PDFAcroTerminal { if (!opt) return; - if (opt instanceof PDFString || opt instanceof PDFHexString) { + if ( + isPDFInstance(opt, PDFClasses.PDFString) || + isPDFInstance(opt, PDFClasses.PDFHexString) + ) { if (idx !== 0) throw new IndexOutOfBoundsError(idx, 0, 0); this.setOpt([]); } else { - if (idx < 0 || idx > opt.size()) { - throw new IndexOutOfBoundsError(idx, 0, opt.size()); + if (idx < 0 || idx > (opt as PDFArray).size()) { + throw new IndexOutOfBoundsError(idx, 0, (opt as PDFArray).size()); } - opt.remove(idx); + (opt as PDFArray).remove(idx); } } diff --git a/src/core/acroform/PDFAcroCheckBox.ts b/src/core/acroform/PDFAcroCheckBox.ts index b1dc2bdb5..91b071852 100644 --- a/src/core/acroform/PDFAcroCheckBox.ts +++ b/src/core/acroform/PDFAcroCheckBox.ts @@ -1,11 +1,16 @@ -import PDFContext from 'src/core/PDFContext'; -import PDFRef from 'src/core/objects/PDFRef'; -import PDFDict from 'src/core/objects/PDFDict'; -import PDFName from 'src/core/objects/PDFName'; -import PDFAcroButton from 'src/core/acroform/PDFAcroButton'; -import { InvalidAcroFieldValueError } from 'src/core/errors'; +import PDFContext from '../PDFContext'; +import PDFRef from '../objects/PDFRef'; +import PDFDict from '../objects/PDFDict'; +import PDFName from '../objects/PDFName'; +import PDFAcroButton from './PDFAcroButton'; +import { InvalidAcroFieldValueError } from '../errors'; +import { isPDFInstance, PDFClasses } from '../../api/objects'; class PDFAcroCheckBox extends PDFAcroButton { + static className = () => PDFClasses.PDFAcroCheckBox; + myClass(): PDFClasses { + return PDFClasses.PDFAcroCheckBox; + } static fromDict = (dict: PDFDict, ref: PDFRef) => new PDFAcroCheckBox(dict, ref); @@ -36,7 +41,7 @@ class PDFAcroCheckBox extends PDFAcroButton { getValue(): PDFName { const v = this.V(); - if (v instanceof PDFName) return v; + if (isPDFInstance(v, PDFClasses.PDFName)) return v as PDFName; return PDFName.of('Off'); } diff --git a/src/core/acroform/PDFAcroChoice.ts b/src/core/acroform/PDFAcroChoice.ts index 52e080745..222dcfe05 100644 --- a/src/core/acroform/PDFAcroChoice.ts +++ b/src/core/acroform/PDFAcroChoice.ts @@ -1,13 +1,11 @@ -import PDFAcroTerminal from 'src/core/acroform/PDFAcroTerminal'; -import PDFHexString from 'src/core/objects/PDFHexString'; -import PDFString from 'src/core/objects/PDFString'; -import PDFArray from 'src/core/objects/PDFArray'; -import PDFName from 'src/core/objects/PDFName'; -import { AcroChoiceFlags } from 'src/core/acroform/flags'; -import { - InvalidAcroFieldValueError, - MultiSelectValueError, -} from 'src/core/errors'; +import PDFAcroTerminal from './PDFAcroTerminal'; +import PDFHexString from '../objects/PDFHexString'; +import PDFString from '../objects/PDFString'; +import PDFArray from '../objects/PDFArray'; +import PDFName from '../objects/PDFName'; +import { AcroChoiceFlags } from './flags'; +import { InvalidAcroFieldValueError, MultiSelectValueError } from '../errors'; +import { isPDFInstance, PDFClasses } from '../../api/objects'; class PDFAcroChoice extends PDFAcroTerminal { setValues(values: (PDFString | PDFHexString)[]) { @@ -65,15 +63,22 @@ class PDFAcroChoice extends PDFAcroTerminal { getValues(): (PDFString | PDFHexString)[] { const v = this.V(); - if (v instanceof PDFString || v instanceof PDFHexString) return [v]; + if ( + isPDFInstance(v, PDFClasses.PDFString) || + isPDFInstance(v, PDFClasses.PDFHexString) + ) + return [v as PDFString | PDFHexString]; - if (v instanceof PDFArray) { + if (isPDFInstance(v, PDFClasses.PDFArray)) { const values: (PDFString | PDFHexString)[] = []; - for (let idx = 0, len = v.size(); idx < len; idx++) { - const value = v.lookup(idx); - if (value instanceof PDFString || value instanceof PDFHexString) { - values.push(value); + for (let idx = 0, len = (v as PDFArray).size(); idx < len; idx++) { + const value = (v as PDFArray).lookup(idx); + if ( + isPDFInstance(value, PDFClasses.PDFString) || + isPDFInstance(value, PDFClasses.PDFHexString) + ) { + values.push(value as PDFString | PDFHexString); } } @@ -113,31 +118,49 @@ class PDFAcroChoice extends PDFAcroTerminal { const Opt = this.Opt(); // Not supposed to happen - Opt _should_ always be `PDFArray | undefined` - if (Opt instanceof PDFString || Opt instanceof PDFHexString) { - return [{ value: Opt, display: Opt }]; + if ( + isPDFInstance(Opt, PDFClasses.PDFString) || + isPDFInstance(Opt, PDFClasses.PDFHexString) + ) { + return [ + { + value: Opt as PDFString | PDFHexString, + display: Opt as PDFString | PDFHexString, + }, + ]; } - if (Opt instanceof PDFArray) { + if (isPDFInstance(Opt, PDFClasses.PDFArray)) { const res: { value: PDFString | PDFHexString; display: PDFString | PDFHexString; }[] = []; - for (let idx = 0, len = Opt.size(); idx < len; idx++) { - const item = Opt.lookup(idx); + for (let idx = 0, len = (Opt as PDFArray).size(); idx < len; idx++) { + const item = (Opt as PDFArray).lookup(idx); // If `item` is a string, use that as both the export and text value - if (item instanceof PDFString || item instanceof PDFHexString) { - res.push({ value: item, display: item }); + if ( + isPDFInstance(item, PDFClasses.PDFString) || + isPDFInstance(item, PDFClasses.PDFHexString) + ) { + res.push({ + value: item as PDFString | PDFHexString, + display: item as PDFString | PDFHexString, + }); } // If `item` is an array of one, treat it the same as just a string, // if it's an array of two then `item[0]` is the export value and // `item[1]` is the text value - if (item instanceof PDFArray) { - if (item.size() > 0) { - const first = item.lookup(0, PDFString, PDFHexString); - const second = item.lookupMaybe(1, PDFString, PDFHexString); + if (isPDFInstance(item, PDFClasses.PDFArray)) { + if ((item as PDFArray).size() > 0) { + const first = (item as PDFArray).lookup(0, PDFString, PDFHexString); + const second = (item as PDFArray).lookupMaybe( + 1, + PDFString, + PDFHexString, + ); res.push({ value: first, display: second || first }); } } diff --git a/src/core/acroform/PDFAcroComboBox.ts b/src/core/acroform/PDFAcroComboBox.ts index 32fd69a08..6da85da3a 100644 --- a/src/core/acroform/PDFAcroComboBox.ts +++ b/src/core/acroform/PDFAcroComboBox.ts @@ -1,10 +1,15 @@ -import PDFDict from 'src/core/objects/PDFDict'; -import PDFAcroChoice from 'src/core/acroform/PDFAcroChoice'; -import PDFContext from 'src/core/PDFContext'; -import PDFRef from 'src/core/objects/PDFRef'; -import { AcroChoiceFlags } from 'src/core/acroform/flags'; +import PDFDict from '../objects/PDFDict'; +import PDFAcroChoice from './PDFAcroChoice'; +import PDFContext from '../PDFContext'; +import PDFRef from '../objects/PDFRef'; +import { AcroChoiceFlags } from './flags'; +import { PDFClasses } from '../../api/objects'; class PDFAcroComboBox extends PDFAcroChoice { + static className = () => PDFClasses.PDFAcroComboBox; + myClass(): PDFClasses { + return PDFClasses.PDFAcroComboBox; + } static fromDict = (dict: PDFDict, ref: PDFRef) => new PDFAcroComboBox(dict, ref); diff --git a/src/core/acroform/PDFAcroField.ts b/src/core/acroform/PDFAcroField.ts index 9f4cd364a..b068f6f0f 100644 --- a/src/core/acroform/PDFAcroField.ts +++ b/src/core/acroform/PDFAcroField.ts @@ -1,21 +1,26 @@ -import PDFDict from 'src/core/objects/PDFDict'; -import PDFString from 'src/core/objects/PDFString'; -import PDFHexString from 'src/core/objects/PDFHexString'; -import PDFName from 'src/core/objects/PDFName'; -import PDFObject from 'src/core/objects/PDFObject'; -import PDFNumber from 'src/core/objects/PDFNumber'; -import PDFArray from 'src/core/objects/PDFArray'; -import PDFRef from 'src/core/objects/PDFRef'; -import { findLastMatch } from 'src/utils'; -import { MissingDAEntryError, MissingTfOperatorError } from 'src/core/errors'; +import PDFDict from '../objects/PDFDict'; +import PDFString from '../objects/PDFString'; +import PDFHexString from '../objects/PDFHexString'; +import PDFName from '../objects/PDFName'; +import PDFObject from '../objects/PDFObject'; +import PDFNumber from '../objects/PDFNumber'; +import PDFArray from '../objects/PDFArray'; +import PDFRef from '../objects/PDFRef'; +import { findLastMatch } from '../../utils'; +import { MissingDAEntryError, MissingTfOperatorError } from '../errors'; +import { isPDFInstance, PDFClasses } from '../../api/objects'; // Examples: // `/Helv 12 Tf` -> ['Helv', '12'] // `/HeBo 8.00 Tf` -> ['HeBo', '8.00'] // `/HeBo Tf` -> ['HeBo', undefined] -const tfRegex = /\/([^\0\t\n\f\r\ ]+)[\0\t\n\f\r\ ]*(\d*\.\d+|\d+)?[\0\t\n\f\r\ ]+Tf/; - +const tfRegex = + /\/([^\0\t\n\f\r ]+)[\0\t\n\f\r ]*(\d*\.\d+|\d+)?[\0\t\n\f\r ]+Tf/; class PDFAcroField { + static className = () => PDFClasses.PDFAcroField; + myClass(): PDFClasses { + return PDFClasses.PDFAcroField; + } readonly dict: PDFDict; readonly ref: PDFRef; @@ -48,7 +53,11 @@ class PDFAcroField { DA(): PDFString | PDFHexString | undefined { const da = this.dict.lookup(PDFName.of('DA')); - if (da instanceof PDFString || da instanceof PDFHexString) return da; + if ( + isPDFInstance(da, PDFClasses.PDFString) || + isPDFInstance(da, PDFClasses.PDFHexString) + ) + return da as PDFString | PDFHexString; return undefined; } @@ -62,9 +71,9 @@ class PDFAcroField { // return new PDFAcroField(parent); const parentRef = this.dict.get(PDFName.of('Parent')); - if (parentRef instanceof PDFRef) { + if (isPDFInstance(parentRef, PDFClasses.PDFRef)) { const parent = this.dict.lookup(PDFName.of('Parent'), PDFDict); - return new PDFAcroField(parent, parentRef); + return new PDFAcroField(parent, parentRef as PDFRef); } return undefined; @@ -97,8 +106,8 @@ class PDFAcroField { getDefaultAppearance(): string | undefined { const DA = this.DA(); - if (DA instanceof PDFHexString) { - return DA.decodeText(); + if (isPDFInstance(DA, PDFClasses.PDFHexString)) { + return (DA as PDFHexString).decodeText(); } return DA?.asString(); diff --git a/src/core/acroform/PDFAcroForm.ts b/src/core/acroform/PDFAcroForm.ts index 076a407d1..e6c8ff934 100644 --- a/src/core/acroform/PDFAcroForm.ts +++ b/src/core/acroform/PDFAcroForm.ts @@ -1,16 +1,17 @@ -import PDFContext from 'src/core/PDFContext'; -import PDFDict from 'src/core/objects/PDFDict'; -import PDFArray from 'src/core/objects/PDFArray'; -import PDFName from 'src/core/objects/PDFName'; -import PDFRef from 'src/core/objects/PDFRef'; -import PDFAcroField from 'src/core/acroform/PDFAcroField'; -import PDFAcroNonTerminal from 'src/core/acroform/PDFAcroNonTerminal'; -import { - createPDFAcroField, - createPDFAcroFields, -} from 'src/core/acroform/utils'; +import PDFContext from '../PDFContext'; +import PDFDict from '../objects/PDFDict'; +import PDFArray from '../objects/PDFArray'; +import PDFName from '../objects/PDFName'; +import PDFRef from '../objects/PDFRef'; +import PDFAcroField from './PDFAcroField'; +import { createPDFAcroField, createPDFAcroFields } from './utils'; +import { isPDFInstance, PDFClasses } from '../../api/objects'; class PDFAcroForm { + static className = () => PDFClasses.PDFAcroForm; + myClass(): PDFClasses { + return PDFClasses.PDFAcroForm; + } readonly dict: PDFDict; static fromDict = (dict: PDFDict) => new PDFAcroForm(dict); @@ -26,7 +27,7 @@ class PDFAcroForm { Fields(): PDFArray | undefined { const fields = this.dict.lookup(PDFName.of('Fields')); - if (fields instanceof PDFArray) return fields; + if (isPDFInstance(fields, PDFClasses.PDFArray)) return fields as PDFArray; return undefined; } @@ -52,7 +53,7 @@ class PDFAcroForm { const field = fields[idx]; allFields.push(field); const [fieldModel] = field; - if (fieldModel instanceof PDFAcroNonTerminal) { + if (isPDFInstance(fieldModel, PDFClasses.PDFAcroNonTerminal)) { pushFields(createPDFAcroFields(fieldModel.Kids())); } } diff --git a/src/core/acroform/PDFAcroListBox.ts b/src/core/acroform/PDFAcroListBox.ts index 4cd5a665b..a503e8745 100644 --- a/src/core/acroform/PDFAcroListBox.ts +++ b/src/core/acroform/PDFAcroListBox.ts @@ -1,9 +1,14 @@ -import PDFDict from 'src/core/objects/PDFDict'; -import PDFAcroChoice from 'src/core/acroform/PDFAcroChoice'; -import PDFContext from 'src/core/PDFContext'; -import PDFRef from 'src/core/objects/PDFRef'; +import PDFDict from '../objects/PDFDict'; +import PDFAcroChoice from './PDFAcroChoice'; +import PDFContext from '../PDFContext'; +import PDFRef from '../objects/PDFRef'; +import { PDFClasses } from '../../api/objects'; class PDFAcroListBox extends PDFAcroChoice { + static className = () => PDFClasses.PDFAcroListBox; + myClass(): PDFClasses { + return PDFClasses.PDFAcroListBox; + } static fromDict = (dict: PDFDict, ref: PDFRef) => new PDFAcroListBox(dict, ref); diff --git a/src/core/acroform/PDFAcroNonTerminal.ts b/src/core/acroform/PDFAcroNonTerminal.ts index 59b13b7d0..0705e3e50 100644 --- a/src/core/acroform/PDFAcroNonTerminal.ts +++ b/src/core/acroform/PDFAcroNonTerminal.ts @@ -1,10 +1,15 @@ -import PDFDict from 'src/core/objects/PDFDict'; -import PDFRef from 'src/core/objects/PDFRef'; -import PDFName from 'src/core/objects/PDFName'; -import PDFContext from 'src/core/PDFContext'; -import PDFAcroField from 'src/core/acroform/PDFAcroField'; +import PDFDict from '../objects/PDFDict'; +import PDFRef from '../objects/PDFRef'; +import PDFName from '../objects/PDFName'; +import PDFContext from '../PDFContext'; +import PDFAcroField from './PDFAcroField'; +import { PDFClasses } from '../../api/objects'; class PDFAcroNonTerminal extends PDFAcroField { + static className = () => PDFClasses.PDFAcroNonTerminal; + myClass(): PDFClasses { + return PDFClasses.PDFAcroNonTerminal; + } static fromDict = (dict: PDFDict, ref: PDFRef) => new PDFAcroNonTerminal(dict, ref); diff --git a/src/core/acroform/PDFAcroPushButton.ts b/src/core/acroform/PDFAcroPushButton.ts index 67a985611..0f1578b89 100644 --- a/src/core/acroform/PDFAcroPushButton.ts +++ b/src/core/acroform/PDFAcroPushButton.ts @@ -1,10 +1,15 @@ -import PDFDict from 'src/core/objects/PDFDict'; -import PDFAcroButton from 'src/core/acroform/PDFAcroButton'; -import PDFContext from 'src/core/PDFContext'; -import PDFRef from 'src/core/objects/PDFRef'; -import { AcroButtonFlags } from 'src/core/acroform/flags'; +import PDFDict from '../objects/PDFDict'; +import PDFAcroButton from './PDFAcroButton'; +import PDFContext from '../PDFContext'; +import PDFRef from '../objects/PDFRef'; +import { AcroButtonFlags } from './flags'; +import { PDFClasses } from '../../api/objects'; class PDFAcroPushButton extends PDFAcroButton { + static className = () => PDFClasses.PDFAcroPushButton; + myClass(): PDFClasses { + return PDFClasses.PDFAcroPushButton; + } static fromDict = (dict: PDFDict, ref: PDFRef) => new PDFAcroPushButton(dict, ref); diff --git a/src/core/acroform/PDFAcroRadioButton.ts b/src/core/acroform/PDFAcroRadioButton.ts index 6f8ecd6c2..d5fab36fc 100644 --- a/src/core/acroform/PDFAcroRadioButton.ts +++ b/src/core/acroform/PDFAcroRadioButton.ts @@ -1,12 +1,17 @@ -import PDFRef from 'src/core/objects/PDFRef'; -import PDFDict from 'src/core/objects/PDFDict'; -import PDFName from 'src/core/objects/PDFName'; -import PDFAcroButton from 'src/core/acroform/PDFAcroButton'; -import PDFContext from 'src/core/PDFContext'; -import { AcroButtonFlags } from 'src/core/acroform/flags'; -import { InvalidAcroFieldValueError } from 'src/core/errors'; +import PDFRef from '../objects/PDFRef'; +import PDFDict from '../objects/PDFDict'; +import PDFName from '../objects/PDFName'; +import PDFAcroButton from './PDFAcroButton'; +import PDFContext from '../PDFContext'; +import { AcroButtonFlags } from './flags'; +import { InvalidAcroFieldValueError } from '../errors'; +import { isPDFInstance, PDFClasses } from '../../api/objects'; class PDFAcroRadioButton extends PDFAcroButton { + static className = () => PDFClasses.PDFAcroRadioButton; + myClass(): PDFClasses { + return PDFClasses.PDFAcroRadioButton; + } static fromDict = (dict: PDFDict, ref: PDFRef) => new PDFAcroRadioButton(dict, ref); @@ -38,7 +43,7 @@ class PDFAcroRadioButton extends PDFAcroButton { getValue(): PDFName { const v = this.V(); - if (v instanceof PDFName) return v; + if (isPDFInstance(v, PDFClasses.PDFName)) return v as PDFName; return PDFName.of('Off'); } diff --git a/src/core/acroform/PDFAcroSignature.ts b/src/core/acroform/PDFAcroSignature.ts index 8b7c1ca37..8f6a6bed9 100644 --- a/src/core/acroform/PDFAcroSignature.ts +++ b/src/core/acroform/PDFAcroSignature.ts @@ -1,8 +1,13 @@ -import PDFDict from 'src/core/objects/PDFDict'; -import PDFRef from 'src/core/objects/PDFRef'; -import PDFAcroTerminal from 'src/core/acroform/PDFAcroTerminal'; +import { PDFClasses } from '../../api/objects'; +import PDFDict from '../objects/PDFDict'; +import PDFRef from '../objects/PDFRef'; +import PDFAcroTerminal from './PDFAcroTerminal'; class PDFAcroSignature extends PDFAcroTerminal { + static className = () => PDFClasses.PDFAcroSignature; + myClass(): PDFClasses { + return PDFClasses.PDFAcroSignature; + } static fromDict = (dict: PDFDict, ref: PDFRef) => new PDFAcroSignature(dict, ref); } diff --git a/src/core/acroform/PDFAcroTerminal.ts b/src/core/acroform/PDFAcroTerminal.ts index 8f307dbff..c26aec80c 100644 --- a/src/core/acroform/PDFAcroTerminal.ts +++ b/src/core/acroform/PDFAcroTerminal.ts @@ -1,9 +1,9 @@ -import PDFDict from 'src/core/objects/PDFDict'; -import PDFName from 'src/core/objects/PDFName'; -import PDFRef from 'src/core/objects/PDFRef'; -import PDFAcroField from 'src/core/acroform/PDFAcroField'; -import PDFWidgetAnnotation from 'src/core/annotation/PDFWidgetAnnotation'; -import { IndexOutOfBoundsError } from 'src/core/errors'; +import PDFDict from '../objects/PDFDict'; +import PDFName from '../objects/PDFName'; +import PDFRef from '../objects/PDFRef'; +import PDFAcroField from './PDFAcroField'; +import PDFWidgetAnnotation from '../annotation/PDFWidgetAnnotation'; +import { IndexOutOfBoundsError } from '../errors'; class PDFAcroTerminal extends PDFAcroField { static fromDict = (dict: PDFDict, ref: PDFRef) => diff --git a/src/core/acroform/PDFAcroText.ts b/src/core/acroform/PDFAcroText.ts index 25171bc9d..44b0bf0b1 100644 --- a/src/core/acroform/PDFAcroText.ts +++ b/src/core/acroform/PDFAcroText.ts @@ -1,13 +1,18 @@ -import PDFContext from 'src/core/PDFContext'; -import PDFDict from 'src/core/objects/PDFDict'; -import PDFNumber from 'src/core/objects/PDFNumber'; -import PDFString from 'src/core/objects/PDFString'; -import PDFHexString from 'src/core/objects/PDFHexString'; -import PDFName from 'src/core/objects/PDFName'; -import PDFRef from 'src/core/objects/PDFRef'; -import PDFAcroTerminal from 'src/core/acroform/PDFAcroTerminal'; +import PDFContext from '../PDFContext'; +import PDFDict from '../objects/PDFDict'; +import PDFNumber from '../objects/PDFNumber'; +import PDFString from '../objects/PDFString'; +import PDFHexString from '../objects/PDFHexString'; +import PDFName from '../objects/PDFName'; +import PDFRef from '../objects/PDFRef'; +import PDFAcroTerminal from './PDFAcroTerminal'; +import { isPDFInstance, PDFClasses } from '../../api/objects'; class PDFAcroText extends PDFAcroTerminal { + static className = () => PDFClasses.PDFAcroText; + myClass(): PDFClasses { + return PDFClasses.PDFAcroText; + } static fromDict = (dict: PDFDict, ref: PDFRef) => new PDFAcroText(dict, ref); static create = (context: PDFContext) => { @@ -21,13 +26,13 @@ class PDFAcroText extends PDFAcroTerminal { MaxLen(): PDFNumber | undefined { const maxLen = this.dict.lookup(PDFName.of('MaxLen')); - if (maxLen instanceof PDFNumber) return maxLen; + if (isPDFInstance(maxLen, PDFClasses.PDFNumber)) return maxLen as PDFNumber; return undefined; } Q(): PDFNumber | undefined { const q = this.dict.lookup(PDFName.of('Q')); - if (q instanceof PDFNumber) return q; + if (isPDFInstance(q, PDFClasses.PDFNumber)) return q as PDFNumber; return undefined; } @@ -68,7 +73,11 @@ class PDFAcroText extends PDFAcroTerminal { getValue(): PDFString | PDFHexString | undefined { const v = this.V(); - if (v instanceof PDFString || v instanceof PDFHexString) return v; + if ( + isPDFInstance(v, PDFClasses.PDFString) || + isPDFInstance(v, PDFClasses.PDFHexString) + ) + return v as PDFString | PDFHexString; return undefined; } } diff --git a/src/core/acroform/index.ts b/src/core/acroform/index.ts index 25ee8ef04..972558d02 100644 --- a/src/core/acroform/index.ts +++ b/src/core/acroform/index.ts @@ -1,15 +1,15 @@ -export { default as PDFAcroButton } from 'src/core/acroform/PDFAcroButton'; -export { default as PDFAcroCheckBox } from 'src/core/acroform/PDFAcroCheckBox'; -export { default as PDFAcroChoice } from 'src/core/acroform/PDFAcroChoice'; -export { default as PDFAcroComboBox } from 'src/core/acroform/PDFAcroComboBox'; -export { default as PDFAcroField } from 'src/core/acroform/PDFAcroField'; -export { default as PDFAcroForm } from 'src/core/acroform/PDFAcroForm'; -export { default as PDFAcroListBox } from 'src/core/acroform/PDFAcroListBox'; -export { default as PDFAcroNonTerminal } from 'src/core/acroform/PDFAcroNonTerminal'; -export { default as PDFAcroPushButton } from 'src/core/acroform/PDFAcroPushButton'; -export { default as PDFAcroRadioButton } from 'src/core/acroform/PDFAcroRadioButton'; -export { default as PDFAcroSignature } from 'src/core/acroform/PDFAcroSignature'; -export { default as PDFAcroTerminal } from 'src/core/acroform/PDFAcroTerminal'; -export { default as PDFAcroText } from 'src/core/acroform/PDFAcroText'; -export * from 'src/core/acroform/flags'; -export * from 'src/core/acroform/utils'; +export { default as PDFAcroButton } from './PDFAcroButton'; +export { default as PDFAcroCheckBox } from './PDFAcroCheckBox'; +export { default as PDFAcroChoice } from './PDFAcroChoice'; +export { default as PDFAcroComboBox } from './PDFAcroComboBox'; +export { default as PDFAcroField } from './PDFAcroField'; +export { default as PDFAcroForm } from './PDFAcroForm'; +export { default as PDFAcroListBox } from './PDFAcroListBox'; +export { default as PDFAcroNonTerminal } from './PDFAcroNonTerminal'; +export { default as PDFAcroPushButton } from './PDFAcroPushButton'; +export { default as PDFAcroRadioButton } from './PDFAcroRadioButton'; +export { default as PDFAcroSignature } from './PDFAcroSignature'; +export { default as PDFAcroTerminal } from './PDFAcroTerminal'; +export { default as PDFAcroText } from './PDFAcroText'; +export * from './flags'; +export * from './utils'; diff --git a/src/core/acroform/utils.ts b/src/core/acroform/utils.ts index 9f051b6be..232024552 100644 --- a/src/core/acroform/utils.ts +++ b/src/core/acroform/utils.ts @@ -1,23 +1,24 @@ -import PDFObject from 'src/core/objects/PDFObject'; -import PDFNumber from 'src/core/objects/PDFNumber'; -import PDFDict from 'src/core/objects/PDFDict'; -import PDFName from 'src/core/objects/PDFName'; -import PDFArray from 'src/core/objects/PDFArray'; -import PDFRef from 'src/core/objects/PDFRef'; - -import PDFAcroField from 'src/core/acroform/PDFAcroField'; -import PDFAcroTerminal from 'src/core/acroform/PDFAcroTerminal'; -import PDFAcroNonTerminal from 'src/core/acroform/PDFAcroNonTerminal'; -import PDFAcroButton from 'src/core/acroform/PDFAcroButton'; -import PDFAcroSignature from 'src/core/acroform/PDFAcroSignature'; -import PDFAcroChoice from 'src/core/acroform/PDFAcroChoice'; -import PDFAcroText from 'src/core/acroform/PDFAcroText'; -import PDFAcroPushButton from 'src/core/acroform/PDFAcroPushButton'; -import PDFAcroRadioButton from 'src/core/acroform/PDFAcroRadioButton'; -import PDFAcroCheckBox from 'src/core/acroform/PDFAcroCheckBox'; -import PDFAcroComboBox from 'src/core/acroform/PDFAcroComboBox'; -import PDFAcroListBox from 'src/core/acroform/PDFAcroListBox'; -import { AcroButtonFlags, AcroChoiceFlags } from 'src/core/acroform/flags'; +import PDFObject from '../objects/PDFObject'; +import PDFNumber from '../objects/PDFNumber'; +import PDFDict from '../objects/PDFDict'; +import PDFName from '../objects/PDFName'; +import PDFArray from '../objects/PDFArray'; +import PDFRef from '../objects/PDFRef'; + +import PDFAcroField from './PDFAcroField'; +import PDFAcroTerminal from './PDFAcroTerminal'; +import PDFAcroNonTerminal from './PDFAcroNonTerminal'; +import PDFAcroButton from './PDFAcroButton'; +import PDFAcroSignature from './PDFAcroSignature'; +import PDFAcroChoice from './PDFAcroChoice'; +import PDFAcroText from './PDFAcroText'; +import PDFAcroPushButton from './PDFAcroPushButton'; +import PDFAcroRadioButton from './PDFAcroRadioButton'; +import PDFAcroCheckBox from './PDFAcroCheckBox'; +import PDFAcroComboBox from './PDFAcroComboBox'; +import PDFAcroListBox from './PDFAcroListBox'; +import { AcroButtonFlags, AcroChoiceFlags } from './flags'; +import { isPDFInstance, PDFClasses } from '../../api/objects'; export const createPDFAcroFields = ( kidDicts?: PDFArray, @@ -28,9 +29,15 @@ export const createPDFAcroFields = ( for (let idx = 0, len = kidDicts.size(); idx < len; idx++) { const ref = kidDicts.get(idx); const dict = kidDicts.lookup(idx); - // if (dict instanceof PDFDict) kids.push(PDFAcroField.fromDict(dict)); - if (ref instanceof PDFRef && dict instanceof PDFDict) { - kids.push([createPDFAcroField(dict, ref), ref]); + // if (isPDFInstance(dict, PDFClasses.PDFDict)) kids.push(PDFAcroField.fromDict(dict)); + if ( + isPDFInstance(ref, PDFClasses.PDFRef) && + isPDFInstance(dict, PDFClasses.PDFDict) + ) { + kids.push([ + createPDFAcroField(dict as PDFDict, ref as PDFRef), + ref as PDFRef, + ]); } } @@ -65,10 +72,12 @@ export const createPDFAcroField = ( const isNonTerminalAcroField = (dict: PDFDict): boolean => { const kids = dict.lookup(PDFName.of('Kids')); - if (kids instanceof PDFArray) { - for (let idx = 0, len = kids.size(); idx < len; idx++) { - const kid = kids.lookup(idx); - const kidIsField = kid instanceof PDFDict && kid.has(PDFName.of('T')); + if (isPDFInstance(kids, PDFClasses.PDFArray)) { + for (let idx = 0, len = (kids as PDFArray).size(); idx < len; idx++) { + const kid = (kids as PDFArray).lookup(idx); + const kidIsField = + isPDFInstance(kid, PDFClasses.PDFDict) && + (kid as PDFDict).has(PDFName.of('T')); if (kidIsField) return true; } } diff --git a/src/core/annotation/AppearanceCharacteristics.ts b/src/core/annotation/AppearanceCharacteristics.ts index 5e9ec2357..e011053ac 100644 --- a/src/core/annotation/AppearanceCharacteristics.ts +++ b/src/core/annotation/AppearanceCharacteristics.ts @@ -1,9 +1,10 @@ -import PDFDict from 'src/core/objects/PDFDict'; -import PDFName from 'src/core/objects/PDFName'; -import PDFNumber from 'src/core/objects/PDFNumber'; -import PDFArray from 'src/core/objects/PDFArray'; -import PDFHexString from 'src/core/objects/PDFHexString'; -import PDFString from 'src/core/objects/PDFString'; +import PDFDict from '../objects/PDFDict'; +import PDFName from '../objects/PDFName'; +import PDFNumber from '../objects/PDFNumber'; +import PDFArray from '../objects/PDFArray'; +import PDFHexString from '../objects/PDFHexString'; +import PDFString from '../objects/PDFString'; +import { isPDFInstance, PDFClasses } from '../../api/objects'; class AppearanceCharacteristics { readonly dict: PDFDict; @@ -17,37 +18,49 @@ class AppearanceCharacteristics { R(): PDFNumber | undefined { const R = this.dict.lookup(PDFName.of('R')); - if (R instanceof PDFNumber) return R; + if (isPDFInstance(R, PDFClasses.PDFNumber)) return R as PDFNumber; return undefined; } BC(): PDFArray | undefined { const BC = this.dict.lookup(PDFName.of('BC')); - if (BC instanceof PDFArray) return BC; + if (isPDFInstance(BC, PDFClasses.PDFArray)) return BC as PDFArray; return undefined; } BG(): PDFArray | undefined { const BG = this.dict.lookup(PDFName.of('BG')); - if (BG instanceof PDFArray) return BG; + if (isPDFInstance(BG, PDFClasses.PDFArray)) return BG as PDFArray; return undefined; } CA(): PDFHexString | PDFString | undefined { const CA = this.dict.lookup(PDFName.of('CA')); - if (CA instanceof PDFHexString || CA instanceof PDFString) return CA; + if ( + isPDFInstance(CA, PDFClasses.PDFHexString) || + isPDFInstance(CA, PDFClasses.PDFString) + ) + return CA as PDFString | PDFHexString; return undefined; } RC(): PDFHexString | PDFString | undefined { const RC = this.dict.lookup(PDFName.of('RC')); - if (RC instanceof PDFHexString || RC instanceof PDFString) return RC; + if ( + isPDFInstance(RC, PDFClasses.PDFHexString) || + isPDFInstance(RC, PDFClasses.PDFString) + ) + return RC as PDFString | PDFHexString; return undefined; } AC(): PDFHexString | PDFString | undefined { const AC = this.dict.lookup(PDFName.of('AC')); - if (AC instanceof PDFHexString || AC instanceof PDFString) return AC; + if ( + isPDFInstance(AC, PDFClasses.PDFHexString) || + isPDFInstance(AC, PDFClasses.PDFString) + ) + return AC as PDFString | PDFHexString; return undefined; } @@ -63,7 +76,8 @@ class AppearanceCharacteristics { const components: number[] = []; for (let idx = 0, len = BC?.size(); idx < len; idx++) { const component = BC.get(idx); - if (component instanceof PDFNumber) components.push(component.asNumber()); + if (isPDFInstance(component, PDFClasses.PDFNumber)) + components.push((component as PDFNumber).asNumber()); } return components; @@ -77,7 +91,8 @@ class AppearanceCharacteristics { const components: number[] = []; for (let idx = 0, len = BG?.size(); idx < len; idx++) { const component = BG.get(idx); - if (component instanceof PDFNumber) components.push(component.asNumber()); + if (isPDFInstance(component, PDFClasses.PDFNumber)) + components.push((component as PDFNumber).asNumber()); } return components; diff --git a/src/core/annotation/BorderStyle.ts b/src/core/annotation/BorderStyle.ts index 5ebc13b30..8e5faed1e 100644 --- a/src/core/annotation/BorderStyle.ts +++ b/src/core/annotation/BorderStyle.ts @@ -1,6 +1,7 @@ -import PDFDict from 'src/core/objects/PDFDict'; -import PDFName from 'src/core/objects/PDFName'; -import PDFNumber from 'src/core/objects/PDFNumber'; +import { isPDFInstance, PDFClasses } from '../../api/objects'; +import PDFDict from '../objects/PDFDict'; +import PDFName from '../objects/PDFName'; +import PDFNumber from '../objects/PDFNumber'; // TODO: Also handle the `/S` and `/D` entries class BorderStyle { @@ -14,7 +15,7 @@ class BorderStyle { W(): PDFNumber | undefined { const W = this.dict.lookup(PDFName.of('W')); - if (W instanceof PDFNumber) return W; + if (isPDFInstance(W, PDFClasses.PDFNumber)) return W as PDFNumber; return undefined; } diff --git a/src/core/annotation/PDFAnnotation.ts b/src/core/annotation/PDFAnnotation.ts index d62258251..e94e837b3 100644 --- a/src/core/annotation/PDFAnnotation.ts +++ b/src/core/annotation/PDFAnnotation.ts @@ -1,9 +1,10 @@ -import PDFDict from 'src/core/objects/PDFDict'; -import PDFName from 'src/core/objects/PDFName'; -import PDFStream from 'src/core/objects/PDFStream'; -import PDFArray from 'src/core/objects/PDFArray'; -import PDFRef from 'src/core/objects/PDFRef'; -import PDFNumber from 'src/core/objects/PDFNumber'; +import PDFDict from '../objects/PDFDict'; +import PDFName from '../objects/PDFName'; +import PDFStream from '../objects/PDFStream'; +import PDFArray from '../objects/PDFArray'; +import PDFRef from '../objects/PDFRef'; +import PDFNumber from '../objects/PDFNumber'; +import { isPDFInstance, PDFClasses } from '../../api/objects'; class PDFAnnotation { readonly dict: PDFDict; @@ -41,7 +42,7 @@ class PDFAnnotation { getAppearanceState(): PDFName | undefined { const AS = this.dict.lookup(PDFName.of('AS')); - if (AS instanceof PDFName) return AS; + if (isPDFInstance(AS, PDFClasses.PDFName)) return AS as PDFName; return undefined; } @@ -65,7 +66,11 @@ class PDFAnnotation { getNormalAppearance(): PDFRef | PDFDict { const AP = this.ensureAP(); const N = AP.get(PDFName.of('N')); - if (N instanceof PDFRef || N instanceof PDFDict) return N; + if ( + isPDFInstance(N, PDFClasses.PDFRef) || + isPDFInstance(N, PDFClasses.PDFDict) + ) + return N as PDFRef | PDFDict; throw new Error(`Unexpected N type: ${N?.constructor.name}`); } diff --git a/src/core/annotation/PDFWidgetAnnotation.ts b/src/core/annotation/PDFWidgetAnnotation.ts index c87903081..92e1a3255 100644 --- a/src/core/annotation/PDFWidgetAnnotation.ts +++ b/src/core/annotation/PDFWidgetAnnotation.ts @@ -1,12 +1,13 @@ -import PDFDict from 'src/core/objects/PDFDict'; -import PDFName from 'src/core/objects/PDFName'; -import PDFRef from 'src/core/objects/PDFRef'; -import PDFString from 'src/core/objects/PDFString'; -import PDFHexString from 'src/core/objects/PDFHexString'; -import PDFContext from 'src/core/PDFContext'; -import BorderStyle from 'src/core/annotation/BorderStyle'; -import PDFAnnotation from 'src/core/annotation/PDFAnnotation'; -import AppearanceCharacteristics from 'src/core/annotation/AppearanceCharacteristics'; +import PDFDict from '../objects/PDFDict'; +import PDFName from '../objects/PDFName'; +import PDFRef from '../objects/PDFRef'; +import PDFString from '../objects/PDFString'; +import PDFHexString from '../objects/PDFHexString'; +import PDFContext from '../PDFContext'; +import BorderStyle from './BorderStyle'; +import PDFAnnotation from './PDFAnnotation'; +import AppearanceCharacteristics from './AppearanceCharacteristics'; +import { isPDFInstance, PDFClasses } from '../../api/objects'; class PDFWidgetAnnotation extends PDFAnnotation { static fromDict = (dict: PDFDict): PDFWidgetAnnotation => @@ -24,25 +25,29 @@ class PDFWidgetAnnotation extends PDFAnnotation { MK(): PDFDict | undefined { const MK = this.dict.lookup(PDFName.of('MK')); - if (MK instanceof PDFDict) return MK; + if (isPDFInstance(MK, PDFClasses.PDFDict)) return MK as PDFDict; return undefined; } BS(): PDFDict | undefined { const BS = this.dict.lookup(PDFName.of('BS')); - if (BS instanceof PDFDict) return BS; + if (isPDFInstance(BS, PDFClasses.PDFDict)) return BS as PDFDict; return undefined; } DA(): PDFString | PDFHexString | undefined { const da = this.dict.lookup(PDFName.of('DA')); - if (da instanceof PDFString || da instanceof PDFHexString) return da; + if ( + isPDFInstance(da, PDFClasses.PDFString) || + isPDFInstance(da, PDFClasses.PDFHexString) + ) + return da as PDFString | PDFHexString; return undefined; } P(): PDFRef | undefined { const P = this.dict.get(PDFName.of('P')); - if (P instanceof PDFRef) return P; + if (isPDFInstance(P, PDFClasses.PDFRef)) return P as PDFRef; return undefined; } @@ -57,8 +62,8 @@ class PDFWidgetAnnotation extends PDFAnnotation { getDefaultAppearance(): string | undefined { const DA = this.DA(); - if (DA instanceof PDFHexString) { - return DA.decodeText(); + if (isPDFInstance(DA, PDFClasses.PDFHexString)) { + return (DA as PDFHexString).decodeText(); } return DA?.asString(); @@ -97,8 +102,8 @@ class PDFWidgetAnnotation extends PDFAnnotation { getOnValue(): PDFName | undefined { const normal = this.getAppearances()?.normal; - if (normal instanceof PDFDict) { - const keys = normal.keys(); + if (isPDFInstance(normal, PDFClasses.PDFDict)) { + const keys = (normal as PDFDict).keys(); for (let idx = 0, len = keys.length; idx < len; idx++) { const key = keys[idx]; if (key !== PDFName.of('Off')) return key; diff --git a/src/core/annotation/index.ts b/src/core/annotation/index.ts index 60b9d6d57..2e42734fc 100644 --- a/src/core/annotation/index.ts +++ b/src/core/annotation/index.ts @@ -1,4 +1,4 @@ -export { default as PDFAnnotation } from 'src/core/annotation/PDFAnnotation'; -export { default as PDFWidgetAnnotation } from 'src/core/annotation/PDFWidgetAnnotation'; -export { default as AppearanceCharacteristics } from 'src/core/annotation/AppearanceCharacteristics'; -export * from 'src/core/annotation/flags'; +export { default as PDFAnnotation } from './PDFAnnotation'; +export { default as PDFWidgetAnnotation } from './PDFWidgetAnnotation'; +export { default as AppearanceCharacteristics } from './AppearanceCharacteristics'; +export * from './flags'; diff --git a/src/core/crypto.ts b/src/core/crypto.ts new file mode 100644 index 000000000..3bc9c0fb3 --- /dev/null +++ b/src/core/crypto.ts @@ -0,0 +1,2005 @@ +/* Copyright 2012 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* tslint:disable */ + +import { isPDFInstance, PDFClasses } from '../api/objects'; +import { arrayAsString, isArrayEqual } from '../utils/arrays'; +import { stringAsByteArray } from '../utils/strings'; +import PDFBool from './objects/PDFBool'; +import PDFDict from './objects/PDFDict'; +import PDFName from './objects/PDFName'; +import PDFNumber from './objects/PDFNumber'; +import PDFString from './objects/PDFString'; +import DecryptStream from './streams/DecryptStream'; +import { StreamType } from './streams/Stream'; + +class ARCFourCipher { + private s: Uint8Array; + private a: number; + private b: number; + + constructor(key: Uint8Array) { + this.a = 0; + this.b = 0; + const s = new Uint8Array(256); + const keyLength = key.length; + + for (let i = 0; i < 256; ++i) { + s[i] = i; + } + for (let i = 0, j = 0; i < 256; ++i) { + const tmp = s[i]; + j = (j + tmp + key[i % keyLength]) & 0xff; + s[i] = s[j]; + s[j] = tmp; + } + this.s = s; + } + + encryptBlock(data: Uint8Array) { + let a = this.a, + b = this.b; + const s = this.s; + const n = data.length; + const output = new Uint8Array(n); + for (let i = 0; i < n; ++i) { + a = (a + 1) & 0xff; + const tmp = s[a]; + b = (b + tmp) & 0xff; + const tmp2 = s[b]; + s[a] = tmp2; + s[b] = tmp; + output[i] = data[i] ^ s[(tmp + tmp2) & 0xff]; + } + this.a = a; + this.b = b; + return output; + } + + decryptBlock(data: Uint8Array) { + return this.encryptBlock(data); + } + + encrypt(data: Uint8Array) { + return this.encryptBlock(data); + } +} + +const calculateMD5 = (function calculateMD5Closure() { + const r = new Uint8Array([ + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, + 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, + 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, + 15, 21, + ]); + + const k = new Int32Array([ + -680876936, -389564586, 606105819, -1044525330, -176418897, 1200080426, + -1473231341, -45705983, 1770035416, -1958414417, -42063, -1990404162, + 1804603682, -40341101, -1502002290, 1236535329, -165796510, -1069501632, + 643717713, -373897302, -701558691, 38016083, -660478335, -405537848, + 568446438, -1019803690, -187363961, 1163531501, -1444681467, -51403784, + 1735328473, -1926607734, -378558, -2022574463, 1839030562, -35309556, + -1530992060, 1272893353, -155497632, -1094730640, 681279174, -358537222, + -722521979, 76029189, -640364487, -421815835, 530742520, -995338651, + -198630844, 1126891415, -1416354905, -57434055, 1700485571, -1894986606, + -1051523, -2054922799, 1873313359, -30611744, -1560198380, 1309151649, + -145523070, -1120210379, 718787259, -343485551, + ]); + + function hash(data: Uint8Array, offset: number, length: number) { + let h0 = 1732584193, + h1 = -271733879, + h2 = -1732584194, + h3 = 271733878; + // pre-processing + const paddedLength = (length + 72) & ~63; // data + 9 extra bytes + const padded = new Uint8Array(paddedLength); + let i, j; + for (i = 0; i < length; ++i) { + padded[i] = data[offset++]; + } + padded[i++] = 0x80; + const n = paddedLength - 8; + while (i < n) { + padded[i++] = 0; + } + padded[i++] = (length << 3) & 0xff; + padded[i++] = (length >> 5) & 0xff; + padded[i++] = (length >> 13) & 0xff; + padded[i++] = (length >> 21) & 0xff; + padded[i++] = (length >>> 29) & 0xff; + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = 0; + const w = new Int32Array(16); + for (i = 0; i < paddedLength; ) { + for (j = 0; j < 16; ++j, i += 4) { + w[j] = + padded[i] | + (padded[i + 1] << 8) | + (padded[i + 2] << 16) | + (padded[i + 3] << 24); + } + let a = h0, + b = h1, + c = h2, + d = h3, + f, + g; + for (j = 0; j < 64; ++j) { + if (j < 16) { + f = (b & c) | (~b & d); + g = j; + } else if (j < 32) { + f = (d & b) | (~d & c); + g = (5 * j + 1) & 15; + } else if (j < 48) { + f = b ^ c ^ d; + g = (3 * j + 5) & 15; + } else { + f = c ^ (b | ~d); + g = (7 * j) & 15; + } + const tmp = d, + rotateArg = (a + f + k[j] + w[g]) | 0, + rotate = r[j]; + d = c; + c = b; + b = (b + ((rotateArg << rotate) | (rotateArg >>> (32 - rotate)))) | 0; + a = tmp; + } + h0 = (h0 + a) | 0; + h1 = (h1 + b) | 0; + h2 = (h2 + c) | 0; + h3 = (h3 + d) | 0; + } + // prettier-ignore + return new Uint8Array([ + h0 & 0xFF, (h0 >> 8) & 0xFF, (h0 >> 16) & 0xFF, (h0 >>> 24) & 0xFF, + h1 & 0xFF, (h1 >> 8) & 0xFF, (h1 >> 16) & 0xFF, (h1 >>> 24) & 0xFF, + h2 & 0xFF, (h2 >> 8) & 0xFF, (h2 >> 16) & 0xFF, (h2 >>> 24) & 0xFF, + h3 & 0xFF, (h3 >> 8) & 0xFF, (h3 >> 16) & 0xFF, (h3 >>> 24) & 0xFF + ]); + } + + return hash; +})(); + +class Word64 { + private low: number; + private high: number; + + constructor(highInteger: number, lowInteger: number) { + this.high = highInteger | 0; + this.low = lowInteger | 0; + } + + and(word: Word64) { + this.high &= word.high; + this.low &= word.low; + } + + xor(word: Word64) { + this.high ^= word.high; + this.low ^= word.low; + } + + or(word: Word64) { + this.high |= word.high; + this.low |= word.low; + } + + shiftRight(places: number) { + if (places >= 32) { + this.low = (this.high >>> (places - 32)) | 0; + this.high = 0; + } else { + this.low = (this.low >>> places) | (this.high << (32 - places)); + this.high = (this.high >>> places) | 0; + } + } + + shiftLeft(places: number) { + if (places >= 32) { + this.high = this.low << (places - 32); + this.low = 0; + } else { + this.high = (this.high << places) | (this.low >>> (32 - places)); + this.low <<= places; + } + } + + rotateRight(places: number) { + let low, high; + if (places & 32) { + high = this.low; + low = this.high; + } else { + low = this.low; + high = this.high; + } + places &= 31; + this.low = (low >>> places) | (high << (32 - places)); + this.high = (high >>> places) | (low << (32 - places)); + } + + not() { + this.high = ~this.high; + this.low = ~this.low; + } + + add(word: Word64) { + const lowAdd = (this.low >>> 0) + (word.low >>> 0); + let highAdd = (this.high >>> 0) + (word.high >>> 0); + if (lowAdd > 0xffffffff) { + highAdd += 1; + } + this.low = lowAdd | 0; + this.high = highAdd | 0; + } + + copyTo(bytes: Uint8Array, offset: number) { + bytes[offset] = (this.high >>> 24) & 0xff; + bytes[offset + 1] = (this.high >> 16) & 0xff; + bytes[offset + 2] = (this.high >> 8) & 0xff; + bytes[offset + 3] = this.high & 0xff; + bytes[offset + 4] = (this.low >>> 24) & 0xff; + bytes[offset + 5] = (this.low >> 16) & 0xff; + bytes[offset + 6] = (this.low >> 8) & 0xff; + bytes[offset + 7] = this.low & 0xff; + } + + assign(word: Word64) { + this.high = word.high; + this.low = word.low; + } +} + +const calculateSHA256 = (function calculateSHA256Closure() { + function rotr(x: number, n: number) { + return (x >>> n) | (x << (32 - n)); + } + + function ch(x: number, y: number, z: number) { + return (x & y) ^ (~x & z); + } + + function maj(x: number, y: number, z: number) { + return (x & y) ^ (x & z) ^ (y & z); + } + + function sigma(x: number) { + return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22); + } + + function sigmaPrime(x: number) { + return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25); + } + + function littleSigma(x: number) { + return rotr(x, 7) ^ rotr(x, 18) ^ (x >>> 3); + } + + function littleSigmaPrime(x: number) { + return rotr(x, 17) ^ rotr(x, 19) ^ (x >>> 10); + } + + const k = [ + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, + 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, + 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, + 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, + 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, + ]; + + function hash(data: Uint8Array, offset: number, length: number) { + // initial hash values + let h0 = 0x6a09e667, + h1 = 0xbb67ae85, + h2 = 0x3c6ef372, + h3 = 0xa54ff53a, + h4 = 0x510e527f, + h5 = 0x9b05688c, + h6 = 0x1f83d9ab, + h7 = 0x5be0cd19; + // pre-processing + const paddedLength = Math.ceil((length + 9) / 64) * 64; + const padded = new Uint8Array(paddedLength); + let i, j; + for (i = 0; i < length; ++i) { + padded[i] = data[offset++]; + } + padded[i++] = 0x80; + const n = paddedLength - 8; + while (i < n) { + padded[i++] = 0; + } + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = (length >>> 29) & 0xff; + padded[i++] = (length >> 21) & 0xff; + padded[i++] = (length >> 13) & 0xff; + padded[i++] = (length >> 5) & 0xff; + padded[i++] = (length << 3) & 0xff; + const w = new Uint32Array(64); + // for each 512 bit block + for (i = 0; i < paddedLength; ) { + for (j = 0; j < 16; ++j) { + w[j] = + (padded[i] << 24) | + (padded[i + 1] << 16) | + (padded[i + 2] << 8) | + padded[i + 3]; + i += 4; + } + + for (j = 16; j < 64; ++j) { + w[j] = + (littleSigmaPrime(w[j - 2]) + + w[j - 7] + + littleSigma(w[j - 15]) + + w[j - 16]) | + 0; + } + let a = h0, + b = h1, + c = h2, + d = h3, + e = h4, + f = h5, + g = h6, + h = h7, + t1, + t2; + for (j = 0; j < 64; ++j) { + t1 = h + sigmaPrime(e) + ch(e, f, g) + k[j] + w[j]; + t2 = sigma(a) + maj(a, b, c); + h = g; + g = f; + f = e; + e = (d + t1) | 0; + d = c; + c = b; + b = a; + a = (t1 + t2) | 0; + } + h0 = (h0 + a) | 0; + h1 = (h1 + b) | 0; + h2 = (h2 + c) | 0; + h3 = (h3 + d) | 0; + h4 = (h4 + e) | 0; + h5 = (h5 + f) | 0; + h6 = (h6 + g) | 0; + h7 = (h7 + h) | 0; + } + // prettier-ignore + return new Uint8Array([ + (h0 >> 24) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 8) & 0xFF, (h0) & 0xFF, + (h1 >> 24) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 8) & 0xFF, (h1) & 0xFF, + (h2 >> 24) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 8) & 0xFF, (h2) & 0xFF, + (h3 >> 24) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 8) & 0xFF, (h3) & 0xFF, + (h4 >> 24) & 0xFF, (h4 >> 16) & 0xFF, (h4 >> 8) & 0xFF, (h4) & 0xFF, + (h5 >> 24) & 0xFF, (h5 >> 16) & 0xFF, (h5 >> 8) & 0xFF, (h5) & 0xFF, + (h6 >> 24) & 0xFF, (h6 >> 16) & 0xFF, (h6 >> 8) & 0xFF, (h6) & 0xFF, + (h7 >> 24) & 0xFF, (h7 >> 16) & 0xFF, (h7 >> 8) & 0xFF, (h7) & 0xFF + ]); + } + + return hash; +})(); + +const calculateSHA512 = (function calculateSHA512Closure() { + function ch(result: Word64, x: Word64, y: Word64, z: Word64, tmp: Word64) { + result.assign(x); + result.and(y); + tmp.assign(x); + tmp.not(); + tmp.and(z); + result.xor(tmp); + } + + function maj(result: Word64, x: Word64, y: Word64, z: Word64, tmp: Word64) { + result.assign(x); + result.and(y); + tmp.assign(x); + tmp.and(z); + result.xor(tmp); + tmp.assign(y); + tmp.and(z); + result.xor(tmp); + } + + function sigma(result: Word64, x: Word64, tmp: Word64) { + result.assign(x); + result.rotateRight(28); + tmp.assign(x); + tmp.rotateRight(34); + result.xor(tmp); + tmp.assign(x); + tmp.rotateRight(39); + result.xor(tmp); + } + + function sigmaPrime(result: Word64, x: Word64, tmp: Word64) { + result.assign(x); + result.rotateRight(14); + tmp.assign(x); + tmp.rotateRight(18); + result.xor(tmp); + tmp.assign(x); + tmp.rotateRight(41); + result.xor(tmp); + } + + function littleSigma(result: Word64, x: Word64, tmp: Word64) { + result.assign(x); + result.rotateRight(1); + tmp.assign(x); + tmp.rotateRight(8); + result.xor(tmp); + tmp.assign(x); + tmp.shiftRight(7); + result.xor(tmp); + } + + function littleSigmaPrime(result: Word64, x: Word64, tmp: Word64) { + result.assign(x); + result.rotateRight(19); + tmp.assign(x); + tmp.rotateRight(61); + result.xor(tmp); + tmp.assign(x); + tmp.shiftRight(6); + result.xor(tmp); + } + + // prettier-ignore + const k = [ + new Word64(0x428a2f98, 0xd728ae22), new Word64(0x71374491, 0x23ef65cd), + new Word64(0xb5c0fbcf, 0xec4d3b2f), new Word64(0xe9b5dba5, 0x8189dbbc), + new Word64(0x3956c25b, 0xf348b538), new Word64(0x59f111f1, 0xb605d019), + new Word64(0x923f82a4, 0xaf194f9b), new Word64(0xab1c5ed5, 0xda6d8118), + new Word64(0xd807aa98, 0xa3030242), new Word64(0x12835b01, 0x45706fbe), + new Word64(0x243185be, 0x4ee4b28c), new Word64(0x550c7dc3, 0xd5ffb4e2), + new Word64(0x72be5d74, 0xf27b896f), new Word64(0x80deb1fe, 0x3b1696b1), + new Word64(0x9bdc06a7, 0x25c71235), new Word64(0xc19bf174, 0xcf692694), + new Word64(0xe49b69c1, 0x9ef14ad2), new Word64(0xefbe4786, 0x384f25e3), + new Word64(0x0fc19dc6, 0x8b8cd5b5), new Word64(0x240ca1cc, 0x77ac9c65), + new Word64(0x2de92c6f, 0x592b0275), new Word64(0x4a7484aa, 0x6ea6e483), + new Word64(0x5cb0a9dc, 0xbd41fbd4), new Word64(0x76f988da, 0x831153b5), + new Word64(0x983e5152, 0xee66dfab), new Word64(0xa831c66d, 0x2db43210), + new Word64(0xb00327c8, 0x98fb213f), new Word64(0xbf597fc7, 0xbeef0ee4), + new Word64(0xc6e00bf3, 0x3da88fc2), new Word64(0xd5a79147, 0x930aa725), + new Word64(0x06ca6351, 0xe003826f), new Word64(0x14292967, 0x0a0e6e70), + new Word64(0x27b70a85, 0x46d22ffc), new Word64(0x2e1b2138, 0x5c26c926), + new Word64(0x4d2c6dfc, 0x5ac42aed), new Word64(0x53380d13, 0x9d95b3df), + new Word64(0x650a7354, 0x8baf63de), new Word64(0x766a0abb, 0x3c77b2a8), + new Word64(0x81c2c92e, 0x47edaee6), new Word64(0x92722c85, 0x1482353b), + new Word64(0xa2bfe8a1, 0x4cf10364), new Word64(0xa81a664b, 0xbc423001), + new Word64(0xc24b8b70, 0xd0f89791), new Word64(0xc76c51a3, 0x0654be30), + new Word64(0xd192e819, 0xd6ef5218), new Word64(0xd6990624, 0x5565a910), + new Word64(0xf40e3585, 0x5771202a), new Word64(0x106aa070, 0x32bbd1b8), + new Word64(0x19a4c116, 0xb8d2d0c8), new Word64(0x1e376c08, 0x5141ab53), + new Word64(0x2748774c, 0xdf8eeb99), new Word64(0x34b0bcb5, 0xe19b48a8), + new Word64(0x391c0cb3, 0xc5c95a63), new Word64(0x4ed8aa4a, 0xe3418acb), + new Word64(0x5b9cca4f, 0x7763e373), new Word64(0x682e6ff3, 0xd6b2b8a3), + new Word64(0x748f82ee, 0x5defb2fc), new Word64(0x78a5636f, 0x43172f60), + new Word64(0x84c87814, 0xa1f0ab72), new Word64(0x8cc70208, 0x1a6439ec), + new Word64(0x90befffa, 0x23631e28), new Word64(0xa4506ceb, 0xde82bde9), + new Word64(0xbef9a3f7, 0xb2c67915), new Word64(0xc67178f2, 0xe372532b), + new Word64(0xca273ece, 0xea26619c), new Word64(0xd186b8c7, 0x21c0c207), + new Word64(0xeada7dd6, 0xcde0eb1e), new Word64(0xf57d4f7f, 0xee6ed178), + new Word64(0x06f067aa, 0x72176fba), new Word64(0x0a637dc5, 0xa2c898a6), + new Word64(0x113f9804, 0xbef90dae), new Word64(0x1b710b35, 0x131c471b), + new Word64(0x28db77f5, 0x23047d84), new Word64(0x32caab7b, 0x40c72493), + new Word64(0x3c9ebe0a, 0x15c9bebc), new Word64(0x431d67c4, 0x9c100d4c), + new Word64(0x4cc5d4be, 0xcb3e42b6), new Word64(0x597f299c, 0xfc657e2a), + new Word64(0x5fcb6fab, 0x3ad6faec), new Word64(0x6c44198c, 0x4a475817)]; + + function hash( + data: Uint8Array, + offset: number, + length: number, + mode384: boolean = false, + ) { + // initial hash values + let h0, h1, h2, h3, h4, h5, h6, h7; + if (!mode384) { + h0 = new Word64(0x6a09e667, 0xf3bcc908); + h1 = new Word64(0xbb67ae85, 0x84caa73b); + h2 = new Word64(0x3c6ef372, 0xfe94f82b); + h3 = new Word64(0xa54ff53a, 0x5f1d36f1); + h4 = new Word64(0x510e527f, 0xade682d1); + h5 = new Word64(0x9b05688c, 0x2b3e6c1f); + h6 = new Word64(0x1f83d9ab, 0xfb41bd6b); + h7 = new Word64(0x5be0cd19, 0x137e2179); + } else { + // SHA384 is exactly the same + // except with different starting values and a trimmed result + h0 = new Word64(0xcbbb9d5d, 0xc1059ed8); + h1 = new Word64(0x629a292a, 0x367cd507); + h2 = new Word64(0x9159015a, 0x3070dd17); + h3 = new Word64(0x152fecd8, 0xf70e5939); + h4 = new Word64(0x67332667, 0xffc00b31); + h5 = new Word64(0x8eb44a87, 0x68581511); + h6 = new Word64(0xdb0c2e0d, 0x64f98fa7); + h7 = new Word64(0x47b5481d, 0xbefa4fa4); + } + + // pre-processing + const paddedLength = Math.ceil((length + 17) / 128) * 128; + const padded = new Uint8Array(paddedLength); + let i, j; + for (i = 0; i < length; ++i) { + padded[i] = data[offset++]; + } + padded[i++] = 0x80; + const n = paddedLength - 16; + while (i < n) { + padded[i++] = 0; + } + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = (length >>> 29) & 0xff; + padded[i++] = (length >> 21) & 0xff; + padded[i++] = (length >> 13) & 0xff; + padded[i++] = (length >> 5) & 0xff; + padded[i++] = (length << 3) & 0xff; + + const w = new Array(80); + for (i = 0; i < 80; i++) { + w[i] = new Word64(0, 0); + } + let a = new Word64(0, 0), + b = new Word64(0, 0), + c = new Word64(0, 0); + let d = new Word64(0, 0), + e = new Word64(0, 0), + f = new Word64(0, 0); + let g = new Word64(0, 0), + h = new Word64(0, 0); + const t1 = new Word64(0, 0), + t2 = new Word64(0, 0); + const tmp1 = new Word64(0, 0), + tmp2 = new Word64(0, 0); + let tmp3; + + // for each 1024 bit block + for (i = 0; i < paddedLength; ) { + for (j = 0; j < 16; ++j) { + w[j].high = + (padded[i] << 24) | + (padded[i + 1] << 16) | + (padded[i + 2] << 8) | + padded[i + 3]; + w[j].low = + (padded[i + 4] << 24) | + (padded[i + 5] << 16) | + (padded[i + 6] << 8) | + padded[i + 7]; + i += 8; + } + for (j = 16; j < 80; ++j) { + tmp3 = w[j]; + littleSigmaPrime(tmp3, w[j - 2], tmp2); + tmp3.add(w[j - 7]); + littleSigma(tmp1, w[j - 15], tmp2); + tmp3.add(tmp1); + tmp3.add(w[j - 16]); + } + + a.assign(h0); + b.assign(h1); + c.assign(h2); + d.assign(h3); + e.assign(h4); + f.assign(h5); + g.assign(h6); + h.assign(h7); + for (j = 0; j < 80; ++j) { + t1.assign(h); + sigmaPrime(tmp1, e, tmp2); + t1.add(tmp1); + ch(tmp1, e, f, g, tmp2); + t1.add(tmp1); + t1.add(k[j]); + t1.add(w[j]); + + sigma(t2, a, tmp2); + maj(tmp1, a, b, c, tmp2); + t2.add(tmp1); + + tmp3 = h; + h = g; + g = f; + f = e; + d.add(t1); + e = d; + d = c; + c = b; + b = a; + tmp3.assign(t1); + tmp3.add(t2); + a = tmp3; + } + h0.add(a); + h1.add(b); + h2.add(c); + h3.add(d); + h4.add(e); + h5.add(f); + h6.add(g); + h7.add(h); + } + + let result; + if (!mode384) { + result = new Uint8Array(64); + h0.copyTo(result, 0); + h1.copyTo(result, 8); + h2.copyTo(result, 16); + h3.copyTo(result, 24); + h4.copyTo(result, 32); + h5.copyTo(result, 40); + h6.copyTo(result, 48); + h7.copyTo(result, 56); + } else { + result = new Uint8Array(48); + h0.copyTo(result, 0); + h1.copyTo(result, 8); + h2.copyTo(result, 16); + h3.copyTo(result, 24); + h4.copyTo(result, 32); + h5.copyTo(result, 40); + } + return result; + } + + return hash; +})(); + +function calculateSHA384(data: Uint8Array, offset: number, length: number) { + return calculateSHA512(data, offset, length, /* mode384 = */ true); +} + +class NullCipher { + decryptBlock(data: Uint8Array) { + return data; + } + + encrypt(data: Uint8Array) { + return data; + } +} + +class AESBaseCipher { + static className = () => PDFClasses.AESBaseCipher; + myClass(): PDFClasses { + return PDFClasses.AESBaseCipher; + } + protected _s: Uint8Array; + protected _keySize!: number; + protected _key!: Uint8Array; + protected _cyclesOfRepetition!: number; + private _inv_s: Uint8Array; + private _mix: Uint32Array; + private _mixCol: Uint8Array; + buffer: Uint8Array; + bufferPosition: number; + bufferLength!: number; + iv!: Uint8Array; + + constructor() { + if (this.constructor === AESBaseCipher) { + throw new Error('Cannot initialize AESBaseCipher.'); + } + + this._s = new Uint8Array([ + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, + 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, + 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, + 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, + 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, + 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, + 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, + 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, + 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, + 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, + 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, + 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, + 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, + 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, + 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, + 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, + 0xb0, 0x54, 0xbb, 0x16, + ]); + + this._inv_s = new Uint8Array([ + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, + 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, + 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, + 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, + 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, + 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, + 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, + 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, + 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, + 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, + 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, + 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, + 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, + 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, + 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, + 0x55, 0x21, 0x0c, 0x7d, + ]); + + this._mix = new Uint32Array([ + 0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927, + 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45, + 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb, + 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381, + 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf, + 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66, + 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28, + 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012, + 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec, + 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e, + 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd, + 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7, + 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89, + 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b, + 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815, + 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f, + 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa, + 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8, + 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36, + 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c, + 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742, + 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea, + 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4, + 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e, + 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360, + 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502, + 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87, + 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd, + 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3, + 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621, + 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f, + 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55, + 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26, + 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844, + 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba, + 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480, + 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce, + 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67, + 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929, + 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713, + 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed, + 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f, + 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3, + ]); + + this._mixCol = new Uint8Array(256); + for (let i = 0; i < 256; i++) { + if (i < 128) { + this._mixCol[i] = i << 1; + } else { + this._mixCol[i] = (i << 1) ^ 0x1b; + } + } + + this.buffer = new Uint8Array(16); + this.bufferPosition = 0; + } + + _expandKey(_cipherKey: Uint8Array) { + throw new Error('Cannot call `_expandKey` on the base class'); + } + + _decrypt(input: Uint8Array, key: Uint8Array) { + let t, u, v; + const state = new Uint8Array(16); + state.set(input); + + // AddRoundKey + for (let j = 0, k = this._keySize; j < 16; ++j, ++k) { + state[j] ^= key[k]; + } + for (let i = this._cyclesOfRepetition - 1; i >= 1; --i) { + // InvShiftRows + t = state[13]; + state[13] = state[9]; + state[9] = state[5]; + state[5] = state[1]; + state[1] = t; + t = state[14]; + u = state[10]; + state[14] = state[6]; + state[10] = state[2]; + state[6] = t; + state[2] = u; + t = state[15]; + u = state[11]; + v = state[7]; + state[15] = state[3]; + state[11] = t; + state[7] = u; + state[3] = v; + // InvSubBytes + for (let j = 0; j < 16; ++j) { + state[j] = this._inv_s[state[j]]; + } + // AddRoundKey + for (let j = 0, k = i * 16; j < 16; ++j, ++k) { + state[j] ^= key[k]; + } + // InvMixColumns + for (let j = 0; j < 16; j += 4) { + const s0 = this._mix[state[j]]; + const s1 = this._mix[state[j + 1]]; + const s2 = this._mix[state[j + 2]]; + const s3 = this._mix[state[j + 3]]; + t = + s0 ^ + (s1 >>> 8) ^ + (s1 << 24) ^ + (s2 >>> 16) ^ + (s2 << 16) ^ + (s3 >>> 24) ^ + (s3 << 8); + state[j] = (t >>> 24) & 0xff; + state[j + 1] = (t >> 16) & 0xff; + state[j + 2] = (t >> 8) & 0xff; + state[j + 3] = t & 0xff; + } + } + // InvShiftRows + t = state[13]; + state[13] = state[9]; + state[9] = state[5]; + state[5] = state[1]; + state[1] = t; + t = state[14]; + u = state[10]; + state[14] = state[6]; + state[10] = state[2]; + state[6] = t; + state[2] = u; + t = state[15]; + u = state[11]; + v = state[7]; + state[15] = state[3]; + state[11] = t; + state[7] = u; + state[3] = v; + for (let j = 0; j < 16; ++j) { + // InvSubBytes + state[j] = this._inv_s[state[j]]; + // AddRoundKey + state[j] ^= key[j]; + } + return state; + } + + _encrypt(input: Uint8Array, key: Uint8Array) { + const s = this._s; + + let t, u, v; + const state = new Uint8Array(16); + state.set(input); + + for (let j = 0; j < 16; ++j) { + // AddRoundKey + state[j] ^= key[j]; + } + + for (let i = 1; i < this._cyclesOfRepetition; i++) { + // SubBytes + for (let j = 0; j < 16; ++j) { + state[j] = s[state[j]]; + } + // ShiftRows + v = state[1]; + state[1] = state[5]; + state[5] = state[9]; + state[9] = state[13]; + state[13] = v; + v = state[2]; + u = state[6]; + state[2] = state[10]; + state[6] = state[14]; + state[10] = v; + state[14] = u; + v = state[3]; + u = state[7]; + t = state[11]; + state[3] = state[15]; + state[7] = v; + state[11] = u; + state[15] = t; + // MixColumns + for (let j = 0; j < 16; j += 4) { + const s0 = state[j + 0]; + const s1 = state[j + 1]; + const s2 = state[j + 2]; + const s3 = state[j + 3]; + t = s0 ^ s1 ^ s2 ^ s3; + state[j + 0] ^= t ^ this._mixCol[s0 ^ s1]; + state[j + 1] ^= t ^ this._mixCol[s1 ^ s2]; + state[j + 2] ^= t ^ this._mixCol[s2 ^ s3]; + state[j + 3] ^= t ^ this._mixCol[s3 ^ s0]; + } + // AddRoundKey + for (let j = 0, k = i * 16; j < 16; ++j, ++k) { + state[j] ^= key[k]; + } + } + + // SubBytes + for (let j = 0; j < 16; ++j) { + state[j] = s[state[j]]; + } + // ShiftRows + v = state[1]; + state[1] = state[5]; + state[5] = state[9]; + state[9] = state[13]; + state[13] = v; + v = state[2]; + u = state[6]; + state[2] = state[10]; + state[6] = state[14]; + state[10] = v; + state[14] = u; + v = state[3]; + u = state[7]; + t = state[11]; + state[3] = state[15]; + state[7] = v; + state[11] = u; + state[15] = t; + // AddRoundKey + for (let j = 0, k = this._keySize; j < 16; ++j, ++k) { + state[j] ^= key[k]; + } + return state; + } + + _decryptBlock2(data: Uint8Array, finalize: boolean) { + const sourceLength = data.length; + let buffer = this.buffer, + bufferLength = this.bufferPosition; + const result: Uint8Array[] = []; + let iv = this.iv; + + for (let i = 0; i < sourceLength; ++i) { + buffer[bufferLength] = data[i]; + ++bufferLength; + if (bufferLength < 16) { + continue; + } + // buffer is full, decrypting + const plain = this._decrypt(buffer, this._key); + // xor-ing the IV vector to get plain text + for (let j = 0; j < 16; ++j) { + plain[j] ^= iv[j]; + } + iv = buffer; + result.push(plain); + buffer = new Uint8Array(16); + bufferLength = 0; + } + // saving incomplete buffer + this.buffer = buffer; + this.bufferLength = bufferLength; + this.iv = iv; + if (result.length === 0) { + return new Uint8Array(0); + } + // combining plain text blocks into one + let outputLength = 16 * result.length; + if (finalize) { + // undo a padding that is described in RFC 2898 + const lastBlock = result[result.length - 1]; + let psLen = lastBlock[15]; + if (psLen <= 16) { + for (let i = 15, ii = 16 - psLen; i >= ii; --i) { + if (lastBlock[i] !== psLen) { + // Invalid padding, assume that the block has no padding. + psLen = 0; + break; + } + } + outputLength -= psLen; + result[result.length - 1] = lastBlock.subarray(0, 16 - psLen); + } + } + const output = new Uint8Array(outputLength); + for (let i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) { + output.set(result[i], j); + } + return output; + } + + decryptBlock( + data: Uint8Array, + finalize: boolean, + iv?: Uint8Array, + ): Uint8Array { + const sourceLength = data.length; + const buffer = this.buffer; + let bufferLength = this.bufferPosition; + // If an IV is not supplied, wait for IV values. They are at the start + // of the stream. + if (iv) { + this.iv = iv; + } else { + for ( + let i = 0; + bufferLength < 16 && i < sourceLength; + ++i, ++bufferLength + ) { + buffer[bufferLength] = data[i]; + } + if (bufferLength < 16) { + // Need more data. + this.bufferLength = bufferLength; + return new Uint8Array(0); + } + this.iv = buffer; + data = data.subarray(16); + } + this.buffer = new Uint8Array(16); + this.bufferLength = 0; + // starting decryption + this.decryptBlock = this._decryptBlock2; + return this.decryptBlock(data, finalize); + } + + encrypt(data: Uint8Array, iv: Uint8Array) { + const sourceLength = data.length; + let buffer = this.buffer, + bufferLength = this.bufferPosition; + const result = []; + + if (!iv) { + iv = new Uint8Array(16); + } + for (let i = 0; i < sourceLength; ++i) { + buffer[bufferLength] = data[i]; + ++bufferLength; + if (bufferLength < 16) { + continue; + } + + for (let j = 0; j < 16; ++j) { + buffer[j] ^= iv[j]; + } + + // buffer is full, encrypting + const cipher = this._encrypt(buffer, this._key); + iv = cipher; + result.push(cipher); + buffer = new Uint8Array(16); + bufferLength = 0; + } + // saving incomplete buffer + this.buffer = buffer; + this.bufferLength = bufferLength; + this.iv = iv; + if (result.length === 0) { + return new Uint8Array(0); + } + // combining plain text blocks into one + const outputLength = 16 * result.length; + const output = new Uint8Array(outputLength); + for (let i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) { + output.set(result[i], j); + } + return output; + } +} + +class AES128Cipher extends AESBaseCipher { + private _rcon: Uint8Array; + + constructor(key: Uint8Array) { + super(); + + this._cyclesOfRepetition = 10; + this._keySize = 160; // bits + + this._rcon = new Uint8Array([ + 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, + 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, + 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, + 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, + 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, + 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, + 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, + 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, + 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, + 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, + 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, + 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, + 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, + 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, + 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, + 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, + 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, + 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, + 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, + 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, + 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, + 0x74, 0xe8, 0xcb, 0x8d, + ]); + + this._key = this._expandKey(key); + } + + _expandKey(cipherKey: Uint8Array) { + const b = 176; + const s = this._s; + const rcon = this._rcon; + + const result = new Uint8Array(b); + result.set(cipherKey); + + for (let j = 16, i = 1; j < b; ++i) { + // RotWord + let t1 = result[j - 3]; + let t2 = result[j - 2]; + let t3 = result[j - 1]; + let t4 = result[j - 4]; + // SubWord + t1 = s[t1]; + t2 = s[t2]; + t3 = s[t3]; + t4 = s[t4]; + // Rcon + t1 ^= rcon[i]; + for (let n = 0; n < 4; ++n) { + result[j] = t1 ^= result[j - 16]; + j++; + result[j] = t2 ^= result[j - 16]; + j++; + result[j] = t3 ^= result[j - 16]; + j++; + result[j] = t4 ^= result[j - 16]; + j++; + } + } + return result; + } +} + +class AES256Cipher extends AESBaseCipher { + constructor(key: Uint8Array) { + super(); + + this._cyclesOfRepetition = 14; + this._keySize = 224; // bits + + this._key = this._expandKey(key); + } + + _expandKey(cipherKey: Uint8Array) { + const b = 240; + const s = this._s; + + const result = new Uint8Array(b); + result.set(cipherKey); + + let r = 1; + let t1 = 0, + t2 = 0, + t3 = 0, + t4 = 0; + for (let j = 32, i = 1; j < b; ++i) { + if (j % 32 === 16) { + t1 = s[t1]; + t2 = s[t2]; + t3 = s[t3]; + t4 = s[t4]; + } else if (j % 32 === 0) { + // RotWord + t1 = result[j - 3]; + t2 = result[j - 2]; + t3 = result[j - 1]; + t4 = result[j - 4]; + // SubWord + t1 = s[t1]; + t2 = s[t2]; + t3 = s[t3]; + t4 = s[t4]; + // Rcon + t1 ^= r; + if ((r <<= 1) >= 256) { + r = (r ^ 0x1b) & 0xff; + } + } + + for (let n = 0; n < 4; ++n) { + result[j] = t1 ^= result[j - 32]; + j++; + result[j] = t2 ^= result[j - 32]; + j++; + result[j] = t3 ^= result[j - 32]; + j++; + result[j] = t4 ^= result[j - 32]; + j++; + } + } + return result; + } +} + +class PDF17 { + checkOwnerPassword( + password: Uint8Array, + ownerValidationSalt: Uint8Array, + userBytes: Uint8Array, + ownerPassword: Uint8Array, + ) { + const hashData = new Uint8Array(password.length + 56); + hashData.set(password, 0); + hashData.set(ownerValidationSalt, password.length); + hashData.set(userBytes, password.length + ownerValidationSalt.length); + const result = calculateSHA256(hashData, 0, hashData.length); + return isArrayEqual(result, ownerPassword); + } + + checkUserPassword( + password: Uint8Array, + userValidationSalt: Uint8Array, + userPassword: Uint8Array, + ) { + const hashData = new Uint8Array(password.length + 8); + hashData.set(password, 0); + hashData.set(userValidationSalt, password.length); + const result = calculateSHA256(hashData, 0, hashData.length); + return isArrayEqual(result, userPassword); + } + + getOwnerKey( + password: Uint8Array, + ownerKeySalt: Uint8Array, + userBytes: Uint8Array, + ownerEncryption: Uint8Array, + ) { + const hashData = new Uint8Array(password.length + 56); + hashData.set(password, 0); + hashData.set(ownerKeySalt, password.length); + hashData.set(userBytes, password.length + ownerKeySalt.length); + const key = calculateSHA256(hashData, 0, hashData.length); + const cipher = new AES256Cipher(key); + return cipher.decryptBlock(ownerEncryption, false, new Uint8Array(16)); + } + + getUserKey( + password: Uint8Array, + userKeySalt: Uint8Array, + userEncryption: Uint8Array, + ) { + const hashData = new Uint8Array(password.length + 8); + hashData.set(password, 0); + hashData.set(userKeySalt, password.length); + // `key` is the decryption key for the UE string. + const key = calculateSHA256(hashData, 0, hashData.length); + const cipher = new AES256Cipher(key); + return cipher.decryptBlock(userEncryption, false, new Uint8Array(16)); + } +} + +class PDF20 { + calculatePDF20Hash( + password: Uint8Array, + input: Uint8Array, + userBytes: Uint8Array, + ) { + // This refers to Algorithm 2.B as defined in ISO 32000-2. + let k = calculateSHA256(input, 0, input.length).subarray(0, 32); + let e: Uint8Array = new Uint8Array([0]); + let i = 0; + while (i < 64 || e[e.length - 1] > i - 32) { + const combinedLength = password.length + k.length + userBytes.length, + combinedArray = new Uint8Array(combinedLength); + let writeOffset = 0; + combinedArray.set(password, writeOffset); + writeOffset += password.length; + combinedArray.set(k, writeOffset); + writeOffset += k.length; + combinedArray.set(userBytes, writeOffset); + + const k1 = new Uint8Array(combinedLength * 64); + for (let j = 0, pos = 0; j < 64; j++, pos += combinedLength) { + k1.set(combinedArray, pos); + } + // AES128 CBC NO PADDING with first 16 bytes of k as the key + // and the second 16 as the iv. + const cipher = new AES128Cipher(k.subarray(0, 16)); + e = cipher.encrypt(k1, k.subarray(16, 32)); + // Now we have to take the first 16 bytes of an unsigned big endian + // integer and compute the remainder modulo 3. That is a fairly large + // number and JavaScript isn't going to handle that well. + // The number is e0 + 256 * e1 + 256^2 * e2... and 256 % 3 === 1, hence + // the powers of 256 are === 1 modulo 3 and finally the number modulo 3 + // is equal to the remainder modulo 3 of the sum of the e_n. + const remainder = e.slice(0, 16).reduce((a, b) => a + b, 0) % 3; + if (remainder === 0) { + k = calculateSHA256(e, 0, e.length); + } else if (remainder === 1) { + k = calculateSHA384(e, 0, e.length); + } else if (remainder === 2) { + k = calculateSHA512(e, 0, e.length); + } + i++; + } + return k.subarray(0, 32); + } + + hash(password: Uint8Array, concatBytes: Uint8Array, userBytes: Uint8Array) { + return this.calculatePDF20Hash(password, concatBytes, userBytes); + } + + checkOwnerPassword( + password: Uint8Array, + ownerValidationSalt: Uint8Array, + userBytes: Uint8Array, + ownerPassword: Uint8Array, + ) { + const hashData = new Uint8Array(password.length + 56); + hashData.set(password, 0); + hashData.set(ownerValidationSalt, password.length); + hashData.set(userBytes, password.length + ownerValidationSalt.length); + const result = this.calculatePDF20Hash(password, hashData, userBytes); + return isArrayEqual(result, ownerPassword); + } + + checkUserPassword( + password: Uint8Array, + userValidationSalt: Uint8Array, + userPassword: Uint8Array, + ) { + const hashData = new Uint8Array(password.length + 8); + hashData.set(password, 0); + hashData.set(userValidationSalt, password.length); + const result = this.calculatePDF20Hash( + password, + hashData, + new Uint8Array(), + ); + return isArrayEqual(result, userPassword); + } + + getOwnerKey( + password: Uint8Array, + ownerKeySalt: Uint8Array, + userBytes: Uint8Array, + ownerEncryption: Uint8Array, + ) { + const hashData = new Uint8Array(password.length + 56); + hashData.set(password, 0); + hashData.set(ownerKeySalt, password.length); + hashData.set(userBytes, password.length + ownerKeySalt.length); + const key = this.calculatePDF20Hash(password, hashData, userBytes); + const cipher = new AES256Cipher(key); + return cipher.decryptBlock(ownerEncryption, false, new Uint8Array(16)); + } + + getUserKey( + password: Uint8Array, + userKeySalt: Uint8Array, + userEncryption: Uint8Array, + ) { + const hashData = new Uint8Array(password.length + 8); + hashData.set(password, 0); + hashData.set(userKeySalt, password.length); + // `key` is the decryption key for the UE string. + const key = this.calculatePDF20Hash(password, hashData, new Uint8Array()); + const cipher = new AES256Cipher(key); + return cipher.decryptBlock(userEncryption, false, new Uint8Array(16)); + } +} + +type Cipher = ARCFourCipher | NullCipher | AES128Cipher | AES256Cipher; +class CipherTransform { + private StringCipherConstructor: () => Cipher; + private StreamCipherConstructor: () => Cipher; + + constructor( + stringCipherConstructor: () => Cipher, + streamCipherConstructor: () => Cipher, + ) { + this.StringCipherConstructor = stringCipherConstructor; + this.StreamCipherConstructor = streamCipherConstructor; + } + + createStream(stream: StreamType, length: number) { + const cipher = this.StreamCipherConstructor(); + return new DecryptStream( + stream, + function cipherTransformDecryptStream(data, finalize) { + return cipher.decryptBlock(data as Uint8Array, finalize); + }, + length, + ); + } + + decryptString(s: string) { + const cipher = this.StringCipherConstructor(); + let data = stringAsByteArray(s); + data = cipher.decryptBlock(data, true); + return arrayAsString(data); + } + + decryptBytes(d: Uint8Array) { + const cipher = this.StringCipherConstructor(); + return cipher.decryptBlock(d, true); + } + + encryptString(s: string) { + const cipher = this.StringCipherConstructor(); + if (isPDFInstance(cipher, PDFClasses.AESBaseCipher)) { + // Append some chars equal to "16 - (M mod 16)" + // where M is the string length (see section 7.6.2 in PDF specification) + // to have a final string where the length is a multiple of 16. + // Special note: + // "Note that the pad is present when M is evenly divisible by 16; + // it contains 16 bytes of 0x10." + const strLen = s.length; + const pad = 16 - (strLen % 16); + s += String.fromCharCode(pad).repeat(pad); + + // Generate an initialization vector + const iv = new Uint8Array(16); + if (typeof crypto !== 'undefined') { + crypto.getRandomValues(iv); + } else { + for (let i = 0; i < 16; i++) { + iv[i] = Math.floor(256 * Math.random()); + } + } + + let data = stringAsByteArray(s); + data = cipher.encrypt(data, iv); + + const buf = new Uint8Array(16 + data.length); + buf.set(iv); + buf.set(data, 16); + + return arrayAsString(buf); + } + + let data = stringAsByteArray(s); + data = (cipher as NullCipher).encrypt(data); + return arrayAsString(data); + } +} + +// eslint-disable-next-line no-shadow +class CipherTransformFactory { + encryptMetadata: boolean; + encryptionKey: Uint8Array; + algorithm: number; + filterName: string; + dict: PDFDict; + cf!: PDFDict; + stmf!: PDFName; + strf!: PDFName; + eff!: PDFName; + + private defaultPasswordBytes = new Uint8Array([ + 0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, 0x64, 0x00, 0x4e, 0x56, + 0xff, 0xfa, 0x01, 0x08, 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80, + 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a, + ]); + private identityName = PDFName.of('Identity'); + + constructor(dict: PDFDict, fileIdBytes: Uint8Array, password?: string) { + const filter = dict.get(PDFName.of('Filter')) as PDFName; + if (filter.asString() !== '/Standard') { + throw new Error('unknown encryption method'); + } + this.filterName = filter.asString(); + this.dict = dict; + const algorithm = (dict.get(PDFName.of('V')) as PDFNumber).asNumber(); + if ( + !Number.isInteger(algorithm) || + (algorithm !== 1 && algorithm !== 2 && algorithm !== 4 && algorithm !== 5) + ) { + throw new Error('unsupported encryption algorithm'); + } + this.algorithm = algorithm; + let keyLength = ( + dict.get(PDFName.of('Length')) as PDFNumber | undefined + )?.asNumber(); + if (!keyLength) { + // Spec asks to rely on encryption dictionary's Length entry, however + // some PDFs don't have it. Trying to recover. + if (algorithm <= 3) { + // For 1 and 2 it's fixed to 40-bit, for 3 40-bit is a minimal value. + keyLength = 40; + } else { + // Trying to find default handler -- it usually has Length. + const cfDict = dict.get(PDFName.of('CF')) as PDFDict; + const streamCryptoName = dict.get(PDFName.of('StmF')) as PDFName; + if ( + isPDFInstance(cfDict, PDFClasses.PDFDict) && + isPDFInstance(streamCryptoName, PDFClasses.PDFName) + ) { + cfDict.suppressEncryption = true; + const handlerDict = cfDict.get( + PDFName.of(streamCryptoName.asString()), + ) as PDFDict; + let keyLen: PDFNumber | null = null; + if (handlerDict) { + keyLen = handlerDict.get(PDFName.of('Length')) as PDFNumber; + } + keyLength = (keyLen && keyLen.asNumber()) || 128; + if (keyLength < 40) { + // Sometimes it's incorrect value of bits, generators specify + // bytes. + keyLength <<= 3; + } + } + } + } + if ( + keyLength === undefined || + !Number.isInteger(keyLength) || + keyLength < 40 || + keyLength % 8 !== 0 + ) { + throw new Error(`invalid key length: ${keyLength}`); + } + + const oPdfStr = (dict.get(PDFName.of('O')) as PDFString).asBytes(); + const uPdfStr = (dict.get(PDFName.of('U')) as PDFString).asBytes(); + // prepare keys + const ownerPassword = oPdfStr.subarray(0, 32); + const userPassword = uPdfStr.subarray(0, 32); + const flags = (dict.get(PDFName.of('P')) as PDFNumber).asNumber(); + const revision = (dict.get(PDFName.of('R')) as PDFNumber).asNumber(); + // meaningful when V is 4 or 5 + const encryptMetadata = + (algorithm === 4 || algorithm === 5) && + (dict.get(PDFName.of('EncryptMetadata')) as PDFBool)?.asBoolean() !== + false; + this.encryptMetadata = encryptMetadata; + + let passwordBytes: Uint8Array | undefined; + if (password) { + if (revision === 6) { + try { + password = unescape(encodeURIComponent(password)); + } catch (ex) { + console.warn( + 'CipherTransformFactory: ' + + 'Unable to convert UTF8 encoded password.', + ); + } + } + passwordBytes = stringAsByteArray(password!); + } + + let encryptionKey; + if (algorithm !== 5) { + encryptionKey = this.prepareKeyData( + fileIdBytes, + passwordBytes, + ownerPassword, + userPassword, + flags, + revision, + keyLength, + encryptMetadata, + ); + } else { + const ownerValidationSalt = oPdfStr.subarray(32, 40); + const ownerKeySalt = oPdfStr.subarray(40, 48); + const uBytes = uPdfStr.subarray(0, 48); + const userValidationSalt = uPdfStr.subarray(32, 40); + const userKeySalt = uPdfStr.subarray(40, 48); + + const ownerEncryption = ( + dict.get(PDFName.of('OE')) as PDFString + ).asBytes(); + const userEncryption = ( + dict.get(PDFName.of('UE')) as PDFString + ).asBytes(); + const perms = (dict.get(PDFName.of('Perms')) as PDFString).asBytes(); + encryptionKey = this.createEncryptionKey20( + revision, + passwordBytes, + ownerPassword, + ownerValidationSalt, + ownerKeySalt, + uBytes, + userPassword, + userValidationSalt, + userKeySalt, + ownerEncryption, + userEncryption, + perms, + ); + } + if (!encryptionKey && !password) { + throw new Error('NEEDS PASSWORD'); + } else if (!encryptionKey && password) { + // Attempting use the password as an owner password + const decodedPassword = this.decodeUserPassword( + passwordBytes!, + ownerPassword, + revision, + keyLength, + ); + encryptionKey = this.prepareKeyData( + fileIdBytes, + decodedPassword, + ownerPassword, + userPassword, + flags, + revision, + keyLength, + encryptMetadata, + ); + } + + if (!encryptionKey) { + throw new Error('Password incorrect'); + } + + this.encryptionKey = encryptionKey; + + if (algorithm >= 4) { + const cf = dict.get(PDFName.of('CF')) as PDFDict; + if (isPDFInstance(cf, PDFClasses.PDFDict)) { + // The 'CF' dictionary itself should not be encrypted, and by setting + // `suppressEncryption` we can prevent an infinite loop inside of + // `XRef_fetchUncompressed` if the dictionary contains indirect + // objects (fixes issue7665.pdf). + cf.suppressEncryption = true; + } + this.cf = cf; + this.stmf = + (dict.get(PDFName.of('StmF')) as PDFName) || this.identityName; + this.strf = + (dict.get(PDFName.of('StrF')) as PDFName) || this.identityName; + this.eff = (dict.get(PDFName.of('EFF')) as PDFName) || this.stmf; + } + } + + createCipherTransform(num: number, gen: number) { + if (this.algorithm === 4 || this.algorithm === 5) { + return new CipherTransform( + this.buildCipherConstructor( + this.cf, + this.strf, + num, + gen, + this.encryptionKey, + ), + this.buildCipherConstructor( + this.cf, + this.stmf, + num, + gen, + this.encryptionKey, + ), + ); + } + // algorithms 1 and 2 + const key = this.buildObjectKey( + num, + gen, + this.encryptionKey, + /* isAes = */ false, + ); + const cipherConstructor = function buildCipherCipherConstructor() { + return new ARCFourCipher(key); + }; + return new CipherTransform(cipherConstructor, cipherConstructor); + } + + createEncryptionKey20( + revision: number, + password: Uint8Array | undefined, + ownerPassword: Uint8Array, + ownerValidationSalt: Uint8Array, + ownerKeySalt: Uint8Array, + uBytes: Uint8Array, + userPassword: Uint8Array, + userValidationSalt: Uint8Array, + userKeySalt: Uint8Array, + ownerEncryption: Uint8Array, + userEncryption: Uint8Array, + _perms: Uint8Array, + ) { + if (password) { + const passwordLength = Math.min(127, password.length); + password = password.subarray(0, passwordLength); + } else { + password = new Uint8Array(); + } + let pdfAlgorithm; + if (revision === 6) { + pdfAlgorithm = new PDF20(); + } else { + pdfAlgorithm = new PDF17(); + } + + if ( + pdfAlgorithm.checkUserPassword(password, userValidationSalt, userPassword) + ) { + return pdfAlgorithm.getUserKey(password, userKeySalt, userEncryption); + } else if ( + password.length && + pdfAlgorithm.checkOwnerPassword( + password, + ownerValidationSalt, + uBytes, + ownerPassword, + ) + ) { + return pdfAlgorithm.getOwnerKey( + password, + ownerKeySalt, + uBytes, + ownerEncryption, + ); + } + + return null; + } + + prepareKeyData( + fileId: Uint8Array, + password: Uint8Array | undefined, + ownerPassword: Uint8Array, + userPassword: Uint8Array, + flags: number, + revision: number, + keyLength: number, + encryptMetadata: boolean, + ) { + const hashDataSize = 40 + ownerPassword.length + fileId.length; + const hashData = new Uint8Array(hashDataSize); + let i = 0, + j, + n; + if (password) { + n = Math.min(32, password.length); + for (; i < n; ++i) { + hashData[i] = password[i]; + } + } + j = 0; + while (i < 32) { + hashData[i++] = this.defaultPasswordBytes[j++]; + } + // as now the padded password in the hashData[0..i] + for (j = 0, n = ownerPassword.length; j < n; ++j) { + hashData[i++] = ownerPassword[j]; + } + hashData[i++] = flags & 0xff; + hashData[i++] = (flags >> 8) & 0xff; + hashData[i++] = (flags >> 16) & 0xff; + hashData[i++] = (flags >>> 24) & 0xff; + for (j = 0, n = fileId.length; j < n; ++j) { + hashData[i++] = fileId[j]; + } + if (revision >= 4 && !encryptMetadata) { + hashData[i++] = 0xff; + hashData[i++] = 0xff; + hashData[i++] = 0xff; + hashData[i++] = 0xff; + } + let hash = calculateMD5(hashData, 0, i); + const keyLengthInBytes = keyLength >> 3; + if (revision >= 3) { + for (j = 0; j < 50; ++j) { + hash = calculateMD5(hash, 0, keyLengthInBytes); + } + } + const encryptionKey = hash.subarray(0, keyLengthInBytes); + let cipher, checkData; + + if (revision >= 3) { + for (i = 0; i < 32; ++i) { + hashData[i] = this.defaultPasswordBytes[i]; + } + for (j = 0, n = fileId.length; j < n; ++j) { + hashData[i++] = fileId[j]; + } + cipher = new ARCFourCipher(encryptionKey); + checkData = cipher.encryptBlock(calculateMD5(hashData, 0, i)); + n = encryptionKey.length; + const derivedKey = new Uint8Array(n); + for (j = 1; j <= 19; ++j) { + for (let k = 0; k < n; ++k) { + derivedKey[k] = encryptionKey[k] ^ j; + } + cipher = new ARCFourCipher(derivedKey); + checkData = cipher.encryptBlock(checkData); + } + for (j = 0, n = checkData.length; j < n; ++j) { + if (userPassword[j] !== checkData[j]) { + return null; + } + } + } else { + cipher = new ARCFourCipher(encryptionKey); + checkData = cipher.encryptBlock(this.defaultPasswordBytes); + for (j = 0, n = checkData.length; j < n; ++j) { + if (userPassword[j] !== checkData[j]) { + return null; + } + } + } + return encryptionKey; + } + + decodeUserPassword( + password: Uint8Array, + ownerPassword: Uint8Array, + revision: number, + keyLength: number, + ) { + const hashData = new Uint8Array(32); + let i = 0; + const n = Math.min(32, password.length); + for (; i < n; ++i) { + hashData[i] = password[i]; + } + let j = 0; + while (i < 32) { + hashData[i++] = this.defaultPasswordBytes[j++]; + } + let hash = calculateMD5(hashData, 0, i); + const keyLengthInBytes = keyLength >> 3; + if (revision >= 3) { + for (j = 0; j < 50; ++j) { + hash = calculateMD5(hash, 0, hash.length); + } + } + + let cipher, userPassword; + if (revision >= 3) { + userPassword = ownerPassword; + const derivedKey = new Uint8Array(keyLengthInBytes); + for (j = 19; j >= 0; j--) { + for (let k = 0; k < keyLengthInBytes; ++k) { + derivedKey[k] = hash[k] ^ j; + } + cipher = new ARCFourCipher(derivedKey); + userPassword = cipher.encryptBlock(userPassword); + } + } else { + cipher = new ARCFourCipher(hash.subarray(0, keyLengthInBytes)); + userPassword = cipher.encryptBlock(ownerPassword); + } + return userPassword; + } + + buildObjectKey( + num: number, + gen: number, + encryptionKey: Uint8Array, + isAes: boolean = false, + ) { + const key = new Uint8Array(encryptionKey.length + 9); + const n = encryptionKey.length; + let i; + for (i = 0; i < n; ++i) { + key[i] = encryptionKey[i]; + } + key[i++] = num & 0xff; + key[i++] = (num >> 8) & 0xff; + key[i++] = (num >> 16) & 0xff; + key[i++] = gen & 0xff; + key[i++] = (gen >> 8) & 0xff; + if (isAes) { + key[i++] = 0x73; + key[i++] = 0x41; + key[i++] = 0x6c; + key[i++] = 0x54; + } + const hash = calculateMD5(key, 0, i); + return hash.subarray(0, Math.min(encryptionKey.length + 5, 16)); + } + + buildCipherConstructor( + cf: PDFDict, + name: PDFName, + num: number, + gen: number, + key: Uint8Array, + ) { + if (!isPDFInstance(name, PDFClasses.PDFName)) { + throw new Error('Invalid crypt filter name.'); + } + const cryptFilter = cf.get( + PDFName.of(name.asString().replace('/', '')), + ) as PDFDict; + let cfm; + if (cryptFilter !== null && cryptFilter !== undefined) { + cfm = cryptFilter.get(PDFName.of('CFM')) as PDFName; + } + if (!cfm || cfm.asString() === '/None') { + return function cipherTransformFactoryBuildCipherConstructorNone() { + return new NullCipher(); + }; + } + if (cfm.asString() === '/V2') { + return () => + new ARCFourCipher( + this.buildObjectKey(num, gen, key, /* isAes = */ false), + ); + } + if (cfm.asString() === '/AESV2') { + return () => + new AES128Cipher( + this.buildObjectKey(num, gen, key, /* isAes = */ true), + ); + } + if (cfm.asString() === '/AESV3') { + return () => new AES256Cipher(key); + } + throw new Error('Unknown crypto method'); + } +} + +export { + AES128Cipher, + AES256Cipher, + ARCFourCipher, + calculateMD5, + calculateSHA256, + calculateSHA384, + calculateSHA512, + CipherTransformFactory, + CipherTransform, + PDF17, + PDF20, +}; diff --git a/src/core/document/PDFCrossRefSection.ts b/src/core/document/PDFCrossRefSection.ts index 13bbab1ef..4990b45bb 100644 --- a/src/core/document/PDFCrossRefSection.ts +++ b/src/core/document/PDFCrossRefSection.ts @@ -1,6 +1,6 @@ -import PDFRef from 'src/core/objects/PDFRef'; -import CharCodes from 'src/core/syntax/CharCodes'; -import { copyStringIntoBuffer, padStart } from 'src/utils'; +import PDFRef from '../objects/PDFRef'; +import CharCodes from '../syntax/CharCodes'; +import { copyStringIntoBuffer, padStart } from '../../utils'; export interface Entry { ref: PDFRef; @@ -10,7 +10,7 @@ export interface Entry { /** * Entries should be added using the [[addEntry]] and [[addDeletedEntry]] - * methods **in order of ascending object number**. + * methods. */ class PDFCrossRefSection { static create = () => @@ -37,11 +37,27 @@ class PDFCrossRefSection { } addDeletedEntry(ref: PDFRef, nextFreeObjectNumber: number): void { + // fix the first entry if required + if (!this.subsections.length) { + this.subsections = [ + [ + { + ref: PDFRef.of(0, 65535), + offset: ref.objectNumber, + deleted: true, + }, + ], + ]; + this.chunkIdx = 0; + this.chunkLength = 1; + } else if (!this.subsections[0][0].offset) { + this.subsections[0][0].offset = ref.objectNumber; + } this.append({ ref, offset: nextFreeObjectNumber, deleted: true }); } toString(): string { - let section = `xref\n`; + let section = 'xref\n'; for ( let rangeIdx = 0, rangeLen = this.subsections.length; @@ -159,7 +175,35 @@ class PDFCrossRefSection { const chunk = this.subsections[this.chunkIdx]; const prevEntry = chunk[this.chunkLength - 1]; - if (currEntry.ref.objectNumber - prevEntry.ref.objectNumber > 1) { + if (currEntry.ref.objectNumber - prevEntry.ref.objectNumber !== 1) { + // the current chunk is not the right chunk, find the right one, or create a new one + for (let c = 0; c < this.subsections.length; c++) { + const first = this.subsections[c][0]; + const last = this.subsections[c][this.subsections[c].length - 1]; + if (first.ref.objectNumber > currEntry.ref.objectNumber) { + // goes before this subsection, or at the start of it + if (first.ref.objectNumber - currEntry.ref.objectNumber === 1) { + // first element of subsection + this.subsections[c].unshift(currEntry); + if (c === this.chunkIdx) this.chunkLength += 1; + return; + } else { + // create subsection + this.subsections.splice(c, 0, [currEntry]); + this.chunkIdx++; + return; + } + } else if (last.ref.objectNumber > currEntry.ref.objectNumber) { + // goes in this subsection, find its place.. + const cep = this.subsections[c].findIndex( + (ee) => ee.ref.objectNumber > currEntry.ref.objectNumber, + ); + this.subsections[c].splice(cep, 0, currEntry); + if (c === this.chunkIdx) this.chunkLength += 1; + } + // bigger, keep looking + } + // if got to here, then a new subsection is required this.subsections.push([currEntry]); this.chunkIdx += 1; this.chunkLength = 1; @@ -168,6 +212,30 @@ class PDFCrossRefSection { this.chunkLength += 1; } } + + /** + * Returns all the entries in the XREF section, except the first one (object == 0) + * @returns {Entry[]} All the entries in the XREF section + */ + listRefs(): Entry[] { + const refList: Entry[] = []; + for ( + let rangeIdx = 0, rangeLen = this.subsections.length; + rangeIdx < rangeLen; + rangeIdx++ + ) { + const range = this.subsections[rangeIdx]; + for ( + let entryIdx = 0, entryLen = range.length; + entryIdx < entryLen; + entryIdx++ + ) { + const entry = range[entryIdx]; + if (entry.ref.objectNumber) refList.push(entry); + } + } + return refList; + } } export default PDFCrossRefSection; diff --git a/src/core/document/PDFHeader.ts b/src/core/document/PDFHeader.ts index 0ef16e73a..6c686380d 100644 --- a/src/core/document/PDFHeader.ts +++ b/src/core/document/PDFHeader.ts @@ -1,5 +1,5 @@ -import CharCodes from 'src/core/syntax/CharCodes'; -import { charFromCode, copyStringIntoBuffer } from 'src/utils'; +import CharCodes from '../syntax/CharCodes'; +import { charFromCode, copyStringIntoBuffer } from '../../utils'; class PDFHeader { static forVersion = (major: number, minor: number) => @@ -13,6 +13,10 @@ class PDFHeader { this.minor = String(minor); } + getVersionString(): string { + return `${this.major}.${this.minor}`; + } + toString(): string { const bc = charFromCode(129); return `%PDF-${this.major}.${this.minor}\n%${bc}${bc}${bc}${bc}`; diff --git a/src/core/document/PDFTrailer.ts b/src/core/document/PDFTrailer.ts index c4292da9e..d6fa5f911 100644 --- a/src/core/document/PDFTrailer.ts +++ b/src/core/document/PDFTrailer.ts @@ -1,5 +1,5 @@ -import CharCodes from 'src/core/syntax/CharCodes'; -import { copyStringIntoBuffer } from 'src/utils'; +import CharCodes from '../syntax/CharCodes'; +import { copyStringIntoBuffer } from '../../utils'; class PDFTrailer { static forLastCrossRefSectionOffset = (offset: number) => diff --git a/src/core/document/PDFTrailerDict.ts b/src/core/document/PDFTrailerDict.ts index 80dcae985..b0521a54f 100644 --- a/src/core/document/PDFTrailerDict.ts +++ b/src/core/document/PDFTrailerDict.ts @@ -1,5 +1,5 @@ -import PDFDict from 'src/core/objects/PDFDict'; -import CharCodes from 'src/core/syntax/CharCodes'; +import PDFDict from '../objects/PDFDict'; +import CharCodes from '../syntax/CharCodes'; class PDFTrailerDict { static of = (dict: PDFDict) => new PDFTrailerDict(dict); diff --git a/src/core/embedders/CMap.ts b/src/core/embedders/CMap.ts index e59acf301..d1ce803e6 100644 --- a/src/core/embedders/CMap.ts +++ b/src/core/embedders/CMap.ts @@ -1,12 +1,12 @@ -import { Glyph } from 'src/types/fontkit'; +import { Glyph } from '../../types/fontkit'; -import { toHexString, toHexStringOfMinLength } from 'src/utils'; +import { toHexString, toHexStringOfMinLength } from '../../utils'; import { hasSurrogates, highSurrogate, isWithinBMP, lowSurrogate, -} from 'src/utils/unicode'; +} from '../../utils/unicode'; /** [fontId, codePoint] */ type BfChar = [string, string]; diff --git a/src/core/embedders/CustomFontEmbedder.ts b/src/core/embedders/CustomFontEmbedder.ts index f8d215a6f..d6e3d95e3 100644 --- a/src/core/embedders/CustomFontEmbedder.ts +++ b/src/core/embedders/CustomFontEmbedder.ts @@ -1,17 +1,17 @@ -import { Font, Fontkit, Glyph, TypeFeatures } from 'src/types/fontkit'; - -import { createCmap } from 'src/core/embedders/CMap'; -import { deriveFontFlags } from 'src/core/embedders/FontFlags'; -import PDFHexString from 'src/core/objects/PDFHexString'; -import PDFRef from 'src/core/objects/PDFRef'; -import PDFString from 'src/core/objects/PDFString'; -import PDFContext from 'src/core/PDFContext'; +import { Font, Fontkit, Glyph, TypeFeatures } from '../../types/fontkit'; + +import { createCmap } from './CMap'; +import { deriveFontFlags } from './FontFlags'; +import PDFHexString from '../objects/PDFHexString'; +import PDFRef from '../objects/PDFRef'; +import PDFString from '../objects/PDFString'; +import PDFContext from '../PDFContext'; import { byAscendingId, Cache, sortedUniq, toHexStringOfMinLength, -} from 'src/utils'; +} from '../../utils'; /** * A note of thanks to the developers of https://github.com/foliojs/pdfkit, as diff --git a/src/core/embedders/CustomFontSubsetEmbedder.ts b/src/core/embedders/CustomFontSubsetEmbedder.ts index bf80b1cf3..20f436ad4 100644 --- a/src/core/embedders/CustomFontSubsetEmbedder.ts +++ b/src/core/embedders/CustomFontSubsetEmbedder.ts @@ -1,8 +1,14 @@ -import { Font, Fontkit, Glyph, Subset, TypeFeatures } from 'src/types/fontkit'; +import { + Font, + Fontkit, + Glyph, + Subset, + TypeFeatures, +} from '../../types/fontkit'; -import CustomFontEmbedder from 'src/core/embedders/CustomFontEmbedder'; -import PDFHexString from 'src/core/objects/PDFHexString'; -import { Cache, mergeUint8Arrays, toHexStringOfMinLength } from 'src/utils'; +import CustomFontEmbedder from './CustomFontEmbedder'; +import PDFHexString from '../objects/PDFHexString'; +import { Cache, mergeUint8Arrays, toHexStringOfMinLength } from '../../utils'; /** * A note of thanks to the developers of https://github.com/foliojs/pdfkit, as diff --git a/src/core/embedders/FileEmbedder.ts b/src/core/embedders/FileEmbedder.ts index 059d5d89d..c0cbde7d8 100644 --- a/src/core/embedders/FileEmbedder.ts +++ b/src/core/embedders/FileEmbedder.ts @@ -1,7 +1,7 @@ -import PDFString from 'src/core/objects/PDFString'; -import PDFHexString from 'src/core/objects/PDFHexString'; -import PDFContext from 'src/core/PDFContext'; -import PDFRef from 'src/core/objects/PDFRef'; +import PDFString from '../objects/PDFString'; +import PDFHexString from '../objects/PDFHexString'; +import PDFContext from '../PDFContext'; +import PDFRef from '../objects/PDFRef'; /** * From the PDF-A3 specification, section **3.1. Requirements - General**. @@ -90,6 +90,10 @@ class FileEmbedder { return context.register(fileSpecDict); } } + + getFileData() { + return this.fileData; + } } export default FileEmbedder; diff --git a/src/core/embedders/FontFlags.ts b/src/core/embedders/FontFlags.ts index 57e0bc6d0..35763ef9a 100644 --- a/src/core/embedders/FontFlags.ts +++ b/src/core/embedders/FontFlags.ts @@ -1,4 +1,4 @@ -import { Font } from 'src/types/fontkit'; +import { Font } from '../../types/fontkit'; export interface FontFlagOptions { fixedPitch?: boolean; diff --git a/src/core/embedders/JavaScriptEmbedder.ts b/src/core/embedders/JavaScriptEmbedder.ts index b054601c5..9b53d9c84 100644 --- a/src/core/embedders/JavaScriptEmbedder.ts +++ b/src/core/embedders/JavaScriptEmbedder.ts @@ -1,6 +1,6 @@ -import PDFHexString from 'src/core/objects/PDFHexString'; -import PDFContext from 'src/core/PDFContext'; -import PDFRef from 'src/core/objects/PDFRef'; +import PDFHexString from '../objects/PDFHexString'; +import PDFContext from '../PDFContext'; +import PDFRef from '../objects/PDFRef'; class JavaScriptEmbedder { static for(script: string, scriptName: string) { diff --git a/src/core/embedders/JpegEmbedder.ts b/src/core/embedders/JpegEmbedder.ts index 94e6dc490..5af106490 100644 --- a/src/core/embedders/JpegEmbedder.ts +++ b/src/core/embedders/JpegEmbedder.ts @@ -1,5 +1,5 @@ -import PDFRef from 'src/core/objects/PDFRef'; -import PDFContext from 'src/core/PDFContext'; +import PDFRef from '../objects/PDFRef'; +import PDFContext from '../PDFContext'; // prettier-ignore const MARKERS = [ @@ -29,7 +29,11 @@ const ChannelToColorSpace: { [idx: number]: ColorSpace | undefined } = { */ class JpegEmbedder { static async for(imageData: Uint8Array) { - const dataView = new DataView(imageData.buffer); + const dataView = new DataView( + imageData.buffer, + imageData.byteOffset, + imageData.byteLength, + ); const soi = dataView.getUint16(0); if (soi !== 0xffd8) throw new Error('SOI not found in JPEG'); diff --git a/src/core/embedders/PDFPageEmbedder.ts b/src/core/embedders/PDFPageEmbedder.ts index 069cb35b2..686e99056 100644 --- a/src/core/embedders/PDFPageEmbedder.ts +++ b/src/core/embedders/PDFPageEmbedder.ts @@ -1,19 +1,20 @@ import { MissingPageContentsEmbeddingError, UnrecognizedStreamTypeError, -} from 'src/core/errors'; -import PDFArray from 'src/core/objects/PDFArray'; -import PDFNumber from 'src/core/objects/PDFNumber'; -import PDFRawStream from 'src/core/objects/PDFRawStream'; -import PDFRef from 'src/core/objects/PDFRef'; -import PDFStream from 'src/core/objects/PDFStream'; -import PDFContext from 'src/core/PDFContext'; -import { decodePDFRawStream } from 'src/core/streams/decode'; -import PDFContentStream from 'src/core/structures/PDFContentStream'; -import PDFPageLeaf from 'src/core/structures/PDFPageLeaf'; -import CharCodes from 'src/core/syntax/CharCodes'; -import { TransformationMatrix } from 'src/types/matrix'; -import { mergeIntoTypedArray } from 'src/utils'; +} from '../errors'; +import PDFArray from '../objects/PDFArray'; +import PDFNumber from '../objects/PDFNumber'; +import PDFRawStream from '../objects/PDFRawStream'; +import PDFRef from '../objects/PDFRef'; +import PDFStream from '../objects/PDFStream'; +import PDFContext from '../PDFContext'; +import { decodePDFRawStream } from '../streams/decode'; +import PDFContentStream from '../structures/PDFContentStream'; +import PDFPageLeaf from '../structures/PDFPageLeaf'; +import CharCodes from '../syntax/CharCodes'; +import { TransformationMatrix } from '../../types/matrix'; +import { mergeIntoTypedArray } from '../../utils'; +import { isPDFInstance, PDFClasses } from '../../api/objects'; /** * Represents a page bounding box. @@ -40,15 +41,17 @@ export interface PageBoundingBox { const fullPageBoundingBox = (page: PDFPageLeaf) => { const mediaBox = page.MediaBox(); - const width = - mediaBox.lookup(2, PDFNumber).asNumber() - - mediaBox.lookup(0, PDFNumber).asNumber(); - - const height = - mediaBox.lookup(3, PDFNumber).asNumber() - - mediaBox.lookup(1, PDFNumber).asNumber(); - - return { left: 0, bottom: 0, right: width, top: height }; + const x0 = mediaBox.lookup(0, PDFNumber).asNumber(); + const y0 = mediaBox.lookup(1, PDFNumber).asNumber(); + const x1 = mediaBox.lookup(2, PDFNumber).asNumber(); + const y1 = mediaBox.lookup(3, PDFNumber).asNumber(); + + return { + left: Math.min(x0, x1), + bottom: Math.min(y0, y1), + right: Math.max(x0, x1), + top: Math.max(y0, y1), + }; }; // Returns the identity matrix, modified to position the content of the given @@ -123,10 +126,10 @@ class PDFPageEmbedder { const stream = contents.lookup(idx, PDFStream); let content: Uint8Array; - if (stream instanceof PDFRawStream) { - content = decodePDFRawStream(stream).decode(); - } else if (stream instanceof PDFContentStream) { - content = stream.getUnencodedContents(); + if (isPDFInstance(stream, PDFClasses.PDFRawStream)) { + content = decodePDFRawStream(stream as PDFRawStream).decode(); + } else if (isPDFInstance(stream, PDFClasses.PDFContentStream)) { + content = (stream as PDFContentStream).getUnencodedContents(); } else { throw new UnrecognizedStreamTypeError(stream); } diff --git a/src/core/embedders/PngEmbedder.ts b/src/core/embedders/PngEmbedder.ts index d01d4a71b..2ac298b44 100644 --- a/src/core/embedders/PngEmbedder.ts +++ b/src/core/embedders/PngEmbedder.ts @@ -1,6 +1,6 @@ -import PDFRef from 'src/core/objects/PDFRef'; -import PDFContext from 'src/core/PDFContext'; -import { PNG } from 'src/utils/png'; +import PDFRef from '../objects/PDFRef'; +import PDFContext from '../PDFContext'; +import { PNG } from '../../utils/png'; /** * A note of thanks to the developers of https://github.com/foliojs/pdfkit, as diff --git a/src/core/embedders/StandardFontEmbedder.ts b/src/core/embedders/StandardFontEmbedder.ts index 8a3b71083..219df617d 100644 --- a/src/core/embedders/StandardFontEmbedder.ts +++ b/src/core/embedders/StandardFontEmbedder.ts @@ -5,10 +5,11 @@ import { EncodingType, } from '@pdf-lib/standard-fonts'; -import PDFHexString from 'src/core/objects/PDFHexString'; -import PDFRef from 'src/core/objects/PDFRef'; -import PDFContext from 'src/core/PDFContext'; -import { toCodePoint, toHexString } from 'src/utils'; +import PDFHexString from '../objects/PDFHexString'; +import PDFRef from '../objects/PDFRef'; +import PDFContext from '../PDFContext'; +import { toCodePoint, toHexString } from '../../utils'; +import { PDFClasses } from '../../api/objects'; export interface Glyph { code: number; @@ -21,6 +22,10 @@ export interface Glyph { * https://github.com/foliojs/pdfkit/blob/f91bdd61c164a72ea06be1a43dc0a412afc3925f/lib/font/afm.coffee */ class StandardFontEmbedder { + static className = () => PDFClasses.StandardFontEmbedder; + myClass(): PDFClasses { + return PDFClasses.StandardFontEmbedder; + } static for = (fontName: FontNames, customName?: string) => new StandardFontEmbedder(fontName, customName); @@ -121,7 +126,12 @@ class StandardFontEmbedder { const glyphs: Glyph[] = new Array(codePoints.length); for (let idx = 0, len = codePoints.length; idx < len; idx++) { const codePoint = toCodePoint(codePoints[idx])!; - glyphs[idx] = this.encoding.encodeUnicodeCodePoint(codePoint); + try { + glyphs[idx] = this.encoding.encodeUnicodeCodePoint(codePoint); + } catch (error) { + // Replace non-WinAnsi characters with a placeholder + glyphs[idx] = this.encoding.encodeUnicodeCodePoint(toCodePoint('?')!); + } } return glyphs; } diff --git a/src/core/errors.ts b/src/core/errors.ts index f8374c482..3777e4b93 100644 --- a/src/core/errors.ts +++ b/src/core/errors.ts @@ -1,6 +1,6 @@ // tslint:disable: max-classes-per-file -import PDFObject from 'src/core/objects/PDFObject'; -import { arrayAsString } from 'src/utils'; +import PDFObject from './objects/PDFObject'; +import { arrayAsString } from '../utils'; export class MethodNotImplementedError extends Error { constructor(className: string, methodName: string) { @@ -55,7 +55,7 @@ export class MissingCatalogError extends Error { export class MissingPageContentsEmbeddingError extends Error { constructor() { - const msg = `Can't embed page with missing Contents`; + const msg = "Can't embed page with missing Contents"; super(msg); } } @@ -70,7 +70,8 @@ export class UnrecognizedStreamTypeError extends Error { export class PageEmbeddingMismatchedContextError extends Error { constructor() { - const msg = `Found mismatched contexts while embedding pages. All pages in the array passed to \`PDFDocument.embedPages()\` must be from the same document.`; + const msg = + 'Found mismatched contexts while embedding pages. All pages in the array passed to `PDFDocument.embedPages()` must be from the same document.'; super(msg); } } @@ -112,14 +113,14 @@ export class IndexOutOfBoundsError extends Error { export class InvalidAcroFieldValueError extends Error { constructor() { - const msg = `Attempted to set invalid field value`; + const msg = 'Attempted to set invalid field value'; super(msg); } } export class MultiSelectValueError extends Error { constructor() { - const msg = `Attempted to select multiple values for single-select field`; + const msg = 'Attempted to select multiple values for single-select field'; super(msg); } } @@ -149,7 +150,7 @@ export interface Position { export class NumberParsingError extends Error { constructor(pos: Position, value: string) { const msg = - `Failed to parse number ` + + 'Failed to parse number ' + `(line:${pos.line} col:${pos.column} offset=${pos.offset}): "${value}"`; super(msg); } @@ -158,7 +159,7 @@ export class NumberParsingError extends Error { export class PDFParsingError extends Error { constructor(pos: Position, details: string) { const msg = - `Failed to parse PDF document ` + + 'Failed to parse PDF document ' + `(line:${pos.line} col:${pos.column} offset=${pos.offset}): ${details}`; super(msg); } @@ -180,35 +181,36 @@ export class PDFObjectParsingError extends PDFParsingError { export class PDFInvalidObjectParsingError extends PDFParsingError { constructor(pos: Position) { - const msg = `Failed to parse invalid PDF object`; + const msg = 'Failed to parse invalid PDF object'; super(pos, msg); } } export class PDFStreamParsingError extends PDFParsingError { constructor(pos: Position) { - const msg = `Failed to parse PDF stream`; + const msg = 'Failed to parse PDF stream'; super(pos, msg); } } export class UnbalancedParenthesisError extends PDFParsingError { constructor(pos: Position) { - const msg = `Failed to parse PDF literal string due to unbalanced parenthesis`; + const msg = + 'Failed to parse PDF literal string due to unbalanced parenthesis'; super(pos, msg); } } export class StalledParserError extends PDFParsingError { constructor(pos: Position) { - const msg = `Parser stalled`; + const msg = 'Parser stalled'; super(pos, msg); } } export class MissingPDFHeaderError extends PDFParsingError { constructor(pos: Position) { - const msg = `No PDF header found`; + const msg = 'No PDF header found'; super(pos, msg); } } diff --git a/src/core/index.ts b/src/core/index.ts index 8e2d38616..0384cdcb7 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -1,29 +1,29 @@ -export * from 'src/core/errors'; -export { default as CharCodes } from 'src/core/syntax/CharCodes'; +export * from './errors'; +export { default as CharCodes } from './syntax/CharCodes'; -export { default as PDFContext } from 'src/core/PDFContext'; -export { default as PDFObjectCopier } from 'src/core/PDFObjectCopier'; -export { default as PDFWriter } from 'src/core/writers/PDFWriter'; -export { default as PDFStreamWriter } from 'src/core/writers/PDFStreamWriter'; +export { default as PDFContext } from './PDFContext'; +export { default as PDFObjectCopier } from './PDFObjectCopier'; +export { default as PDFWriter } from './writers/PDFWriter'; +export { default as PDFStreamWriter } from './writers/PDFStreamWriter'; -export { default as PDFHeader } from 'src/core/document/PDFHeader'; -export { default as PDFTrailer } from 'src/core/document/PDFTrailer'; -export { default as PDFTrailerDict } from 'src/core/document/PDFTrailerDict'; -export { default as PDFCrossRefSection } from 'src/core/document/PDFCrossRefSection'; +export { default as PDFHeader } from './document/PDFHeader'; +export { default as PDFTrailer } from './document/PDFTrailer'; +export { default as PDFTrailerDict } from './document/PDFTrailerDict'; +export { default as PDFCrossRefSection } from './document/PDFCrossRefSection'; -export { default as StandardFontEmbedder } from 'src/core/embedders/StandardFontEmbedder'; -export { default as CustomFontEmbedder } from 'src/core/embedders/CustomFontEmbedder'; -export { default as CustomFontSubsetEmbedder } from 'src/core/embedders/CustomFontSubsetEmbedder'; +export { default as StandardFontEmbedder } from './embedders/StandardFontEmbedder'; +export { default as CustomFontEmbedder } from './embedders/CustomFontEmbedder'; +export { default as CustomFontSubsetEmbedder } from './embedders/CustomFontSubsetEmbedder'; export { default as FileEmbedder, AFRelationship, -} from 'src/core/embedders/FileEmbedder'; -export { default as JpegEmbedder } from 'src/core/embedders/JpegEmbedder'; -export { default as PngEmbedder } from 'src/core/embedders/PngEmbedder'; +} from './embedders/FileEmbedder'; +export { default as JpegEmbedder } from './embedders/JpegEmbedder'; +export { default as PngEmbedder } from './embedders/PngEmbedder'; export { default as PDFPageEmbedder, PageBoundingBox, -} from 'src/core/embedders/PDFPageEmbedder'; +} from './embedders/PDFPageEmbedder'; export { default as ViewerPreferences, @@ -31,39 +31,44 @@ export { ReadingDirection, PrintScaling, Duplex, -} from 'src/core/interactive/ViewerPreferences'; +} from './interactive/ViewerPreferences'; -export { default as PDFObject } from 'src/core/objects/PDFObject'; -export { default as PDFBool } from 'src/core/objects/PDFBool'; -export { default as PDFNumber } from 'src/core/objects/PDFNumber'; -export { default as PDFString } from 'src/core/objects/PDFString'; -export { default as PDFHexString } from 'src/core/objects/PDFHexString'; -export { default as PDFName } from 'src/core/objects/PDFName'; -export { default as PDFNull } from 'src/core/objects/PDFNull'; -export { default as PDFArray } from 'src/core/objects/PDFArray'; -export { default as PDFDict } from 'src/core/objects/PDFDict'; -export { default as PDFRef } from 'src/core/objects/PDFRef'; -export { default as PDFInvalidObject } from 'src/core/objects/PDFInvalidObject'; -export { default as PDFStream } from 'src/core/objects/PDFStream'; -export { default as PDFRawStream } from 'src/core/objects/PDFRawStream'; +export { default as PDFObject } from './objects/PDFObject'; +export { default as PDFBool } from './objects/PDFBool'; +export { default as PDFNumber } from './objects/PDFNumber'; +export { default as PDFString } from './objects/PDFString'; +export { default as PDFHexString } from './objects/PDFHexString'; +export { default as PDFName } from './objects/PDFName'; +export { default as PDFNull } from './objects/PDFNull'; +export { default as PDFArray } from './objects/PDFArray'; +export { default as PDFDict } from './objects/PDFDict'; +export { default as PDFRef } from './objects/PDFRef'; +export { default as PDFInvalidObject } from './objects/PDFInvalidObject'; +export { default as PDFStream } from './objects/PDFStream'; +export { default as PDFRawStream } from './objects/PDFRawStream'; -export { default as PDFCatalog } from 'src/core/structures/PDFCatalog'; -export { default as PDFContentStream } from 'src/core/structures/PDFContentStream'; -export { default as PDFCrossRefStream } from 'src/core/structures/PDFCrossRefStream'; -export { default as PDFObjectStream } from 'src/core/structures/PDFObjectStream'; -export { default as PDFPageTree } from 'src/core/structures/PDFPageTree'; -export { default as PDFPageLeaf } from 'src/core/structures/PDFPageLeaf'; -export { default as PDFFlateStream } from 'src/core/structures/PDFFlateStream'; +export { default as PDFCatalog } from './structures/PDFCatalog'; +export { default as PDFContentStream } from './structures/PDFContentStream'; +export { default as PDFCrossRefStream } from './structures/PDFCrossRefStream'; +export { default as PDFObjectStream } from './structures/PDFObjectStream'; +export { default as PDFPageTree } from './structures/PDFPageTree'; +export { default as PDFPageLeaf } from './structures/PDFPageLeaf'; +export { default as PDFFlateStream } from './structures/PDFFlateStream'; -export { default as PDFOperator } from 'src/core/operators/PDFOperator'; -export { default as PDFOperatorNames } from 'src/core/operators/PDFOperatorNames'; +export { default as PDFOperator } from './operators/PDFOperator'; +export { default as PDFOperatorNames } from './operators/PDFOperatorNames'; -export { default as PDFObjectParser } from 'src/core/parser/PDFObjectParser'; -export { default as PDFObjectStreamParser } from 'src/core/parser/PDFObjectStreamParser'; -export { default as PDFParser } from 'src/core/parser/PDFParser'; -export { default as PDFXRefStreamParser } from 'src/core/parser/PDFXRefStreamParser'; +export { default as PDFObjectParser } from './parser/PDFObjectParser'; +export { default as PDFObjectStreamParser } from './parser/PDFObjectStreamParser'; +export { default as PDFParser } from './parser/PDFParser'; +export { default as PDFXRefStreamParser } from './parser/PDFXRefStreamParser'; -export { decodePDFRawStream } from 'src/core/streams/decode'; +export { + default as PDFSecurity, + SecurityOptions, +} from './security/PDFSecurity'; + +export { decodePDFRawStream } from './streams/decode'; -export * from 'src/core/annotation'; -export * from 'src/core/acroform'; +export * from './annotation'; +export * from './acroform'; diff --git a/src/core/interactive/ViewerPreferences.ts b/src/core/interactive/ViewerPreferences.ts index f1148aea7..3c2f8fedc 100644 --- a/src/core/interactive/ViewerPreferences.ts +++ b/src/core/interactive/ViewerPreferences.ts @@ -1,15 +1,16 @@ -import PDFArray from 'src/core/objects/PDFArray'; -import PDFBool from 'src/core/objects/PDFBool'; -import PDFDict from 'src/core/objects/PDFDict'; -import PDFName from 'src/core/objects/PDFName'; -import PDFNumber from 'src/core/objects/PDFNumber'; -import PDFContext from 'src/core/PDFContext'; +import PDFArray from '../objects/PDFArray'; +import PDFBool from '../objects/PDFBool'; +import PDFDict from '../objects/PDFDict'; +import PDFName from '../objects/PDFName'; +import PDFNumber from '../objects/PDFNumber'; +import PDFContext from '../PDFContext'; import { assertEachIs, assertInteger, assertIsOneOf, assertRange, -} from 'src/utils'; +} from '../../utils'; +import { isPDFInstance, PDFClasses } from '../../api/objects'; const asEnum = ( rawValue: T | undefined, @@ -115,13 +116,15 @@ class ViewerPreferences { protected lookupBool(key: BoolViewerPrefKey): PDFBool | undefined { const returnObj = this.dict.lookup(PDFName.of(key)); - if (returnObj instanceof PDFBool) return returnObj; + if (isPDFInstance(returnObj, PDFClasses.PDFBool)) + return returnObj as PDFBool; return undefined; } protected lookupName(key: NameViewerPrefKey): PDFName | undefined { const returnObj = this.dict.lookup(PDFName.of(key)); - if (returnObj instanceof PDFName) return returnObj; + if (isPDFInstance(returnObj, PDFClasses.PDFName)) + return returnObj as PDFName; return undefined; } @@ -183,14 +186,16 @@ class ViewerPreferences { /** @ignore */ PrintPageRange(): PDFArray | undefined { const PrintPageRange = this.dict.lookup(PDFName.of('PrintPageRange')); - if (PrintPageRange instanceof PDFArray) return PrintPageRange; + if (isPDFInstance(PrintPageRange, PDFClasses.PDFArray)) + return PrintPageRange as PDFArray; return undefined; } /** @ignore */ NumCopies(): PDFNumber | undefined { const NumCopies = this.dict.lookup(PDFName.of('NumCopies')); - if (NumCopies instanceof PDFNumber) return NumCopies; + if (isPDFInstance(NumCopies, PDFClasses.PDFNumber)) + return NumCopies as PDFNumber; return undefined; } diff --git a/src/core/objects/PDFArray.ts b/src/core/objects/PDFArray.ts index a2124fb5c..0a9653ea0 100644 --- a/src/core/objects/PDFArray.ts +++ b/src/core/objects/PDFArray.ts @@ -1,19 +1,24 @@ -import PDFBool from 'src/core/objects/PDFBool'; -import PDFDict from 'src/core/objects/PDFDict'; -import PDFHexString from 'src/core/objects/PDFHexString'; -import PDFName from 'src/core/objects/PDFName'; -import PDFNull from 'src/core/objects/PDFNull'; -import PDFNumber from 'src/core/objects/PDFNumber'; -import PDFObject from 'src/core/objects/PDFObject'; -import PDFRef from 'src/core/objects/PDFRef'; -import PDFStream from 'src/core/objects/PDFStream'; -import PDFString from 'src/core/objects/PDFString'; -import PDFContext from 'src/core/PDFContext'; -import CharCodes from 'src/core/syntax/CharCodes'; -import { PDFArrayIsNotRectangleError } from 'src/core/errors'; -import PDFRawStream from 'src/core/objects/PDFRawStream'; +import PDFBool from './PDFBool'; +import PDFDict from './PDFDict'; +import PDFHexString from './PDFHexString'; +import PDFName from './PDFName'; +import PDFNull from './PDFNull'; +import PDFNumber from './PDFNumber'; +import PDFObject from './PDFObject'; +import PDFRef from './PDFRef'; +import PDFStream from './PDFStream'; +import PDFString from './PDFString'; +import PDFContext from '../PDFContext'; +import CharCodes from '../syntax/CharCodes'; +import { PDFArrayIsNotRectangleError } from '../errors'; +import PDFRawStream from './PDFRawStream'; +import { isPDFInstance, PDFClasses } from '../../api/objects'; class PDFArray extends PDFObject { + static className = () => PDFClasses.PDFArray; + myClass(): PDFClasses { + return PDFClasses.PDFArray; + } static withContext = (context: PDFContext) => new PDFArray(context); private readonly array: PDFObject[]; @@ -30,10 +35,12 @@ class PDFArray extends PDFObject { } push(object: PDFObject): void { + this.registerChange(); this.array.push(object); } insert(index: number, object: PDFObject): void { + this.registerChange(); this.array.splice(index, 0, object); } @@ -43,10 +50,12 @@ class PDFArray extends PDFObject { } remove(index: number): void { + this.registerChange(); this.array.splice(index, 1); } set(idx: number, object: PDFObject): void { + this.registerChange(); this.array[idx] = object; } @@ -114,15 +123,15 @@ class PDFArray extends PDFObject { asRectangle(): { x: number; y: number; width: number; height: number } { if (this.size() !== 4) throw new PDFArrayIsNotRectangleError(this.size()); - const lowerLeftX = this.lookup(0, PDFNumber).asNumber(); - const lowerLeftY = this.lookup(1, PDFNumber).asNumber(); - const upperRightX = this.lookup(2, PDFNumber).asNumber(); - const upperRightY = this.lookup(3, PDFNumber).asNumber(); + const x1 = this.lookup(0, PDFNumber).asNumber(); + const y1 = this.lookup(1, PDFNumber).asNumber(); + const x2 = this.lookup(2, PDFNumber).asNumber(); + const y2 = this.lookup(3, PDFNumber).asNumber(); - const x = lowerLeftX; - const y = lowerLeftY; - const width = upperRightX - lowerLeftX; - const height = upperRightY - lowerLeftY; + const x = Math.min(x1, x2); + const y = Math.min(y1, y2); + const width = Math.abs(x1 - x2); + const height = Math.abs(y1 - y2); return { x, y, width, height }; } @@ -174,12 +183,16 @@ class PDFArray extends PDFObject { scalePDFNumbers(x: number, y: number): void { for (let idx = 0, len = this.size(); idx < len; idx++) { const el = this.lookup(idx); - if (el instanceof PDFNumber) { + if (isPDFInstance(el, PDFClasses.PDFNumber)) { const factor = idx % 2 === 0 ? x : y; - this.set(idx, PDFNumber.of(el.asNumber() * factor)); + this.set(idx, PDFNumber.of((el as PDFNumber).asNumber() * factor)); } } } + + registerChange(): void { + this.context.registerObjectChange(this); + } } export default PDFArray; diff --git a/src/core/objects/PDFBool.ts b/src/core/objects/PDFBool.ts index fc8264a0b..46d197078 100644 --- a/src/core/objects/PDFBool.ts +++ b/src/core/objects/PDFBool.ts @@ -1,10 +1,15 @@ -import { PrivateConstructorError } from 'src/core/errors'; -import PDFObject from 'src/core/objects/PDFObject'; -import CharCodes from 'src/core/syntax/CharCodes'; +import { PrivateConstructorError } from '../errors'; +import PDFObject from './PDFObject'; +import CharCodes from '../syntax/CharCodes'; +import { PDFClasses } from '../../api/objects'; const ENFORCER = {}; class PDFBool extends PDFObject { + static className = () => PDFClasses.PDFBool; + myClass(): PDFClasses { + return PDFClasses.PDFBool; + } static readonly True = new PDFBool(ENFORCER, true); static readonly False = new PDFBool(ENFORCER, false); diff --git a/src/core/objects/PDFDict.ts b/src/core/objects/PDFDict.ts index f7ba7c7ae..098567dc5 100644 --- a/src/core/objects/PDFDict.ts +++ b/src/core/objects/PDFDict.ts @@ -1,19 +1,26 @@ -import PDFArray from 'src/core/objects/PDFArray'; -import PDFBool from 'src/core/objects/PDFBool'; -import PDFHexString from 'src/core/objects/PDFHexString'; -import PDFName from 'src/core/objects/PDFName'; -import PDFNull from 'src/core/objects/PDFNull'; -import PDFNumber from 'src/core/objects/PDFNumber'; -import PDFObject from 'src/core/objects/PDFObject'; -import PDFRef from 'src/core/objects/PDFRef'; -import PDFStream from 'src/core/objects/PDFStream'; -import PDFString from 'src/core/objects/PDFString'; -import PDFContext from 'src/core/PDFContext'; -import CharCodes from 'src/core/syntax/CharCodes'; +import PDFArray from './PDFArray'; +import PDFBool from './PDFBool'; +import PDFHexString from './PDFHexString'; +import PDFName from './PDFName'; +import PDFNull from './PDFNull'; +import PDFNumber from './PDFNumber'; +import PDFObject from './PDFObject'; +import PDFRef from './PDFRef'; +import PDFStream from './PDFStream'; +import PDFString from './PDFString'; +import PDFContext from '../PDFContext'; +import CharCodes from '../syntax/CharCodes'; +import { isPDFInstance, PDFClasses } from '../../api/objects'; export type DictMap = Map; +// dictionary keys must be unique, using PDFName does not guarantee that +type InternalDictMap = Map; class PDFDict extends PDFObject { + static className = () => PDFClasses.PDFDict; + myClass(): PDFClasses { + return PDFClasses.PDFDict; + } static withContext = (context: PDFContext) => new PDFDict(new Map(), context); static fromMapWithContext = (map: DictMap, context: PDFContext) => @@ -21,28 +28,33 @@ class PDFDict extends PDFObject { readonly context: PDFContext; - private readonly dict: DictMap; + private readonly dict: InternalDictMap; + + suppressEncryption: boolean = false; protected constructor(map: DictMap, context: PDFContext) { super(); - this.dict = map; + this.dict = new Map( + Array.from(map.entries()).map((entry) => [entry[0].toString(), entry]), + ); this.context = context; } keys(): PDFName[] { - return Array.from(this.dict.keys()); + return Array.from(this.dict.values()).map((value) => value[0]); } values(): PDFObject[] { - return Array.from(this.dict.values()); + return Array.from(this.dict.values()).map((value) => value[1]); } entries(): [PDFName, PDFObject][] { - return Array.from(this.dict.entries()); + return Array.from(this.dict.values()); } set(key: PDFName, value: PDFObject): void { - this.dict.set(key, value); + this.registerChange(); + this.dict.set(key.asString(), [key, value]); } get( @@ -51,14 +63,20 @@ class PDFDict extends PDFObject { // removed in next breaking API change. preservePDFNull = false, ): PDFObject | undefined { - const value = this.dict.get(key); - if (value === PDFNull && !preservePDFNull) return undefined; - return value; + if (!key.asString) return undefined; + const value = this.dict.get(key.asString()); + if ( + !value || + (isPDFInstance(value[1], PDFClasses.PDFNull) && !preservePDFNull) + ) + return undefined; + return value[1]; } has(key: PDFName): boolean { - const value = this.dict.get(key); - return value !== undefined && value !== PDFNull; + if (!key.asString) return false; + const value = this.dict.get(key.asString()); + return value !== undefined && !isPDFInstance(value[1], PDFClasses.PDFNull); } lookupMaybe(key: PDFName, type: typeof PDFArray): PDFArray | undefined; @@ -102,7 +120,8 @@ class PDFDict extends PDFObject { ...types, ) as any; - if (value === PDFNull && !preservePDFNull) return undefined; + if (isPDFInstance(value, PDFClasses.PDFNull) && !preservePDFNull) + return undefined; return value; } @@ -146,17 +165,19 @@ class PDFDict extends PDFObject { ...types, ) as any; - if (value === PDFNull && !preservePDFNull) return undefined; + if (isPDFInstance(value, PDFClasses.PDFNull) && !preservePDFNull) + return undefined; return value; } delete(key: PDFName): boolean { - return this.dict.delete(key); + this.registerChange(); + return this.dict.delete(key.asString()); } asMap(): Map { - return new Map(this.dict); + return new Map(this.dict.values()); } /** Generate a random key that doesn't exist in current key set */ @@ -221,6 +242,10 @@ class PDFDict extends PDFObject { return offset - initialOffset; } + + registerChange(): void { + this.context.registerObjectChange(this); + } } export default PDFDict; diff --git a/src/core/objects/PDFHexString.ts b/src/core/objects/PDFHexString.ts index 8ddd7d416..266eb01e2 100644 --- a/src/core/objects/PDFHexString.ts +++ b/src/core/objects/PDFHexString.ts @@ -1,5 +1,5 @@ -import PDFObject from 'src/core/objects/PDFObject'; -import CharCodes from 'src/core/syntax/CharCodes'; +import PDFObject from './PDFObject'; +import CharCodes from '../syntax/CharCodes'; import { copyStringIntoBuffer, toHexStringOfMinLength, @@ -8,10 +8,16 @@ import { pdfDocEncodingDecode, parseDate, hasUtf16BOM, -} from 'src/utils'; -import { InvalidPDFDateStringError } from 'src/core/errors'; + byteArrayToHexString, +} from '../../utils'; +import { InvalidPDFDateStringError } from '../errors'; +import { PDFClasses } from '../../api/objects'; class PDFHexString extends PDFObject { + static className = () => PDFClasses.PDFHexString; + myClass(): PDFClasses { + return PDFClasses.PDFHexString; + } static of = (value: string) => new PDFHexString(value); static fromText = (value: string) => { @@ -25,6 +31,9 @@ class PDFHexString extends PDFObject { return new PDFHexString(hex); }; + static fromBytes = (bytes: Uint8Array) => + PDFHexString.of(byteArrayToHexString(bytes)); + private readonly value: string; constructor(value: string) { diff --git a/src/core/objects/PDFInvalidObject.ts b/src/core/objects/PDFInvalidObject.ts index ecf41cbbc..3e5ff7c17 100644 --- a/src/core/objects/PDFInvalidObject.ts +++ b/src/core/objects/PDFInvalidObject.ts @@ -1,6 +1,11 @@ -import PDFObject from 'src/core/objects/PDFObject'; +import { PDFClasses } from '../../api/objects'; +import PDFObject from './PDFObject'; class PDFInvalidObject extends PDFObject { + static className = () => PDFClasses.PDFInvalidObject; + myClass(): PDFClasses { + return PDFClasses.PDFInvalidObject; + } static of = (data: Uint8Array) => new PDFInvalidObject(data); private readonly data: Uint8Array; diff --git a/src/core/objects/PDFName.ts b/src/core/objects/PDFName.ts index 86a04bc34..8a97145b3 100644 --- a/src/core/objects/PDFName.ts +++ b/src/core/objects/PDFName.ts @@ -1,13 +1,14 @@ -import { PrivateConstructorError } from 'src/core/errors'; -import PDFObject from 'src/core/objects/PDFObject'; -import CharCodes from 'src/core/syntax/CharCodes'; -import { IsIrregular } from 'src/core/syntax/Irregular'; +import { PrivateConstructorError } from '../errors'; +import PDFObject from './PDFObject'; +import CharCodes from '../syntax/CharCodes'; +import { IsIrregular } from '../syntax/Irregular'; import { charFromHexCode, copyStringIntoBuffer, toCharCode, toHexString, -} from 'src/utils'; +} from '../../utils'; +import { PDFClasses } from '../../api/objects'; const decodeName = (name: string) => name.replace(/#([\dABCDEF]{2})/g, (_, hex) => charFromHexCode(hex)); @@ -21,6 +22,10 @@ const ENFORCER = {}; const pool = new Map(); class PDFName extends PDFObject { + static className = () => PDFClasses.PDFName; + myClass(): PDFClasses { + return PDFClasses.PDFName; + } static of = (name: string): PDFName => { const decodedValue = decodeName(name); @@ -151,7 +156,7 @@ class PDFName extends PDFObject { } copyBytesInto(buffer: Uint8Array, offset: number): number { - offset += copyStringIntoBuffer(this.encodedName, buffer, offset); + copyStringIntoBuffer(this.encodedName, buffer, offset); return this.encodedName.length; } } diff --git a/src/core/objects/PDFNull.ts b/src/core/objects/PDFNull.ts index 36f3f2987..afacf5785 100644 --- a/src/core/objects/PDFNull.ts +++ b/src/core/objects/PDFNull.ts @@ -1,7 +1,12 @@ -import PDFObject from 'src/core/objects/PDFObject'; -import CharCodes from 'src/core/syntax/CharCodes'; +import PDFObject from './PDFObject'; +import CharCodes from '../syntax/CharCodes'; +import { PDFClasses } from '../../api/objects'; class PDFNull extends PDFObject { + static className = () => PDFClasses.PDFNull; + myClass(): PDFClasses { + return PDFClasses.PDFNull; + } asNull(): null { return null; } diff --git a/src/core/objects/PDFNumber.ts b/src/core/objects/PDFNumber.ts index 33db2e696..75c5d3a44 100644 --- a/src/core/objects/PDFNumber.ts +++ b/src/core/objects/PDFNumber.ts @@ -1,8 +1,13 @@ -import { copyStringIntoBuffer, numberToString } from 'src/utils/index'; +import { PDFClasses } from '../../api/objects'; +import { copyStringIntoBuffer, numberToString } from '../../utils/index'; -import PDFObject from 'src/core/objects/PDFObject'; +import PDFObject from './PDFObject'; class PDFNumber extends PDFObject { + static className = () => PDFClasses.PDFNumber; + myClass(): PDFClasses { + return PDFClasses.PDFNumber; + } static of = (value: number) => new PDFNumber(value); private readonly numberValue: number; @@ -36,7 +41,7 @@ class PDFNumber extends PDFObject { } copyBytesInto(buffer: Uint8Array, offset: number): number { - offset += copyStringIntoBuffer(this.stringValue, buffer, offset); + copyStringIntoBuffer(this.stringValue, buffer, offset); return this.stringValue.length; } } diff --git a/src/core/objects/PDFObject.ts b/src/core/objects/PDFObject.ts index 625a9e7cf..5f5459f47 100644 --- a/src/core/objects/PDFObject.ts +++ b/src/core/objects/PDFObject.ts @@ -1,7 +1,19 @@ -import { MethodNotImplementedError } from 'src/core/errors'; -import PDFContext from 'src/core/PDFContext'; +import { PDFClasses } from '../../api/objects'; +import { MethodNotImplementedError } from '../errors'; +import PDFContext from '../PDFContext'; class PDFObject { + static className = () => PDFClasses.PDFObject; + myClass(): PDFClasses { + return PDFClasses.PDFObject; + } + + registerChange() { + throw new MethodNotImplementedError( + this.constructor.name, + 'registerChange', + ); + } clone(_context?: PDFContext): PDFObject { throw new MethodNotImplementedError(this.constructor.name, 'clone'); } diff --git a/src/core/objects/PDFRawStream.ts b/src/core/objects/PDFRawStream.ts index e867eba1f..561e6edcf 100644 --- a/src/core/objects/PDFRawStream.ts +++ b/src/core/objects/PDFRawStream.ts @@ -1,17 +1,32 @@ -import PDFDict from 'src/core/objects/PDFDict'; -import PDFStream from 'src/core/objects/PDFStream'; -import PDFContext from 'src/core/PDFContext'; -import { arrayAsString } from 'src/utils'; +import PDFDict from './PDFDict'; +import PDFStream from './PDFStream'; +import PDFContext from '../PDFContext'; +import { arrayAsString } from '../../utils'; +import { CipherTransform } from '../crypto'; +import { PDFClasses } from '../../api/objects'; class PDFRawStream extends PDFStream { - static of = (dict: PDFDict, contents: Uint8Array) => - new PDFRawStream(dict, contents); - - readonly contents: Uint8Array; - - private constructor(dict: PDFDict, contents: Uint8Array) { + static className = () => PDFClasses.PDFRawStream; + myClass(): PDFClasses { + return PDFClasses.PDFRawStream; + } + static of = ( + dict: PDFDict, + contents: Uint8Array, + transform?: CipherTransform, + ) => new PDFRawStream(dict, contents, transform); + + contents: Uint8Array; + readonly transform?: CipherTransform; + + private constructor( + dict: PDFDict, + contents: Uint8Array, + transform?: CipherTransform, + ) { super(dict); this.contents = contents; + this.transform = transform; } asUint8Array(): Uint8Array { @@ -33,6 +48,11 @@ class PDFRawStream extends PDFStream { getContentsSize(): number { return this.contents.length; } + + updateContents(contents: Uint8Array): void { + this.dict.registerChange(); + this.contents = contents; + } } export default PDFRawStream; diff --git a/src/core/objects/PDFRef.ts b/src/core/objects/PDFRef.ts index 513f873d4..c7ddab0ab 100644 --- a/src/core/objects/PDFRef.ts +++ b/src/core/objects/PDFRef.ts @@ -1,11 +1,16 @@ -import { PrivateConstructorError } from 'src/core/errors'; -import PDFObject from 'src/core/objects/PDFObject'; -import { copyStringIntoBuffer } from 'src/utils'; +import { PrivateConstructorError } from '../errors'; +import PDFObject from '../objects/PDFObject'; +import { copyStringIntoBuffer } from '../../utils'; +import { PDFClasses } from '../../api'; const ENFORCER = {}; const pool = new Map(); class PDFRef extends PDFObject { + static className = () => PDFClasses.PDFRef; + myClass(): PDFClasses { + return PDFClasses.PDFRef; + } static of = (objectNumber: number, generationNumber = 0) => { const tag = `${objectNumber} ${generationNumber} R`; @@ -47,7 +52,7 @@ class PDFRef extends PDFObject { } copyBytesInto(buffer: Uint8Array, offset: number): number { - offset += copyStringIntoBuffer(this.tag, buffer, offset); + copyStringIntoBuffer(this.tag, buffer, offset); return this.tag.length; } } diff --git a/src/core/objects/PDFStream.ts b/src/core/objects/PDFStream.ts index c947c7fbe..8bb3b9f89 100644 --- a/src/core/objects/PDFStream.ts +++ b/src/core/objects/PDFStream.ts @@ -1,12 +1,17 @@ -import { MethodNotImplementedError } from 'src/core/errors'; -import PDFDict from 'src/core/objects/PDFDict'; -import PDFName from 'src/core/objects/PDFName'; -import PDFNumber from 'src/core/objects/PDFNumber'; -import PDFObject from 'src/core/objects/PDFObject'; -import PDFContext from 'src/core/PDFContext'; -import CharCodes from 'src/core/syntax/CharCodes'; +import { MethodNotImplementedError } from '../errors'; +import PDFDict from './PDFDict'; +import PDFName from './PDFName'; +import PDFNumber from './PDFNumber'; +import PDFObject from './PDFObject'; +import PDFContext from '../PDFContext'; +import CharCodes from '../syntax/CharCodes'; +import { PDFClasses } from '../../api/objects'; class PDFStream extends PDFObject { + static className = () => PDFClasses.PDFStream; + myClass(): PDFClasses { + return PDFClasses.PDFStream; + } readonly dict: PDFDict; constructor(dict: PDFDict) { @@ -36,6 +41,13 @@ class PDFStream extends PDFObject { ); } + updateContents(_contents: Uint8Array): void { + throw new MethodNotImplementedError( + this.constructor.name, + 'updateContents', + ); + } + updateDict(): void { const contentsSize = this.getContentsSize(); this.dict.set(PDFName.Length, PDFNumber.of(contentsSize)); diff --git a/src/core/objects/PDFString.ts b/src/core/objects/PDFString.ts index 834f02d8e..ab1f3029a 100644 --- a/src/core/objects/PDFString.ts +++ b/src/core/objects/PDFString.ts @@ -1,5 +1,5 @@ -import PDFObject from 'src/core/objects/PDFObject'; -import CharCodes from 'src/core/syntax/CharCodes'; +import PDFObject from './PDFObject'; +import CharCodes from '../syntax/CharCodes'; import { copyStringIntoBuffer, padStart, @@ -8,10 +8,15 @@ import { toCharCode, parseDate, hasUtf16BOM, -} from 'src/utils'; -import { InvalidPDFDateStringError } from 'src/core/errors'; +} from '../../utils'; +import { InvalidPDFDateStringError } from '../errors'; +import { PDFClasses } from '../../api/objects'; class PDFString extends PDFObject { + static className = () => PDFClasses.PDFString; + myClass(): PDFClasses { + return PDFClasses.PDFString; + } // The PDF spec allows newlines and parens to appear directly within a literal // string. These character _may_ be escaped. But they do not _have_ to be. So // for simplicity, we will not bother escaping them. @@ -62,7 +67,7 @@ class PDFString extends PDFObject { else if (byte === CharCodes.f) pushByte(CharCodes.FormFeed); else if (byte === CharCodes.LeftParen) pushByte(CharCodes.LeftParen); else if (byte === CharCodes.RightParen) pushByte(CharCodes.RightParen); - else if (byte === CharCodes.Backspace) pushByte(CharCodes.BackSlash); + else if (byte === CharCodes.BackSlash) pushByte(CharCodes.BackSlash); else if (byte >= CharCodes.Zero && byte <= CharCodes.Seven) { octal += char; if (octal.length === 3 || !(nextChar >= '0' && nextChar <= '7')) { diff --git a/src/core/operators/PDFOperator.ts b/src/core/operators/PDFOperator.ts index e110dff65..967f69b0f 100644 --- a/src/core/operators/PDFOperator.ts +++ b/src/core/operators/PDFOperator.ts @@ -1,13 +1,14 @@ -import PDFArray from 'src/core/objects/PDFArray'; -import PDFHexString from 'src/core/objects/PDFHexString'; -import PDFName from 'src/core/objects/PDFName'; -import PDFNumber from 'src/core/objects/PDFNumber'; -import PDFObject from 'src/core/objects/PDFObject'; -import PDFString from 'src/core/objects/PDFString'; -import PDFOperatorNames from 'src/core/operators/PDFOperatorNames'; -import PDFContext from 'src/core/PDFContext'; -import CharCodes from 'src/core/syntax/CharCodes'; -import { copyStringIntoBuffer } from 'src/utils'; +import PDFArray from '../objects/PDFArray'; +import PDFHexString from '../objects/PDFHexString'; +import PDFName from '../objects/PDFName'; +import PDFNumber from '../objects/PDFNumber'; +import PDFObject from '../objects/PDFObject'; +import PDFString from '../objects/PDFString'; +import PDFOperatorNames from './PDFOperatorNames'; +import PDFContext from '../PDFContext'; +import CharCodes from '../syntax/CharCodes'; +import { copyStringIntoBuffer } from '../../utils'; +import { isPDFInstance, PDFClasses } from '../../api/objects'; export type PDFOperatorArg = | string @@ -33,7 +34,9 @@ class PDFOperator { const args = new Array(this.args.length); for (let idx = 0, len = args.length; idx < len; idx++) { const arg = this.args[idx]; - args[idx] = arg instanceof PDFObject ? arg.clone(context) : arg; + args[idx] = isPDFInstance(arg, PDFClasses.PDFObject) + ? (arg as PDFObject).clone(context) + : arg; } return PDFOperator.of(this.name, args); } @@ -51,7 +54,10 @@ class PDFOperator { let size = 0; for (let idx = 0, len = this.args.length; idx < len; idx++) { const arg = this.args[idx]; - size += (arg instanceof PDFObject ? arg.sizeInBytes() : arg.length) + 1; + size += + (isPDFInstance(arg, PDFClasses.PDFObject) + ? (arg as PDFObject).sizeInBytes() + : (arg as string).length) + 1; } size += this.name.length; return size; @@ -62,10 +68,10 @@ class PDFOperator { for (let idx = 0, len = this.args.length; idx < len; idx++) { const arg = this.args[idx]; - if (arg instanceof PDFObject) { - offset += arg.copyBytesInto(buffer, offset); + if (isPDFInstance(arg, PDFClasses.PDFObject)) { + offset += (arg as PDFObject).copyBytesInto(buffer, offset); } else { - offset += copyStringIntoBuffer(arg, buffer, offset); + offset += copyStringIntoBuffer(arg as string, buffer, offset); } buffer[offset++] = CharCodes.Space; } diff --git a/src/core/parser/BaseParser.ts b/src/core/parser/BaseParser.ts index 44e0bce16..137d8d7ec 100644 --- a/src/core/parser/BaseParser.ts +++ b/src/core/parser/BaseParser.ts @@ -1,9 +1,9 @@ -import { NumberParsingError } from 'src/core/errors'; -import ByteStream from 'src/core/parser/ByteStream'; -import CharCodes from 'src/core/syntax/CharCodes'; -import { IsDigit, IsNumeric } from 'src/core/syntax/Numeric'; -import { IsWhitespace } from 'src/core/syntax/Whitespace'; -import { charFromCode } from 'src/utils'; +import { NumberParsingError } from '../errors'; +import ByteStream from '../parser/ByteStream'; +import CharCodes from '../syntax/CharCodes'; +import { IsDigit, IsNumeric } from '../syntax/Numeric'; +import { IsWhitespace } from '../syntax/Whitespace'; +import { charFromCode } from '../../utils'; const { Newline, CarriageReturn } = CharCodes; diff --git a/src/core/parser/ByteStream.ts b/src/core/parser/ByteStream.ts index 6098f4f84..d1260a5e8 100644 --- a/src/core/parser/ByteStream.ts +++ b/src/core/parser/ByteStream.ts @@ -1,7 +1,7 @@ -import { NextByteAssertionError } from 'src/core/errors'; -import PDFRawStream from 'src/core/objects/PDFRawStream'; -import { decodePDFRawStream } from 'src/core/streams/decode'; -import CharCodes from 'src/core/syntax/CharCodes'; +import { NextByteAssertionError } from '../errors'; +import PDFRawStream from '../objects/PDFRawStream'; +import { decodePDFRawStream } from '../streams/decode'; +import CharCodes from '../syntax/CharCodes'; // TODO: See how line/col tracking affects performance class ByteStream { diff --git a/src/core/parser/PDFObjectParser.ts b/src/core/parser/PDFObjectParser.ts index c51b59fd4..30e54592a 100644 --- a/src/core/parser/PDFObjectParser.ts +++ b/src/core/parser/PDFObjectParser.ts @@ -3,31 +3,33 @@ import { PDFStreamParsingError, Position, UnbalancedParenthesisError, -} from 'src/core/errors'; -import PDFArray from 'src/core/objects/PDFArray'; -import PDFBool from 'src/core/objects/PDFBool'; -import PDFDict, { DictMap } from 'src/core/objects/PDFDict'; -import PDFHexString from 'src/core/objects/PDFHexString'; -import PDFName from 'src/core/objects/PDFName'; -import PDFNull from 'src/core/objects/PDFNull'; -import PDFNumber from 'src/core/objects/PDFNumber'; -import PDFObject from 'src/core/objects/PDFObject'; -import PDFRawStream from 'src/core/objects/PDFRawStream'; -import PDFRef from 'src/core/objects/PDFRef'; -import PDFStream from 'src/core/objects/PDFStream'; -import PDFString from 'src/core/objects/PDFString'; -import BaseParser from 'src/core/parser/BaseParser'; -import ByteStream from 'src/core/parser/ByteStream'; -import PDFContext from 'src/core/PDFContext'; -import PDFCatalog from 'src/core/structures/PDFCatalog'; -import PDFPageLeaf from 'src/core/structures/PDFPageLeaf'; -import PDFPageTree from 'src/core/structures/PDFPageTree'; -import CharCodes from 'src/core/syntax/CharCodes'; -import { IsDelimiter } from 'src/core/syntax/Delimiters'; -import { Keywords } from 'src/core/syntax/Keywords'; -import { IsDigit, IsNumeric } from 'src/core/syntax/Numeric'; -import { IsWhitespace } from 'src/core/syntax/Whitespace'; -import { charFromCode } from 'src/utils'; +} from '../errors'; +import PDFArray from '../objects/PDFArray'; +import PDFBool from '../objects/PDFBool'; +import PDFDict, { DictMap } from '../objects/PDFDict'; +import PDFHexString from '../objects/PDFHexString'; +import PDFName from '../objects/PDFName'; +import PDFNull from '../objects/PDFNull'; +import PDFNumber from '../objects/PDFNumber'; +import PDFObject from '../objects/PDFObject'; +import PDFRawStream from '../objects/PDFRawStream'; +import PDFRef from '../objects/PDFRef'; +import PDFStream from '../objects/PDFStream'; +import PDFString from '../objects/PDFString'; +import BaseParser from './BaseParser'; +import ByteStream from './ByteStream'; +import PDFContext from '../PDFContext'; +import PDFCatalog from '../structures/PDFCatalog'; +import PDFPageLeaf from '../structures/PDFPageLeaf'; +import PDFPageTree from '../structures/PDFPageTree'; +import CharCodes from '../syntax/CharCodes'; +import { IsDelimiter } from '../syntax/Delimiters'; +import { Keywords } from '../syntax/Keywords'; +import { IsDigit, IsNumeric } from '../syntax/Numeric'; +import { IsWhitespace } from '../syntax/Whitespace'; +import { arrayAsString, charFromCode } from '../../utils'; +import { CipherTransformFactory } from '../crypto'; +import { isPDFInstance, PDFClasses } from '../../api/objects'; // TODO: Throw error if eof is reached before finishing object parse... class PDFObjectParser extends BaseParser { @@ -44,14 +46,21 @@ class PDFObjectParser extends BaseParser { ) => new PDFObjectParser(byteStream, context, capNumbers); protected readonly context: PDFContext; + private readonly cryptoFactory?: CipherTransformFactory; - constructor(byteStream: ByteStream, context: PDFContext, capNumbers = false) { + constructor( + byteStream: ByteStream, + context: PDFContext, + capNumbers = false, + cryptoFactory?: CipherTransformFactory, + ) { super(byteStream, capNumbers); this.context = context; + this.cryptoFactory = cryptoFactory; } // TODO: Is it possible to reduce duplicate parsing for ref lookaheads? - parseObject(): PDFObject { + parseObject(ref?: PDFRef): PDFObject { this.skipWhitespaceAndComments(); if (this.matchKeyword(Keywords.true)) return PDFBool.True; @@ -64,12 +73,12 @@ class PDFObjectParser extends BaseParser { byte === CharCodes.LessThan && this.bytes.peekAhead(1) === CharCodes.LessThan ) { - return this.parseDictOrStream(); + return this.parseDictOrStream(ref); } - if (byte === CharCodes.LessThan) return this.parseHexString(); - if (byte === CharCodes.LeftParen) return this.parseString(); + if (byte === CharCodes.LessThan) return this.parseHexString(ref); + if (byte === CharCodes.LeftParen) return this.parseString(ref); if (byte === CharCodes.ForwardSlash) return this.parseName(); - if (byte === CharCodes.LeftSquareBracket) return this.parseArray(); + if (byte === CharCodes.LeftSquareBracket) return this.parseArray(ref); if (IsNumeric[byte]) return this.parseNumberOrRef(); throw new PDFObjectParsingError(this.bytes.position(), byte); @@ -94,7 +103,7 @@ class PDFObjectParser extends BaseParser { } // TODO: Maybe update PDFHexString.of() logic to remove whitespace and validate input? - protected parseHexString(): PDFHexString { + protected parseHexString(ref?: PDFRef): PDFHexString { let value = ''; this.bytes.assertNext(CharCodes.LessThan); @@ -103,10 +112,22 @@ class PDFObjectParser extends BaseParser { } this.bytes.assertNext(CharCodes.GreaterThan); + if (this.cryptoFactory && ref) { + const transformer = this.cryptoFactory.createCipherTransform( + ref.objectNumber, + ref.generationNumber, + ); + const arr = transformer.decryptBytes(PDFHexString.of(value).asBytes()); + value = arr.reduce( + (str: string, byte: number) => str + byte.toString(16).padStart(2, '0'), + '', + ); + } + return PDFHexString.of(value); } - protected parseString(): PDFString { + protected parseString(ref?: PDFRef): PDFString { let nestingLvl = 0; let isEscaped = false; let value = ''; @@ -130,8 +151,20 @@ class PDFObjectParser extends BaseParser { // Once (if) the unescaped parenthesis balance out, return their contents if (nestingLvl === 0) { + let actualValue = value.substring(1, value.length - 1); + + if (this.cryptoFactory && ref) { + const transformer = this.cryptoFactory.createCipherTransform( + ref.objectNumber, + ref.generationNumber, + ); + const decrypted = transformer.decryptBytes( + PDFString.of(actualValue).asBytes(), + ); + actualValue = arrayAsString(decrypted); + } // Remove the outer parens so they aren't part of the contents - return PDFString.of(value.substring(1, value.length - 1)); + return PDFString.of(actualValue); } } @@ -154,13 +187,13 @@ class PDFObjectParser extends BaseParser { return PDFName.of(name); } - protected parseArray(): PDFArray { + protected parseArray(ref?: PDFRef): PDFArray { this.bytes.assertNext(CharCodes.LeftSquareBracket); this.skipWhitespaceAndComments(); const pdfArray = PDFArray.withContext(this.context); while (this.bytes.peek() !== CharCodes.RightSquareBracket) { - const element = this.parseObject(); + const element = this.parseObject(ref); pdfArray.push(element); this.skipWhitespaceAndComments(); } @@ -168,7 +201,7 @@ class PDFObjectParser extends BaseParser { return pdfArray; } - protected parseDict(): PDFDict { + protected parseDict(ref?: PDFRef): PDFDict { this.bytes.assertNext(CharCodes.LessThan); this.bytes.assertNext(CharCodes.LessThan); this.skipWhitespaceAndComments(); @@ -181,7 +214,7 @@ class PDFObjectParser extends BaseParser { this.bytes.peekAhead(1) !== CharCodes.GreaterThan ) { const key = this.parseName(); - const value = this.parseObject(); + const value = this.parseObject(ref); dict.set(key, value); this.skipWhitespaceAndComments(); } @@ -203,10 +236,10 @@ class PDFObjectParser extends BaseParser { } } - protected parseDictOrStream(): PDFDict | PDFStream { + protected parseDictOrStream(ref?: PDFRef): PDFDict | PDFStream { const startPos = this.bytes.position(); - const dict = this.parseDict(); + const dict = this.parseDict(ref); this.skipWhitespaceAndComments(); @@ -224,8 +257,8 @@ class PDFObjectParser extends BaseParser { let end: number; const Length = dict.get(PDFName.of('Length')); - if (Length instanceof PDFNumber) { - end = start + Length.asNumber(); + if (isPDFInstance(Length, PDFClasses.PDFNumber)) { + end = start + (Length as PDFNumber).asNumber(); this.bytes.moveTo(end); this.skipWhitespaceAndComments(); if (!this.matchKeyword(Keywords.endstream)) { @@ -236,7 +269,15 @@ class PDFObjectParser extends BaseParser { end = this.findEndOfStreamFallback(startPos); } - const contents = this.bytes.slice(start, end); + let contents = this.bytes.slice(start, end); + + if (this.cryptoFactory && ref) { + const transform = this.cryptoFactory.createCipherTransform( + ref.objectNumber, + ref.generationNumber, + ); + contents = transform.decryptBytes(contents); + } return PDFRawStream.of(dict, contents); } diff --git a/src/core/parser/PDFObjectStreamParser.ts b/src/core/parser/PDFObjectStreamParser.ts index 47dd043b2..3f81e0456 100644 --- a/src/core/parser/PDFObjectStreamParser.ts +++ b/src/core/parser/PDFObjectStreamParser.ts @@ -1,11 +1,11 @@ -import { ReparseError } from 'src/core/errors'; -import PDFName from 'src/core/objects/PDFName'; -import PDFNumber from 'src/core/objects/PDFNumber'; -import PDFRawStream from 'src/core/objects/PDFRawStream'; -import PDFRef from 'src/core/objects/PDFRef'; -import ByteStream from 'src/core/parser/ByteStream'; -import PDFObjectParser from 'src/core/parser/PDFObjectParser'; -import { waitForTick } from 'src/utils'; +import { ReparseError } from '../errors'; +import PDFName from '../objects/PDFName'; +import PDFNumber from '../objects/PDFNumber'; +import PDFRawStream from '../objects/PDFRawStream'; +import PDFRef from '../objects/PDFRef'; +import ByteStream from './ByteStream'; +import PDFObjectParser from './PDFObjectParser'; +import { waitForTick } from '../../utils'; class PDFObjectStreamParser extends PDFObjectParser { static forStream = ( @@ -39,8 +39,8 @@ class PDFObjectStreamParser extends PDFObjectParser { for (let idx = 0, len = offsetsAndObjectNumbers.length; idx < len; idx++) { const { objectNumber, offset } = offsetsAndObjectNumbers[idx]; this.bytes.moveTo(this.firstOffset + offset); - const object = this.parseObject(); const ref = PDFRef.of(objectNumber, 0); + const object = this.parseObject(ref); this.context.assign(ref, object); if (this.shouldWaitForTick()) await waitForTick(); } diff --git a/src/core/parser/PDFParser.ts b/src/core/parser/PDFParser.ts index 5b5497e3f..3c334ee2b 100644 --- a/src/core/parser/PDFParser.ts +++ b/src/core/parser/PDFParser.ts @@ -1,40 +1,57 @@ -import PDFCrossRefSection from 'src/core/document/PDFCrossRefSection'; -import PDFHeader from 'src/core/document/PDFHeader'; -import PDFTrailer from 'src/core/document/PDFTrailer'; +import PDFCrossRefSection from '../document/PDFCrossRefSection'; +import PDFHeader from '../document/PDFHeader'; +import PDFTrailer from '../document/PDFTrailer'; import { MissingKeywordError, MissingPDFHeaderError, PDFInvalidObjectParsingError, ReparseError, StalledParserError, -} from 'src/core/errors'; -import PDFDict from 'src/core/objects/PDFDict'; -import PDFInvalidObject from 'src/core/objects/PDFInvalidObject'; -import PDFName from 'src/core/objects/PDFName'; -import PDFObject from 'src/core/objects/PDFObject'; -import PDFRawStream from 'src/core/objects/PDFRawStream'; -import PDFRef from 'src/core/objects/PDFRef'; -import ByteStream from 'src/core/parser/ByteStream'; -import PDFObjectParser from 'src/core/parser/PDFObjectParser'; -import PDFObjectStreamParser from 'src/core/parser/PDFObjectStreamParser'; -import PDFXRefStreamParser from 'src/core/parser/PDFXRefStreamParser'; -import PDFContext from 'src/core/PDFContext'; -import CharCodes from 'src/core/syntax/CharCodes'; -import { Keywords } from 'src/core/syntax/Keywords'; -import { IsDigit } from 'src/core/syntax/Numeric'; -import { waitForTick } from 'src/utils'; +} from '../errors'; +import PDFDict from '../objects/PDFDict'; +import PDFInvalidObject from '../objects/PDFInvalidObject'; +import PDFName from '../objects/PDFName'; +import PDFObject from '../objects/PDFObject'; +import PDFRawStream from '../objects/PDFRawStream'; +import PDFRef from '../objects/PDFRef'; +import ByteStream from './ByteStream'; +import PDFObjectParser from './PDFObjectParser'; +import PDFObjectStreamParser from './PDFObjectStreamParser'; +import PDFXRefStreamParser from './PDFXRefStreamParser'; +import PDFContext from '../PDFContext'; +import CharCodes from '../syntax/CharCodes'; +import { Keywords } from '../syntax/Keywords'; +import { IsDigit } from '../syntax/Numeric'; +import { waitForTick } from '../../utils'; +import { CipherTransformFactory } from '../crypto'; +import PDFNumber from '../objects/PDFNumber'; +import { isPDFInstance, PDFClasses } from '../../api/objects'; class PDFParser extends PDFObjectParser { static forBytesWithOptions = ( pdfBytes: Uint8Array, objectsPerTick?: number, throwOnInvalidObject?: boolean, + warnOnInvalidObjects?: boolean, capNumbers?: boolean, + cryptoFactory?: CipherTransformFactory, + forIncrementalUpdate?: boolean, + preserveObjectsVersions?: boolean, ) => - new PDFParser(pdfBytes, objectsPerTick, throwOnInvalidObject, capNumbers); + new PDFParser( + pdfBytes, + objectsPerTick, + throwOnInvalidObject, + warnOnInvalidObjects, + capNumbers, + cryptoFactory, + forIncrementalUpdate, + preserveObjectsVersions, + ); private readonly objectsPerTick: number; private readonly throwOnInvalidObject: boolean; + private readonly warnOnInvalidObjects: boolean; private alreadyParsed = false; private parsedObjects = 0; @@ -42,11 +59,26 @@ class PDFParser extends PDFObjectParser { pdfBytes: Uint8Array, objectsPerTick = Infinity, throwOnInvalidObject = false, + warnOnInvalidObjects = false, capNumbers = false, + cryptoFactory?: CipherTransformFactory, + forIncrementalUpdate = false, + preserveObjectsVersions = false, ) { - super(ByteStream.of(pdfBytes), PDFContext.create(), capNumbers); + super( + ByteStream.of(pdfBytes), + PDFContext.create(preserveObjectsVersions), + capNumbers, + cryptoFactory, + ); this.objectsPerTick = objectsPerTick; this.throwOnInvalidObject = throwOnInvalidObject; + this.warnOnInvalidObjects = warnOnInvalidObjects; + this.context.isDecrypted = !!cryptoFactory?.encryptionKey; + this.context.pdfFileDetails.pdfSize = pdfBytes.length; + if (forIncrementalUpdate) { + this.context.pdfFileDetails.originalBytes = pdfBytes; + } } async parseDocument(): Promise { @@ -79,8 +111,8 @@ class PDFParser extends PDFObjectParser { private maybeRecoverRoot(): void { const isValidCatalog = (obj?: PDFObject) => - obj instanceof PDFDict && - obj.lookup(PDFName.of('Type')) === PDFName.of('Catalog'); + isPDFInstance(obj, PDFClasses.PDFDict) && + (obj as PDFDict).lookup(PDFName.of('Type')) === PDFName.of('Catalog'); const catalog = this.context.lookup(this.context.trailerInfo.Root); @@ -146,7 +178,7 @@ class PDFParser extends PDFObjectParser { const ref = this.parseIndirectObjectHeader(); this.skipWhitespaceAndComments(); - const object = this.parseObject(); + const object = this.parseObject(ref); this.skipWhitespaceAndComments(); // if (!this.matchKeyword(Keywords.endobj)) { @@ -157,21 +189,33 @@ class PDFParser extends PDFObjectParser { this.matchKeyword(Keywords.endobj); if ( - object instanceof PDFRawStream && - object.dict.lookup(PDFName.of('Type')) === PDFName.of('ObjStm') + isPDFInstance(object, PDFClasses.PDFRawStream) && + (object as PDFRawStream).dict.lookup(PDFName.of('Type')) === + PDFName.of('ObjStm') ) { await PDFObjectStreamParser.forStream( - object, + object as PDFRawStream, this.shouldWaitForTick, ).parseIntoContext(); } else if ( - object instanceof PDFRawStream && - object.dict.lookup(PDFName.of('Type')) === PDFName.of('XRef') + isPDFInstance(object, PDFClasses.PDFRawStream) && + (object as PDFRawStream).dict.lookup(PDFName.of('Type')) === + PDFName.of('XRef') ) { - PDFXRefStreamParser.forStream(object).parseIntoContext(); - } else { - this.context.assign(ref, object); + const entries = PDFXRefStreamParser.forStream( + object as PDFRawStream, + ).parseIntoContext(); + if (entries.length) { + const xref = PDFCrossRefSection.createEmpty(); + for (const entry of entries) { + if (entry.deleted) xref.addDeletedEntry(entry.ref, entry.offset); + else xref.addEntry(entry.ref, entry.offset); + } + this.context.xrefs.push(xref); + } } + // always register the object and the ref, to properly handle object numeration + this.context.assign(ref, object); return ref; } @@ -182,11 +226,11 @@ class PDFParser extends PDFObjectParser { const msg = `Trying to parse invalid object: ${JSON.stringify(startPos)})`; if (this.throwOnInvalidObject) throw new Error(msg); - console.warn(msg); + if (this.warnOnInvalidObjects) console.warn(msg); const ref = this.parseIndirectObjectHeader(); - console.warn(`Invalid object ref: ${ref}`); + if (this.warnOnInvalidObjects) console.warn(`Invalid object ref: ${ref}`); this.skipWhitespaceAndComments(); const start = this.bytes.offset(); @@ -244,6 +288,11 @@ class PDFParser extends PDFObjectParser { const firstInt = this.parseRawInt(); this.skipWhitespaceAndComments(); + // Check if second digit is valid integer + if (!IsDigit[this.bytes.peek()]) { + return PDFCrossRefSection.createEmpty(); + } + const secondInt = this.parseRawInt(); this.skipWhitespaceAndComments(); @@ -275,11 +324,17 @@ class PDFParser extends PDFObjectParser { const { context } = this; context.trailerInfo = { + Size: + dict.lookupMaybe(PDFName.of('Size'), PDFNumber) || + context.trailerInfo.Size, Root: dict.get(PDFName.of('Root')) || context.trailerInfo.Root, Encrypt: dict.get(PDFName.of('Encrypt')) || context.trailerInfo.Encrypt, Info: dict.get(PDFName.of('Info')) || context.trailerInfo.Info, ID: dict.get(PDFName.of('ID')) || context.trailerInfo.ID, }; + // if open for incremental update, then deleted objects need to be preserved, and largestObjectNumber has to be Size-1 + if (context.trailerInfo.Size && context.pdfFileDetails.originalBytes) + context.largestObjectNumber = context.trailerInfo.Size.asNumber() - 1; } private maybeParseTrailer(): PDFTrailer | void { @@ -288,6 +343,7 @@ class PDFParser extends PDFObjectParser { this.skipWhitespaceAndComments(); const offset = this.parseRawInt(); + this.context.pdfFileDetails.prevStartXRef = offset; this.skipWhitespace(); this.matchKeyword(Keywords.eof); @@ -300,7 +356,8 @@ class PDFParser extends PDFObjectParser { private async parseDocumentSection(): Promise { await this.parseIndirectObjects(); - this.maybeParseCrossRefSection(); + const xref = this.maybeParseCrossRefSection(); + if (xref) this.context.xrefs.push(xref); this.maybeParseTrailerDict(); this.maybeParseTrailer(); diff --git a/src/core/parser/PDFXRefStreamParser.ts b/src/core/parser/PDFXRefStreamParser.ts index e452d1152..a054850f4 100644 --- a/src/core/parser/PDFXRefStreamParser.ts +++ b/src/core/parser/PDFXRefStreamParser.ts @@ -1,12 +1,13 @@ -import { ReparseError } from 'src/core/errors'; -import PDFArray from 'src/core/objects/PDFArray'; -import PDFDict from 'src/core/objects/PDFDict'; -import PDFName from 'src/core/objects/PDFName'; -import PDFNumber from 'src/core/objects/PDFNumber'; -import PDFRawStream from 'src/core/objects/PDFRawStream'; -import PDFRef from 'src/core/objects/PDFRef'; -import ByteStream from 'src/core/parser/ByteStream'; -import PDFContext from 'src/core/PDFContext'; +import { ReparseError } from '../errors'; +import PDFArray from '../objects/PDFArray'; +import PDFDict from '../objects/PDFDict'; +import PDFName from '../objects/PDFName'; +import PDFNumber from '../objects/PDFNumber'; +import PDFRawStream from '../objects/PDFRawStream'; +import PDFRef from '../objects/PDFRef'; +import ByteStream from './ByteStream'; +import PDFContext from '../PDFContext'; +import { isPDFInstance, PDFClasses } from '../../api/objects'; export interface Entry { ref: PDFRef; @@ -36,15 +37,20 @@ class PDFXRefStreamParser { this.dict = rawStream.dict; this.bytes = ByteStream.fromPDFRawStream(rawStream); this.context = this.dict.context; + this.context.pdfFileDetails.useObjectStreams = true; const Size = this.dict.lookup(PDFName.of('Size'), PDFNumber); const Index = this.dict.lookup(PDFName.of('Index')); - if (Index instanceof PDFArray) { + if (isPDFInstance(Index, PDFClasses.PDFArray)) { this.subsections = []; - for (let idx = 0, len = Index.size(); idx < len; idx += 2) { - const firstObjectNumber = Index.lookup(idx + 0, PDFNumber).asNumber(); - const length = Index.lookup(idx + 1, PDFNumber).asNumber(); + for (let idx = 0, len = (Index as PDFArray).size(); idx < len; idx += 2) { + const firstObjectNumber = (Index as PDFArray) + .lookup(idx + 0, PDFNumber) + .asNumber(); + const length = (Index as PDFArray) + .lookup(idx + 1, PDFNumber) + .asNumber(); this.subsections.push({ firstObjectNumber, length }); } } else { @@ -65,11 +71,19 @@ class PDFXRefStreamParser { this.alreadyParsed = true; this.context.trailerInfo = { + Size: this.dict.lookup(PDFName.of('Size'), PDFNumber), Root: this.dict.get(PDFName.of('Root')), Encrypt: this.dict.get(PDFName.of('Encrypt')), Info: this.dict.get(PDFName.of('Info')), ID: this.dict.get(PDFName.of('ID')), }; + // if open for incremental update, make sure next object number doesn't overlap a deleted one + if ( + this.context.trailerInfo.Size && + this.context.pdfFileDetails.originalBytes + ) + this.context.largestObjectNumber = + this.context.trailerInfo.Size.asNumber() - 1; const entries = this.parseEntries(); @@ -113,7 +127,7 @@ class PDFXRefStreamParser { const objectNumber = firstObjectNumber + objIdx; const entry = { - ref: PDFRef.of(objectNumber, generationNumber), + ref: PDFRef.of(objectNumber, type === 2 ? 0 : generationNumber), offset, deleted: type === 0, inObjectStream: type === 2, diff --git a/src/core/security/PDFSecurity.ts b/src/core/security/PDFSecurity.ts new file mode 100644 index 000000000..6ebd462cd --- /dev/null +++ b/src/core/security/PDFSecurity.ts @@ -0,0 +1,685 @@ +import CryptoJS from 'crypto-js'; +import PDFContext from '../PDFContext'; + +type WordArray = CryptoJS.lib.WordArray; +type RandomWordArrayGenerator = (bytes: number) => WordArray; + +/** + * Interface representing user permissions. + * + * @interface UserPermissions + */ +interface UserPermissions { + /** + * Printing Permission + * For Security handlers of revision <= 2 : Boolean + * For Security handlers of revision >= 3 : 'lowResolution' or 'highResolution' + */ + printing?: boolean | 'lowResolution' | 'highResolution'; + /** + * Modify Content Permission (Other than 'annotating', 'fillingForms' and 'documentAssembly') + */ + modifying?: boolean; + /** Copy or otherwise extract text and graphics from document */ + copying?: boolean; + /** Permission to add or modify text annotations */ + annotating?: boolean; + /** + * Security handlers of revision >= 3 + * Fill in existing interactive form fields (including signature fields) + */ + fillingForms?: boolean; + /** + * Security handlers of revision >= 3 + * Extract text and graphics (in support of accessibility to users with disabilities or for other purposes) + */ + contentAccessibility?: boolean; + /** + * Security handlers of revision >= 3 + * Assemble the document (insert, rotate or delete pages and create bookmarks or thumbnail images) + */ + documentAssembly?: boolean; +} + +export type EncryptFn = (buffer: Uint8Array) => Uint8Array; + +/** + * Interface options for security + * @interface SecurityOptions + */ +export interface SecurityOptions { + /** + * Password that provides unlimited access to the encrypted document. + * + * Opening encrypted document with owner password allows full (owner) access to the document + */ + ownerPassword?: string; + + /** Password that restricts reader according to the defined permissions. + * + * Opening encrypted document with user password will have limitations in accordance to the permission defined. + */ + userPassword?: string; + + /** Object representing type of user permission enforced on the document + * @link {@link UserPermissions} + */ + permissions?: UserPermissions; +} + +type Algorithm = 1 | 2 | 4 | 5; +type Revision = 2 | 3 | 4 | 5; +type KeyBits = 40 | 128 | 256; + +type Encryption = { + V: number; + R: number; + O: Uint8Array; + U: Uint8Array; + P: number; + Filter: string; + Length?: number; + CF?: { + StdCF: { + AuthEvent: 'DocOpen'; + CFM: 'AESV2' | 'AESV3'; + Length: number; + }; + }; + StmF?: string; + StrF?: string; + OE?: Uint8Array; + UE?: Uint8Array; + Perms?: Uint8Array; +}; + +class PDFSecurity { + context: PDFContext; + + // These are required values which are set by the `initalize` function. + private id!: Uint8Array; + private encryption!: Encryption; + private keyBits!: KeyBits; + private encryptionKey!: WordArray; + + static create(context: PDFContext, options: SecurityOptions) { + return new PDFSecurity(context, options); + } + + constructor(context: PDFContext, options: SecurityOptions) { + if (!options.ownerPassword && !options.userPassword) { + throw new Error( + 'Either an owner password or a user password must be specified.', + ); + } + + this.context = context; + + this.initialize(options); + } + + private initialize(options: SecurityOptions) { + this.id = generateFileID(); + + let v: Algorithm; + switch (this.context.header.getVersionString()) { + case '1.4': + case '1.5': + v = 2; + break; + case '1.6': + case '1.7': + v = 4; + break; + case '1.7ext3': + v = 5; + break; + default: + v = 1; + break; + } + + switch (v) { + case 1: + case 2: + case 4: + this.encryption = this.initializeV1V2V4(v, options); + break; + case 5: + this.encryption = this.initializeV5(options); + break; + } + } + + private initializeV1V2V4(v: Algorithm, options: SecurityOptions): Encryption { + const encryption = { + Filter: 'Standard', + } as Encryption; + + let r: Revision; + let permissions: number; + + switch (v) { + case 1: + r = 2; + this.keyBits = 40; + permissions = getPermissionsR2(options.permissions); + break; + case 2: + r = 3; + this.keyBits = 128; + permissions = getPermissionsR3(options.permissions); + break; + case 4: + r = 4; + this.keyBits = 128; + permissions = getPermissionsR3(options.permissions); + break; + default: + throw new Error(`Unsupported algorithm '${v}'.`); + } + + const paddedUserPassword: WordArray = processPasswordR2R3R4( + options.userPassword, + ); + + const paddedOwnerPassword: WordArray = options.ownerPassword + ? processPasswordR2R3R4(options.ownerPassword) + : paddedUserPassword; + + const ownerPasswordEntry: WordArray = getOwnerPasswordR2R3R4( + r, + this.keyBits, + paddedUserPassword, + paddedOwnerPassword, + ); + + this.encryptionKey = getEncryptionKeyR2R3R4( + r, + this.keyBits, + this.id, + paddedUserPassword, + ownerPasswordEntry, + permissions, + ); + + let userPasswordEntry; + if (r === 2) { + userPasswordEntry = getUserPasswordR2(this.encryptionKey); + } else { + userPasswordEntry = getUserPasswordR3R4(this.id, this.encryptionKey); + } + + encryption.V = v; + if (v >= 2) { + encryption.Length = this.keyBits; + } + if (v === 4) { + encryption.CF = { + StdCF: { + AuthEvent: 'DocOpen', + CFM: 'AESV2', + Length: this.keyBits / 8, + }, + }; + encryption.StmF = 'StdCF'; + encryption.StrF = 'StdCF'; + } + + encryption.R = r; + + encryption.O = wordArrayToBuffer(ownerPasswordEntry); + encryption.U = wordArrayToBuffer(userPasswordEntry); + encryption.P = permissions; + + return encryption; + } + + private initializeV5(options: SecurityOptions): Encryption { + const encryption = { + Filter: 'Standard', + } as Encryption; + + this.keyBits = 256; + + this.encryptionKey = getEncryptionKeyR5(generateRandomWordArray); + + const processedUserPassword = processPasswordR5(options.userPassword); + const userPasswordEntry = getUserPasswordR5( + processedUserPassword, + generateRandomWordArray, + ); + const userKeySalt = CryptoJS.lib.WordArray.create( + userPasswordEntry.words.slice(10, 12), + 8, + ); + const userEncryptionKeyEntry = getUserEncryptionKeyR5( + processedUserPassword, + userKeySalt, + this.encryptionKey, + ); + + const processedOwnerPassword = options.ownerPassword + ? processPasswordR5(options.ownerPassword) + : processedUserPassword; + const ownerPasswordEntry = getOwnerPasswordR5( + processedOwnerPassword, + userPasswordEntry, + generateRandomWordArray, + ); + const ownerKeySalt = CryptoJS.lib.WordArray.create( + ownerPasswordEntry.words.slice(10, 12), + 8, + ); + const ownerEncryptionKeyEntry = getOwnerEncryptionKeyR5( + processedOwnerPassword, + ownerKeySalt, + userPasswordEntry, + this.encryptionKey, + ); + + const permissions = getPermissionsR3(options.permissions); + const permissionsEntry = getEncryptedPermissionsR5( + permissions, + this.encryptionKey, + generateRandomWordArray, + ); + + encryption.V = 5; + encryption.Length = this.keyBits; + encryption.CF = { + StdCF: { + AuthEvent: 'DocOpen', + CFM: 'AESV3', + Length: this.keyBits / 8, + }, + }; + encryption.StmF = 'StdCF'; + encryption.StrF = 'StdCF'; + + encryption.R = 5; + + encryption.O = wordArrayToBuffer(ownerPasswordEntry); + encryption.OE = wordArrayToBuffer(ownerEncryptionKeyEntry); + encryption.U = wordArrayToBuffer(userPasswordEntry); + encryption.UE = wordArrayToBuffer(userEncryptionKeyEntry); + encryption.P = permissions; + encryption.Perms = wordArrayToBuffer(permissionsEntry); + + return encryption; + } + + getEncryptFn(obj: number, gen: number) { + const v = this.encryption.V; + + let digest: WordArray; + let key: WordArray; + if (v < 5) { + digest = this.encryptionKey + .clone() + .concat( + CryptoJS.lib.WordArray.create( + [ + ((obj & 0xff) << 24) | + ((obj & 0xff00) << 8) | + ((obj >> 8) & 0xff00) | + (gen & 0xff), + (gen & 0xff00) << 16, + ], + 5, + ), + ); + + if (v === 1 || v === 2) { + key = CryptoJS.MD5(digest); + key.sigBytes = Math.min(16, this.keyBits / 8 + 5); + return (buffer: Uint8Array) => + wordArrayToBuffer( + CryptoJS.RC4.encrypt( + CryptoJS.lib.WordArray.create(buffer as unknown as number[]), + key, + ).ciphertext, + ); + } + + if (v === 4) { + key = CryptoJS.MD5( + digest.concat(CryptoJS.lib.WordArray.create([0x73416c54], 4)), + ); + } + } else if (v === 5) { + key = this.encryptionKey; + } else { + throw new Error(`Unsupported algorithm '${v}'.`); + } + + const iv = generateRandomWordArray(16); + const options = { + mode: CryptoJS.mode.CBC, + padding: CryptoJS.pad.Pkcs7, + iv, + }; + + return (buffer: Uint8Array) => + wordArrayToBuffer( + iv + .clone() + .concat( + CryptoJS.AES.encrypt( + CryptoJS.lib.WordArray.create(buffer as unknown as number[]), + key, + options, + ).ciphertext, + ), + ); + } + + encrypt() { + const ID = this.context.obj([this.id, this.id]); + this.context.trailerInfo.ID = ID; + + const Encrypt = this.context.obj(this.encryption); + this.context.trailerInfo.Encrypt = this.context.register(Encrypt); + + return this; + } +} + +/** + * A file ID is required if Encrypt entry is present in Trailer + * Doesn't really matter what it is as long as it is consistently + * used. + * + * @returns Uint8Array + */ +const generateFileID = (): Uint8Array => + wordArrayToBuffer(CryptoJS.MD5(Date.now().toString())); + +const generateRandomWordArray = (bytes: number): WordArray => + CryptoJS.lib.WordArray.random(bytes); + +/** + * Get Permission Flag for use Encryption Dictionary (Key: P) + * For Security Handler revision 2 + * + * Only bit position 3,4,5,6,9,10,11 and 12 is meaningful + * Refer Table 22 - User access permission + * @param {permissions} {@link UserPermissions} + * @returns number - Representing unsigned 32-bit integer + */ +const getPermissionsR2 = (permissions: UserPermissions = {}) => { + let flags = 0xffffffc0 >> 0; + if (permissions.printing) { + flags |= 0b000000000100; + } + if (permissions.modifying) { + flags |= 0b000000001000; + } + if (permissions.copying) { + flags |= 0b000000010000; + } + if (permissions.annotating) { + flags |= 0b000000100000; + } + return flags; +}; + +/** + * Get Permission Flag for use Encryption Dictionary (Key: P) + * For Security Handler revision 2 + * + * Only bit position 3,4,5,6,9,10,11 and 12 is meaningful + * Refer Table 22 - User access permission + * @param {permissions} {@link UserPermissions} + * @returns number - Representing unsigned 32-bit integer + */ +const getPermissionsR3 = (permissions: UserPermissions = {}) => { + let flags = 0xfffff0c0 >> 0; + if (permissions.printing === 'lowResolution' || permissions.printing) { + flags |= 0b000000000100; + } + if (permissions.printing === 'highResolution') { + flags |= 0b100000000100; + } + if (permissions.modifying) { + flags |= 0b000000001000; + } + if (permissions.copying) { + flags |= 0b000000010000; + } + if (permissions.annotating) { + flags |= 0b000000100000; + } + if (permissions.fillingForms) { + flags |= 0b000100000000; + } + if (permissions.contentAccessibility) { + flags |= 0b001000000000; + } + if (permissions.documentAssembly) { + flags |= 0b010000000000; + } + return flags; +}; + +const getUserPasswordR2 = (encryptionKey: CryptoJS.lib.WordArray) => + CryptoJS.RC4.encrypt(processPasswordR2R3R4(), encryptionKey).ciphertext; + +const getUserPasswordR3R4 = ( + documentId: Uint8Array, + encryptionKey: WordArray, +) => { + const key = encryptionKey.clone(); + let cipher = CryptoJS.MD5( + processPasswordR2R3R4().concat( + CryptoJS.lib.WordArray.create(documentId as unknown as number[]), + ), + ); + for (let i = 0; i < 20; i++) { + const xorRound = Math.ceil(key.sigBytes / 4); + for (let j = 0; j < xorRound; j++) { + key.words[j] = + encryptionKey.words[j] ^ (i | (i << 8) | (i << 16) | (i << 24)); + } + cipher = CryptoJS.RC4.encrypt(cipher, key).ciphertext; + } + return cipher.concat( + CryptoJS.lib.WordArray.create(null as unknown as undefined, 16), + ); +}; + +const getOwnerPasswordR2R3R4 = ( + r: Revision, + keyBits: KeyBits, + paddedUserPassword: WordArray, + paddedOwnerPassword: WordArray, +): CryptoJS.lib.WordArray => { + let digest = paddedOwnerPassword; + let round = r >= 3 ? 51 : 1; + for (let i = 0; i < round; i++) { + digest = CryptoJS.MD5(digest); + } + + const key = digest.clone(); + key.sigBytes = keyBits / 8; + let cipher = paddedUserPassword; + round = r >= 3 ? 20 : 1; + for (let i = 0; i < round; i++) { + const xorRound = Math.ceil(key.sigBytes / 4); + for (let j = 0; j < xorRound; j++) { + key.words[j] = digest.words[j] ^ (i | (i << 8) | (i << 16) | (i << 24)); + } + cipher = CryptoJS.RC4.encrypt(cipher, key).ciphertext; + } + return cipher; +}; + +const getEncryptionKeyR2R3R4 = ( + r: Revision, + keyBits: KeyBits, + documentId: Uint8Array, + paddedUserPassword: WordArray, + ownerPasswordEntry: WordArray, + permissions: number, +): WordArray => { + let key = paddedUserPassword + .clone() + .concat(ownerPasswordEntry) + .concat(CryptoJS.lib.WordArray.create([lsbFirstWord(permissions)], 4)) + .concat(CryptoJS.lib.WordArray.create(documentId as unknown as number[])); + const round = r >= 3 ? 51 : 1; + for (let i = 0; i < round; i++) { + key = CryptoJS.MD5(key); + key.sigBytes = keyBits / 8; + } + return key; +}; + +const getUserPasswordR5 = ( + processedUserPassword: WordArray, + randomWordArrayGenerator: RandomWordArrayGenerator, +) => { + const validationSalt = randomWordArrayGenerator(8); + const keySalt = randomWordArrayGenerator(8); + return CryptoJS.SHA256(processedUserPassword.clone().concat(validationSalt)) + .concat(validationSalt) + .concat(keySalt); +}; + +const getUserEncryptionKeyR5 = ( + processedUserPassword: WordArray, + userKeySalt: WordArray, + encryptionKey: WordArray, +) => { + const key = CryptoJS.SHA256( + processedUserPassword.clone().concat(userKeySalt), + ); + const options = { + mode: CryptoJS.mode.CBC, + padding: CryptoJS.pad.NoPadding, + iv: CryptoJS.lib.WordArray.create(null as unknown as undefined, 16), + }; + return CryptoJS.AES.encrypt(encryptionKey, key, options).ciphertext; +}; + +const getOwnerPasswordR5 = ( + processedOwnerPassword: WordArray, + userPasswordEntry: WordArray, + randomWordArrayGenerator: RandomWordArrayGenerator, +) => { + const validationSalt = randomWordArrayGenerator(8); + const keySalt = randomWordArrayGenerator(8); + return CryptoJS.SHA256( + processedOwnerPassword + .clone() + .concat(validationSalt) + .concat(userPasswordEntry), + ) + .concat(validationSalt) + .concat(keySalt); +}; + +const getOwnerEncryptionKeyR5 = ( + processedOwnerPassword: WordArray, + ownerKeySalt: WordArray, + userPasswordEntry: WordArray, + encryptionKey: WordArray, +) => { + const key = CryptoJS.SHA256( + processedOwnerPassword + .clone() + .concat(ownerKeySalt) + .concat(userPasswordEntry), + ); + const options = { + mode: CryptoJS.mode.CBC, + padding: CryptoJS.pad.NoPadding, + iv: CryptoJS.lib.WordArray.create(null as unknown as undefined, 16), + }; + return CryptoJS.AES.encrypt(encryptionKey, key, options).ciphertext; +}; + +const getEncryptionKeyR5 = ( + randomWordArrayGenerator: RandomWordArrayGenerator, +) => randomWordArrayGenerator(32); + +const getEncryptedPermissionsR5 = ( + permissions: number, + encryptionKey: WordArray, + randomWordArrayGenerator: RandomWordArrayGenerator, +) => { + const cipher = CryptoJS.lib.WordArray.create( + [lsbFirstWord(permissions), 0xffffffff, 0x54616462], + 12, + ).concat(randomWordArrayGenerator(4)); + const options = { + mode: CryptoJS.mode.ECB, + padding: CryptoJS.pad.NoPadding, + }; + return CryptoJS.AES.encrypt(cipher, encryptionKey, options).ciphertext; +}; + +const processPasswordR2R3R4 = (password = '') => { + const out = new Uint8Array(32); + const length = password.length; + let index = 0; + while (index < length && index < 32) { + const code = password.charCodeAt(index); + if (code > 0xff) { + throw new Error('Password contains one or more invalid characters.'); + } + out[index] = code; + index++; + } + while (index < 32) { + out[index] = PASSWORD_PADDING[index - length]; + index++; + } + return CryptoJS.lib.WordArray.create(out as unknown as number[]); +}; + +const processPasswordR5 = (password = '') => { + // NOTE: Removed this line to eliminate need for the saslprep dependency. + // Probably worth investigating the cases that would be impacted by this. + // password = unescape(encodeURIComponent(saslprep(password))); + + const length = Math.min(127, password.length); + const out = new Uint8Array(length); + + for (let i = 0; i < length; i++) { + out[i] = password.charCodeAt(i); + } + + return CryptoJS.lib.WordArray.create(out as unknown as number[]); +}; + +const lsbFirstWord = (data: number): number => + ((data & 0xff) << 24) | + ((data & 0xff00) << 8) | + ((data >> 8) & 0xff00) | + ((data >> 24) & 0xff); + +const wordArrayToBuffer = (wordArray: WordArray): Uint8Array => { + const byteArray = []; + for (let i = 0; i < wordArray.sigBytes; i++) { + byteArray.push( + (wordArray.words[Math.floor(i / 4)] >> (8 * (3 - (i % 4)))) & 0xff, + ); + } + + return Uint8Array.from(byteArray); +}; + +/* + 7.6.3.3 Encryption Key Algorithm + Algorithm 2 + Password Padding to pad or truncate + the password to exactly 32 bytes +*/ +const PASSWORD_PADDING = [ + 0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, 0x64, 0x00, 0x4e, 0x56, 0xff, + 0xfa, 0x01, 0x08, 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80, 0x2f, 0x0c, + 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a, +]; + +export default PDFSecurity; diff --git a/src/core/streams/Ascii85Stream.ts b/src/core/streams/Ascii85Stream.ts index 3d0d84f5f..39189a4dc 100644 --- a/src/core/streams/Ascii85Stream.ts +++ b/src/core/streams/Ascii85Stream.ts @@ -6,8 +6,8 @@ * under the Apache 2.0 open source license. */ -import DecodeStream from 'src/core/streams/DecodeStream'; -import { StreamType } from 'src/core/streams/Stream'; +import DecodeStream from './DecodeStream'; +import { StreamType } from './Stream'; const isSpace = (ch: number) => ch === 0x20 || ch === 0x09 || ch === 0x0d || ch === 0x0a; diff --git a/src/core/streams/AsciiHexStream.ts b/src/core/streams/AsciiHexStream.ts index a782e2211..d9efc18fc 100644 --- a/src/core/streams/AsciiHexStream.ts +++ b/src/core/streams/AsciiHexStream.ts @@ -6,8 +6,8 @@ * under the Apache 2.0 open source license. */ -import DecodeStream from 'src/core/streams/DecodeStream'; -import { StreamType } from 'src/core/streams/Stream'; +import DecodeStream from './DecodeStream'; +import { StreamType } from './Stream'; class AsciiHexStream extends DecodeStream { private stream: StreamType; diff --git a/src/core/streams/DecodeStream.ts b/src/core/streams/DecodeStream.ts index 62dda11ce..7143ab4c5 100644 --- a/src/core/streams/DecodeStream.ts +++ b/src/core/streams/DecodeStream.ts @@ -1,5 +1,5 @@ -import { MethodNotImplementedError } from 'src/core/errors'; -import Stream, { StreamType } from 'src/core/streams/Stream'; +import { MethodNotImplementedError } from '../errors'; +import Stream, { StreamType } from './Stream'; /* * Copyright 2012 Mozilla Foundation diff --git a/src/core/streams/DecryptStream.ts b/src/core/streams/DecryptStream.ts new file mode 100644 index 000000000..a23cf2eb3 --- /dev/null +++ b/src/core/streams/DecryptStream.ts @@ -0,0 +1,56 @@ +import DecodeStream from './DecodeStream'; +import { StreamType } from './Stream'; + +const chunkSize = 512; + +type DecryptFnType = ( + arg1: Uint8Array | Uint8ClampedArray, + arg2: boolean, +) => Uint8Array; + +class DecryptStream extends DecodeStream { + private stream: StreamType; + private initialized: boolean; + private nextChunk: Uint8Array | Uint8ClampedArray | null; + private decrypt: DecryptFnType; + + constructor( + stream: StreamType, + decrypt: DecryptFnType, + maybeLength?: number, + ) { + super(maybeLength); + + this.stream = stream; + this.decrypt = decrypt; + this.nextChunk = null; + this.initialized = false; + } + + readBlock() { + let chunk; + if (this.initialized) { + chunk = this.nextChunk; + } else { + chunk = this.stream.getBytes(chunkSize); + this.initialized = true; + } + if (!chunk || chunk.length === 0) { + this.eof = true; + return; + } + this.nextChunk = this.stream.getBytes(chunkSize); + const hasMoreData = this.nextChunk && this.nextChunk.length > 0; + + const decrypt = this.decrypt; + chunk = decrypt(chunk, !hasMoreData); + + const bufferLength = this.bufferLength; + const newLength = bufferLength + chunk.length; + const buffer = this.ensureBuffer(newLength); + buffer.set(chunk, bufferLength); + this.bufferLength = newLength; + } +} + +export default DecryptStream; diff --git a/src/core/streams/FlateStream.ts b/src/core/streams/FlateStream.ts index 5b751375b..aa7e7cd48 100644 --- a/src/core/streams/FlateStream.ts +++ b/src/core/streams/FlateStream.ts @@ -15,8 +15,8 @@ */ /* tslint:disable no-conditional-assignment */ -import DecodeStream from 'src/core/streams/DecodeStream'; -import { StreamType } from 'src/core/streams/Stream'; +import DecodeStream from '../../core/streams/DecodeStream'; +import { StreamType } from '../../core/streams/Stream'; // prettier-ignore const codeLenCodeMap = new Int32Array([ @@ -272,6 +272,7 @@ class FlateStream extends DecodeStream { buffer = this.buffer; let limit = buffer ? buffer.length : 0; let pos = this.bufferLength; + // eslint-disable-next-line no-constant-condition while (true) { let code1 = this.getCode(litCodeTable); if (code1 < 256) { diff --git a/src/core/streams/LZWStream.ts b/src/core/streams/LZWStream.ts index c18738a47..39e15d3e6 100644 --- a/src/core/streams/LZWStream.ts +++ b/src/core/streams/LZWStream.ts @@ -6,14 +6,14 @@ * under the Apache 2.0 open source license. */ -import DecodeStream from 'src/core/streams/DecodeStream'; -import { StreamType } from 'src/core/streams/Stream'; +import DecodeStream from './DecodeStream'; +import { StreamType } from './Stream'; class LZWStream extends DecodeStream { private stream: StreamType; private cachedData: number; private bitsCached: number; - private lzwState: { + private lzwState?: { earlyChange: 0 | 1; codeLength: number; nextCode: number; diff --git a/src/core/streams/RunLengthStream.ts b/src/core/streams/RunLengthStream.ts index 04821c80e..269e54ca0 100644 --- a/src/core/streams/RunLengthStream.ts +++ b/src/core/streams/RunLengthStream.ts @@ -6,8 +6,8 @@ * under the Apache 2.0 open source license. */ -import DecodeStream from 'src/core/streams/DecodeStream'; -import { StreamType } from 'src/core/streams/Stream'; +import DecodeStream from './DecodeStream'; +import { StreamType } from './Stream'; class RunLengthStream extends DecodeStream { private stream: StreamType; diff --git a/src/core/streams/decode.ts b/src/core/streams/decode.ts index c9bd689c0..8b7af7e87 100644 --- a/src/core/streams/decode.ts +++ b/src/core/streams/decode.ts @@ -1,19 +1,17 @@ -import { - UnexpectedObjectTypeError, - UnsupportedEncodingError, -} from 'src/core/errors'; -import PDFArray from 'src/core/objects/PDFArray'; -import PDFDict from 'src/core/objects/PDFDict'; -import PDFName from 'src/core/objects/PDFName'; -import PDFNull from 'src/core/objects/PDFNull'; -import PDFNumber from 'src/core/objects/PDFNumber'; -import PDFRawStream from 'src/core/objects/PDFRawStream'; -import Ascii85Stream from 'src/core/streams/Ascii85Stream'; -import AsciiHexStream from 'src/core/streams/AsciiHexStream'; -import FlateStream from 'src/core/streams/FlateStream'; -import LZWStream from 'src/core/streams/LZWStream'; -import RunLengthStream from 'src/core/streams/RunLengthStream'; -import Stream, { StreamType } from 'src/core/streams/Stream'; +import { isPDFInstance, PDFClasses } from '../../api/objects'; +import { UnexpectedObjectTypeError, UnsupportedEncodingError } from '../errors'; +import PDFArray from '../objects/PDFArray'; +import PDFDict from '../objects/PDFDict'; +import PDFName from '../objects/PDFName'; +import PDFNull from '../objects/PDFNull'; +import PDFNumber from '../objects/PDFNumber'; +import PDFRawStream from '../objects/PDFRawStream'; +import Ascii85Stream from './Ascii85Stream'; +import AsciiHexStream from './AsciiHexStream'; +import FlateStream from './FlateStream'; +import LZWStream from './LZWStream'; +import RunLengthStream from './RunLengthStream'; +import Stream, { StreamType } from './Stream'; const decodeStream = ( stream: StreamType, @@ -25,10 +23,10 @@ const decodeStream = ( } if (encoding === PDFName.of('LZWDecode')) { let earlyChange = 1; - if (params instanceof PDFDict) { - const EarlyChange = params.lookup(PDFName.of('EarlyChange')); - if (EarlyChange instanceof PDFNumber) { - earlyChange = EarlyChange.asNumber(); + if (isPDFInstance(params, PDFClasses.PDFDict)) { + const EarlyChange = (params as PDFDict).lookup(PDFName.of('EarlyChange')); + if (isPDFInstance(EarlyChange, PDFClasses.PDFNumber)) { + earlyChange = (EarlyChange as PDFNumber).asNumber(); } } return new LZWStream(stream, undefined, earlyChange as 0 | 1); @@ -45,27 +43,35 @@ const decodeStream = ( throw new UnsupportedEncodingError(encoding.asString()); }; -export const decodePDFRawStream = ({ dict, contents }: PDFRawStream) => { +export const decodePDFRawStream = ({ + dict, + contents, + transform, +}: PDFRawStream) => { let stream: StreamType = new Stream(contents); + if (transform) { + stream = transform.createStream(stream, contents.length); + } + const Filter = dict.lookup(PDFName.of('Filter')); const DecodeParms = dict.lookup(PDFName.of('DecodeParms')); - if (Filter instanceof PDFName) { + if (isPDFInstance(Filter, PDFClasses.PDFName)) { stream = decodeStream( stream, - Filter, + Filter as PDFName, DecodeParms as PDFDict | typeof PDFNull | undefined, ); - } else if (Filter instanceof PDFArray) { - for (let idx = 0, len = Filter.size(); idx < len; idx++) { + } else if (isPDFInstance(Filter, PDFClasses.PDFArray)) { + for (let idx = 0, len = (Filter as PDFArray).size(); idx < len; idx++) { stream = decodeStream( stream, - Filter.lookup(idx, PDFName), + (Filter as PDFArray).lookup(idx, PDFName), DecodeParms && (DecodeParms as PDFArray).lookupMaybe(idx, PDFDict), ); } - } else if (!!Filter) { + } else if (Filter) { throw new UnexpectedObjectTypeError([PDFName, PDFArray], Filter); } diff --git a/src/core/structures/PDFCatalog.ts b/src/core/structures/PDFCatalog.ts index 93765f03c..856e0e0ac 100644 --- a/src/core/structures/PDFCatalog.ts +++ b/src/core/structures/PDFCatalog.ts @@ -1,12 +1,18 @@ -import PDFDict, { DictMap } from 'src/core/objects/PDFDict'; -import PDFName from 'src/core/objects/PDFName'; -import PDFRef from 'src/core/objects/PDFRef'; -import PDFContext from 'src/core/PDFContext'; -import PDFPageTree from 'src/core/structures/PDFPageTree'; -import { PDFAcroForm } from 'src/core/acroform'; +import PDFDict, { DictMap } from '../objects/PDFDict'; +import PDFName from '../objects/PDFName'; +import PDFRef from '../objects/PDFRef'; +import PDFContext from '../PDFContext'; +import PDFPageTree from './PDFPageTree'; +import { PDFAcroForm } from '../acroform'; import ViewerPreferences from '../interactive/ViewerPreferences'; +import PDFArray from '../objects/PDFArray'; +import { PDFClasses } from '../../api/objects'; class PDFCatalog extends PDFDict { + static className = () => PDFClasses.PDFCatalog; + myClass(): PDFClasses { + return PDFClasses.PDFCatalog; + } static withContextAndPages = ( context: PDFContext, pages: PDFPageTree | PDFRef, @@ -28,6 +34,14 @@ class PDFCatalog extends PDFDict { return this.lookupMaybe(PDFName.of('AcroForm'), PDFDict); } + Names(): PDFDict | undefined { + return this.lookupMaybe(PDFName.of('Names'), PDFDict); + } + + AttachedFiles(): PDFArray | undefined { + return this.lookupMaybe(PDFName.of('AF'), PDFArray); + } + getAcroForm(): PDFAcroForm | undefined { const dict = this.AcroForm(); if (!dict) return undefined; diff --git a/src/core/structures/PDFContentStream.ts b/src/core/structures/PDFContentStream.ts index 8ba45f9e4..f81239229 100644 --- a/src/core/structures/PDFContentStream.ts +++ b/src/core/structures/PDFContentStream.ts @@ -1,10 +1,15 @@ -import PDFDict from 'src/core/objects/PDFDict'; -import PDFOperator from 'src/core/operators/PDFOperator'; -import PDFContext from 'src/core/PDFContext'; -import PDFFlateStream from 'src/core/structures/PDFFlateStream'; -import CharCodes from 'src/core/syntax/CharCodes'; +import PDFDict from '../objects/PDFDict'; +import PDFOperator from '../operators/PDFOperator'; +import PDFContext from '../PDFContext'; +import PDFFlateStream from './PDFFlateStream'; +import CharCodes from '../syntax/CharCodes'; +import { PDFClasses } from '../../api/objects'; class PDFContentStream extends PDFFlateStream { + static className = () => PDFClasses.PDFContentStream; + myClass(): PDFClasses { + return PDFClasses.PDFContentStream; + } static of = (dict: PDFDict, operators: PDFOperator[], encode = true) => new PDFContentStream(dict, operators, encode); diff --git a/src/core/structures/PDFCrossRefStream.ts b/src/core/structures/PDFCrossRefStream.ts index b1aac5a2a..4285512ed 100644 --- a/src/core/structures/PDFCrossRefStream.ts +++ b/src/core/structures/PDFCrossRefStream.ts @@ -1,9 +1,9 @@ -import PDFDict from 'src/core/objects/PDFDict'; -import PDFName from 'src/core/objects/PDFName'; -import PDFRef from 'src/core/objects/PDFRef'; -import PDFContext from 'src/core/PDFContext'; -import PDFFlateStream from 'src/core/structures/PDFFlateStream'; -import { bytesFor, Cache, reverseArray, sizeInBytes, sum } from 'src/utils'; +import PDFDict from '../objects/PDFDict'; +import PDFName from '../objects/PDFName'; +import PDFRef from '../objects/PDFRef'; +import PDFContext from '../PDFContext'; +import PDFFlateStream from './PDFFlateStream'; +import { bytesFor, Cache, reverseArray, sizeInBytes, sum } from '../../utils'; export enum EntryType { Deleted = 0, @@ -37,7 +37,6 @@ export type EntryTuple = [number, number, number]; /** * Entries should be added using the [[addDeletedEntry]], * [[addUncompressedEntry]], and [[addCompressedEntry]] methods - * **in order of ascending object number**. */ class PDFCrossRefStream extends PDFFlateStream { static create = (dict: PDFDict, encode = true) => { @@ -65,9 +64,17 @@ class PDFCrossRefStream extends PDFFlateStream { dict.set(PDFName.of('Type'), PDFName.of('XRef')); } + private appendEntry(entry: Entry) { + const eind = this.entries.findIndex( + (e) => e.ref.objectNumber > entry.ref.objectNumber, + ); + if (eind < 0 || eind > this.entries.length) this.entries.push(entry); + else this.entries.splice(eind, 0, entry); + } + addDeletedEntry(ref: PDFRef, nextFreeObjectNumber: number) { const type = EntryType.Deleted; - this.entries.push({ type, ref, nextFreeObjectNumber }); + this.appendEntry({ type, ref, nextFreeObjectNumber }); this.entryTuplesCache.invalidate(); this.maxByteWidthsCache.invalidate(); this.indexCache.invalidate(); @@ -76,7 +83,7 @@ class PDFCrossRefStream extends PDFFlateStream { addUncompressedEntry(ref: PDFRef, offset: number) { const type = EntryType.Uncompressed; - this.entries.push({ type, ref, offset }); + this.appendEntry({ type, ref, offset }); this.entryTuplesCache.invalidate(); this.maxByteWidthsCache.invalidate(); this.indexCache.invalidate(); @@ -85,7 +92,7 @@ class PDFCrossRefStream extends PDFFlateStream { addCompressedEntry(ref: PDFRef, objectStreamRef: PDFRef, index: number) { const type = EntryType.Compressed; - this.entries.push({ type, ref, objectStreamRef, index }); + this.appendEntry({ type, ref, objectStreamRef, index }); this.entryTuplesCache.invalidate(); this.maxByteWidthsCache.invalidate(); this.indexCache.invalidate(); @@ -123,7 +130,6 @@ class PDFCrossRefStream extends PDFFlateStream { value += (thirdBytes[idx] || 0).toString(2); } } - return value; } diff --git a/src/core/structures/PDFFlateStream.ts b/src/core/structures/PDFFlateStream.ts index 4ef32cb5d..9342b0d10 100644 --- a/src/core/structures/PDFFlateStream.ts +++ b/src/core/structures/PDFFlateStream.ts @@ -1,13 +1,13 @@ import pako from 'pako'; -import { MethodNotImplementedError } from 'src/core/errors'; -import PDFDict from 'src/core/objects/PDFDict'; -import PDFName from 'src/core/objects/PDFName'; -import PDFStream from 'src/core/objects/PDFStream'; -import { Cache } from 'src/utils'; +import { MethodNotImplementedError } from '../errors'; +import PDFDict from '../objects/PDFDict'; +import PDFName from '../objects/PDFName'; +import PDFStream from '../objects/PDFStream'; +import { Cache } from '../../utils'; class PDFFlateStream extends PDFStream { - protected readonly contentsCache: Cache; + protected contentsCache: Cache; protected readonly encode: boolean; constructor(dict: PDFDict, encode: boolean) { @@ -38,6 +38,10 @@ class PDFFlateStream extends PDFStream { 'getUnencodedContents', ); } + + updateContents(contents: Uint8Array): void { + this.contentsCache = Cache.populatedBy(() => contents); + } } export default PDFFlateStream; diff --git a/src/core/structures/PDFObjectStream.ts b/src/core/structures/PDFObjectStream.ts index d5b0df44c..aed30410d 100644 --- a/src/core/structures/PDFObjectStream.ts +++ b/src/core/structures/PDFObjectStream.ts @@ -1,15 +1,20 @@ -import PDFName from 'src/core/objects/PDFName'; -import PDFNumber from 'src/core/objects/PDFNumber'; -import PDFObject from 'src/core/objects/PDFObject'; -import PDFRef from 'src/core/objects/PDFRef'; -import PDFContext from 'src/core/PDFContext'; -import PDFFlateStream from 'src/core/structures/PDFFlateStream'; -import CharCodes from 'src/core/syntax/CharCodes'; -import { copyStringIntoBuffer, last } from 'src/utils'; +import PDFName from '../objects/PDFName'; +import PDFNumber from '../objects/PDFNumber'; +import PDFObject from '../objects/PDFObject'; +import PDFRef from '../objects/PDFRef'; +import PDFContext from '../PDFContext'; +import PDFFlateStream from './PDFFlateStream'; +import CharCodes from '../syntax/CharCodes'; +import { copyStringIntoBuffer, last } from '../../utils'; +import { PDFClasses } from '../../api/objects'; export type IndirectObject = [PDFRef, PDFObject]; class PDFObjectStream extends PDFFlateStream { + static className = () => PDFClasses.PDFObjectStream; + myClass(): PDFClasses { + return PDFClasses.PDFObjectStream; + } static withContextAndObjects = ( context: PDFContext, objects: IndirectObject[], diff --git a/src/core/structures/PDFPageLeaf.ts b/src/core/structures/PDFPageLeaf.ts index 0015c5965..ba3a6fcc8 100644 --- a/src/core/structures/PDFPageLeaf.ts +++ b/src/core/structures/PDFPageLeaf.ts @@ -1,14 +1,19 @@ -import PDFArray from 'src/core/objects/PDFArray'; -import PDFDict, { DictMap } from 'src/core/objects/PDFDict'; -import PDFName from 'src/core/objects/PDFName'; -import PDFNumber from 'src/core/objects/PDFNumber'; -import PDFObject from 'src/core/objects/PDFObject'; -import PDFRef from 'src/core/objects/PDFRef'; -import PDFStream from 'src/core/objects/PDFStream'; -import PDFContext from 'src/core/PDFContext'; -import PDFPageTree from 'src/core/structures/PDFPageTree'; +import { isPDFInstance, PDFClasses } from '../../api/objects'; +import PDFArray from '../objects/PDFArray'; +import PDFDict, { DictMap } from '../objects/PDFDict'; +import PDFName from '../objects/PDFName'; +import PDFNumber from '../objects/PDFNumber'; +import PDFObject from '../objects/PDFObject'; +import PDFRef from '../objects/PDFRef'; +import PDFStream from '../objects/PDFStream'; +import PDFContext from '../PDFContext'; +import PDFPageTree from './PDFPageTree'; class PDFPageLeaf extends PDFDict { + static className = () => PDFClasses.PDFPageLeaf; + myClass(): PDFClasses { + return PDFClasses.PDFPageLeaf; + } static readonly InheritableEntries = [ 'Resources', 'MediaBox', @@ -124,9 +129,9 @@ class PDFPageLeaf extends PDFDict { wrapContentStreams(startStream: PDFRef, endStream: PDFRef): boolean { const Contents = this.Contents(); - if (Contents instanceof PDFArray) { - Contents.insert(0, startStream); - Contents.push(endStream); + if (isPDFInstance(Contents, PDFClasses.PDFArray)) { + (Contents as PDFArray).insert(0, startStream); + (Contents as PDFArray).push(endStream); return true; } return false; @@ -135,6 +140,7 @@ class PDFPageLeaf extends PDFDict { addAnnot(annotRef: PDFRef): void { const { Annots } = this.normalizedEntries(); Annots.push(annotRef); + this.registerChange(); } removeAnnot(annotRef: PDFRef) { @@ -142,6 +148,7 @@ class PDFPageLeaf extends PDFDict { const index = Annots.indexOf(annotRef); if (index !== undefined) { Annots.remove(index); + this.registerChange(); } } @@ -206,7 +213,7 @@ class PDFPageLeaf extends PDFDict { const contentsRef = this.get(PDFName.Contents); const contents = this.context.lookup(contentsRef); - if (contents instanceof PDFStream) { + if (isPDFInstance(contents, PDFClasses.PDFStream)) { this.set(PDFName.Contents, context.obj([contentsRef])); } diff --git a/src/core/structures/PDFPageTree.ts b/src/core/structures/PDFPageTree.ts index a8368dcb2..2bca2bf64 100644 --- a/src/core/structures/PDFPageTree.ts +++ b/src/core/structures/PDFPageTree.ts @@ -1,15 +1,21 @@ -import PDFArray from 'src/core/objects/PDFArray'; -import PDFDict, { DictMap } from 'src/core/objects/PDFDict'; -import PDFName from 'src/core/objects/PDFName'; -import PDFNumber from 'src/core/objects/PDFNumber'; -import PDFRef from 'src/core/objects/PDFRef'; -import PDFContext from 'src/core/PDFContext'; -import PDFPageLeaf from 'src/core/structures/PDFPageLeaf'; -import { InvalidTargetIndexError, CorruptPageTreeError } from 'src/core/errors'; +import PDFArray from '../objects/PDFArray'; +import PDFDict, { DictMap } from '../objects/PDFDict'; +import PDFName from '../objects/PDFName'; +import PDFNumber from '../objects/PDFNumber'; +import PDFRef from '../objects/PDFRef'; +import PDFContext from '../PDFContext'; +import PDFPageLeaf from './PDFPageLeaf'; +import { InvalidTargetIndexError, CorruptPageTreeError } from '../errors'; +import { isPDFInstance, PDFClasses } from '../../api/objects'; export type TreeNode = PDFPageTree | PDFPageLeaf; class PDFPageTree extends PDFDict { + static className = () => PDFClasses.PDFPageTree; + myClass(): PDFClasses { + return PDFClasses.PDFPageTree; + } + static withContext = (context: PDFContext, parent?: PDFRef) => { const dict = new Map(); dict.set(PDFName.of('Type'), PDFName.of('Pages')); @@ -72,19 +78,24 @@ class PDFPageTree extends PDFDict { const kidRef = Kids.get(idx) as PDFRef; const kid = this.context.lookup(kidRef); - if (kid instanceof PDFPageTree) { - if (kid.Count().asNumber() > leafsRemainingUntilTarget) { + if (isPDFInstance(kid, PDFClasses.PDFPageTree)) { + if ( + (kid as PDFPageTree).Count().asNumber() > leafsRemainingUntilTarget + ) { // Dig in return ( - kid.insertLeafNode(leafRef, leafsRemainingUntilTarget) || kidRef + (kid as PDFPageTree).insertLeafNode( + leafRef, + leafsRemainingUntilTarget, + ) || kidRef ); } else { // Move on - leafsRemainingUntilTarget -= kid.Count().asNumber(); + leafsRemainingUntilTarget -= (kid as PDFPageTree).Count().asNumber(); } } - if (kid instanceof PDFPageLeaf) { + if (isPDFInstance(kid, PDFClasses.PDFPageLeaf)) { // Move on leafsRemainingUntilTarget -= 1; } @@ -121,19 +132,22 @@ class PDFPageTree extends PDFDict { const kidRef = Kids.get(idx) as PDFRef; const kid = this.context.lookup(kidRef); - if (kid instanceof PDFPageTree) { - if (kid.Count().asNumber() > leafsRemainingUntilTarget) { + if (isPDFInstance(kid, PDFClasses.PDFPageTree)) { + if ( + (kid as PDFPageTree).Count().asNumber() > leafsRemainingUntilTarget + ) { // Dig in - kid.removeLeafNode(leafsRemainingUntilTarget, prune); - if (prune && kid.Kids().size() === 0) Kids.remove(idx); + (kid as PDFPageTree).removeLeafNode(leafsRemainingUntilTarget, prune); + if (prune && (kid as PDFPageTree).Kids().size() === 0) + Kids.remove(idx); return; } else { // Move on - leafsRemainingUntilTarget -= kid.Count().asNumber(); + leafsRemainingUntilTarget -= (kid as PDFPageTree).Count().asNumber(); } } - if (kid instanceof PDFPageLeaf) { + if (isPDFInstance(kid, PDFClasses.PDFPageLeaf)) { if (leafsRemainingUntilTarget === 0) { // Remove page and return this.removeKid(idx); @@ -161,7 +175,8 @@ class PDFPageTree extends PDFDict { for (let idx = 0, len = Kids.size(); idx < len; idx++) { const kidRef = Kids.get(idx) as PDFRef; const kid = this.context.lookup(kidRef) as TreeNode; - if (kid instanceof PDFPageTree) kid.traverse(visitor); + if (isPDFInstance(kid, PDFClasses.PDFPageTree)) + (kid as PDFPageTree).traverse(visitor); visitor(kid, kidRef); } } @@ -181,7 +196,7 @@ class PDFPageTree extends PDFDict { const Kids = this.Kids(); const kid = Kids.lookup(kidIdx); - if (kid instanceof PDFPageLeaf) { + if (isPDFInstance(kid, PDFClasses.PDFPageLeaf)) { this.ascend((node) => { const newCount = node.Count().asNumber() - 1; node.set(PDFName.of('Count'), PDFNumber.of(newCount)); diff --git a/src/core/syntax/Delimiters.ts b/src/core/syntax/Delimiters.ts index 36642bd02..02889fac9 100644 --- a/src/core/syntax/Delimiters.ts +++ b/src/core/syntax/Delimiters.ts @@ -1,4 +1,4 @@ -import CharCodes from 'src/core/syntax/CharCodes'; +import CharCodes from './CharCodes'; export const IsDelimiter = new Uint8Array(256); diff --git a/src/core/syntax/Irregular.ts b/src/core/syntax/Irregular.ts index ea1932ba9..444e40079 100644 --- a/src/core/syntax/Irregular.ts +++ b/src/core/syntax/Irregular.ts @@ -1,6 +1,6 @@ -import CharCodes from 'src/core/syntax/CharCodes'; -import { IsDelimiter } from 'src/core/syntax/Delimiters'; -import { IsWhitespace } from 'src/core/syntax/Whitespace'; +import CharCodes from './CharCodes'; +import { IsDelimiter } from './Delimiters'; +import { IsWhitespace } from './Whitespace'; export const IsIrregular = new Uint8Array(256); diff --git a/src/core/syntax/Keywords.ts b/src/core/syntax/Keywords.ts index 12e2f957c..bc7f941bf 100644 --- a/src/core/syntax/Keywords.ts +++ b/src/core/syntax/Keywords.ts @@ -1,4 +1,4 @@ -import CharCodes from 'src/core/syntax/CharCodes'; +import CharCodes from './CharCodes'; const { Space, CarriageReturn, Newline } = CharCodes; diff --git a/src/core/syntax/Numeric.ts b/src/core/syntax/Numeric.ts index 35413ed4a..a5a3008d2 100644 --- a/src/core/syntax/Numeric.ts +++ b/src/core/syntax/Numeric.ts @@ -1,4 +1,4 @@ -import CharCodes from 'src/core/syntax/CharCodes'; +import CharCodes from './CharCodes'; export const IsDigit = new Uint8Array(256); diff --git a/src/core/syntax/Whitespace.ts b/src/core/syntax/Whitespace.ts index 4c640e641..9ba45d699 100644 --- a/src/core/syntax/Whitespace.ts +++ b/src/core/syntax/Whitespace.ts @@ -1,4 +1,4 @@ -import CharCodes from 'src/core/syntax/CharCodes'; +import CharCodes from './CharCodes'; export const IsWhitespace = new Uint8Array(256); diff --git a/src/core/writers/PDFStreamWriter.ts b/src/core/writers/PDFStreamWriter.ts index 4761f8415..ec470c97d 100644 --- a/src/core/writers/PDFStreamWriter.ts +++ b/src/core/writers/PDFStreamWriter.ts @@ -1,18 +1,24 @@ -import PDFHeader from 'src/core/document/PDFHeader'; -import PDFTrailer from 'src/core/document/PDFTrailer'; -import PDFInvalidObject from 'src/core/objects/PDFInvalidObject'; -import PDFName from 'src/core/objects/PDFName'; -import PDFNumber from 'src/core/objects/PDFNumber'; -import PDFObject from 'src/core/objects/PDFObject'; -import PDFRef from 'src/core/objects/PDFRef'; -import PDFStream from 'src/core/objects/PDFStream'; -import PDFContext from 'src/core/PDFContext'; -import PDFCrossRefStream from 'src/core/structures/PDFCrossRefStream'; -import PDFObjectStream from 'src/core/structures/PDFObjectStream'; -import PDFWriter from 'src/core/writers/PDFWriter'; -import { last, waitForTick } from 'src/utils'; +import { defaultDocumentSnapshot } from '../../api/snapshot'; +import type { DocumentSnapshot } from '../../api/snapshot'; +import PDFHeader from '../document/PDFHeader'; +import PDFTrailer from '../document/PDFTrailer'; +import PDFName from '../objects/PDFName'; +import PDFNumber from '../objects/PDFNumber'; +import PDFObject from '../objects/PDFObject'; +import PDFRef from '../objects/PDFRef'; +import PDFContext from '../PDFContext'; +import PDFCrossRefStream from '../structures/PDFCrossRefStream'; +import PDFObjectStream from '../structures/PDFObjectStream'; +import PDFWriter from '../writers/PDFWriter'; +import { last, waitForTick } from '../../utils'; +import PDFDict from '../objects/PDFDict'; +import { isPDFInstance, PDFClasses } from '../../api/objects'; class PDFStreamWriter extends PDFWriter { + static className = () => PDFClasses.PDFStreamWriter; + myClass(): PDFClasses { + return PDFClasses.PDFStreamWriter; + } static forContext = ( context: PDFContext, objectsPerTick: number, @@ -22,6 +28,22 @@ class PDFStreamWriter extends PDFWriter { new PDFStreamWriter( context, objectsPerTick, + defaultDocumentSnapshot, + encodeStreams, + objectsPerStream, + ); + + static forContextWithSnapshot = ( + context: PDFContext, + objectsPerTick: number, + snapshot: DocumentSnapshot, + encodeStreams = true, + objectsPerStream = 50, + ) => + new PDFStreamWriter( + context, + objectsPerTick, + snapshot, encodeStreams, objectsPerStream, ); @@ -32,21 +54,27 @@ class PDFStreamWriter extends PDFWriter { private constructor( context: PDFContext, objectsPerTick: number, + snapshot: DocumentSnapshot, encodeStreams: boolean, objectsPerStream: number, ) { - super(context, objectsPerTick); + super(context, objectsPerTick, snapshot); this.encodeStreams = encodeStreams; this.objectsPerStream = objectsPerStream; } - protected async computeBufferSize() { - let objectNumber = this.context.largestObjectNumber + 1; - + // the process of saving uses references numbers, and creates a new indirect object, that has to be deleted after saving + private _refToDeleteAfterSave = 0; + protected async computeBufferSize(incremental: boolean) { + this._refToDeleteAfterSave = 0; const header = PDFHeader.forVersion(1, 7); - let size = header.sizeInBytes() + 2; + let size = this.snapshot.pdfSize; + if (!incremental) { + size += header.sizeInBytes() + 1; + } + size += 1; const xrefStream = PDFCrossRefStream.create( this.createTrailerDict(), @@ -57,19 +85,30 @@ class PDFStreamWriter extends PDFWriter { const compressedObjects: [PDFRef, PDFObject][][] = []; const objectStreamRefs: PDFRef[] = []; + const security = this.context.security; + const indirectObjects = this.context.enumerateIndirectObjects(); for (let idx = 0, len = indirectObjects.length; idx < len; idx++) { const indirectObject = indirectObjects[idx]; const [ref, object] = indirectObject; + if (!this.shouldSave(incremental, ref.objectNumber, indirectObjects)) { + continue; + } const shouldNotCompress = ref === this.context.trailerInfo.Encrypt || - object instanceof PDFStream || - object instanceof PDFInvalidObject || - ref.generationNumber !== 0; + isPDFInstance(object, PDFClasses.PDFStream) || + isPDFInstance(object, PDFClasses.PDFInvalidObject) || + isPDFInstance(object, PDFClasses.PDFCatalog) || + isPDFInstance(object, PDFClasses.PDFPageTree) || + isPDFInstance(object, PDFClasses.PDFPageLeaf) || + ref.generationNumber !== 0 || + (isPDFInstance(object, PDFClasses.PDFDict) && + (object as PDFDict).lookup(PDFName.of('Type')) === PDFName.of('Sig')); if (shouldNotCompress) { uncompressedObjects.push(indirectObject); + if (security) this.encrypt(ref, object, security); xrefStream.addUncompressedEntry(ref, size); size += this.computeIndirectObjectSize(indirectObject); if (this.shouldWaitForTick(1)) await waitForTick(); @@ -79,7 +118,8 @@ class PDFStreamWriter extends PDFWriter { if (!chunk || chunk.length % this.objectsPerStream === 0) { chunk = []; compressedObjects.push(chunk); - objectStreamRef = PDFRef.of(objectNumber++); + objectStreamRef = this.context.nextRef(); + this._refToDeleteAfterSave += 1; objectStreamRefs.push(objectStreamRef); } xrefStream.addCompressedEntry(ref, objectStreamRef, chunk.length); @@ -96,6 +136,9 @@ class PDFStreamWriter extends PDFWriter { chunk, this.encodeStreams, ); + this.context.assign(ref, objectStream); + + if (security) this.encrypt(ref, objectStream, security); xrefStream.addUncompressedEntry(ref, size); size += this.computeIndirectObjectSize([ref, objectStream]); @@ -105,8 +148,18 @@ class PDFStreamWriter extends PDFWriter { if (this.shouldWaitForTick(chunk.length)) await waitForTick(); } - const xrefStreamRef = PDFRef.of(objectNumber++); - xrefStream.dict.set(PDFName.of('Size'), PDFNumber.of(objectNumber)); + const xrefStreamRef = this.context.nextRef(); + this._refToDeleteAfterSave += 1; + xrefStream.dict.set( + PDFName.of('Size'), + PDFNumber.of(this.context.largestObjectNumber + 1), + ); + if (this.snapshot.prevStartXRef) { + xrefStream.dict.set( + PDFName.of('Prev'), + PDFNumber.of(this.snapshot.prevStartXRef), + ); + } xrefStream.addUncompressedEntry(xrefStreamRef, size); const xrefOffset = size; size += this.computeIndirectObjectSize([xrefStreamRef, xrefStream]); @@ -115,9 +168,19 @@ class PDFStreamWriter extends PDFWriter { const trailer = PDFTrailer.forLastCrossRefSectionOffset(xrefOffset); size += trailer.sizeInBytes(); + size -= this.snapshot.pdfSize; return { size, header, indirectObjects: uncompressedObjects, trailer }; } + + override async serializeToBuffer(): Promise { + const buffer = await super.serializeToBuffer(); + // delete xref stream created for saving + this.context.delete(PDFRef.of(this.context.largestObjectNumber - 1)); + // fix largestObjectNumbering + this.context.largestObjectNumber -= this._refToDeleteAfterSave; + return buffer; + } } export default PDFStreamWriter; diff --git a/src/core/writers/PDFWriter.ts b/src/core/writers/PDFWriter.ts index b9b21457b..276d863be 100644 --- a/src/core/writers/PDFWriter.ts +++ b/src/core/writers/PDFWriter.ts @@ -1,14 +1,22 @@ -import PDFCrossRefSection from 'src/core/document/PDFCrossRefSection'; -import PDFHeader from 'src/core/document/PDFHeader'; -import PDFTrailer from 'src/core/document/PDFTrailer'; -import PDFTrailerDict from 'src/core/document/PDFTrailerDict'; -import PDFDict from 'src/core/objects/PDFDict'; -import PDFObject from 'src/core/objects/PDFObject'; -import PDFRef from 'src/core/objects/PDFRef'; -import PDFContext from 'src/core/PDFContext'; -import PDFObjectStream from 'src/core/structures/PDFObjectStream'; -import CharCodes from 'src/core/syntax/CharCodes'; -import { copyStringIntoBuffer, waitForTick } from 'src/utils'; +import { defaultDocumentSnapshot } from '../../api/snapshot'; +import type { DocumentSnapshot } from '../../api/snapshot'; +import PDFCrossRefSection from '../document/PDFCrossRefSection'; +import PDFHeader from '../document/PDFHeader'; +import PDFTrailer from '../document/PDFTrailer'; +import PDFTrailerDict from '../document/PDFTrailerDict'; +import PDFDict from '../objects/PDFDict'; +import PDFObject from '../objects/PDFObject'; +import PDFRef from '../objects/PDFRef'; +import PDFContext from '../PDFContext'; +import PDFObjectStream from '../structures/PDFObjectStream'; +import CharCodes from '../syntax/CharCodes'; +import { copyStringIntoBuffer, waitForTick } from '../../utils'; +import PDFNumber from '../objects/PDFNumber'; +import PDFSecurity from '../security/PDFSecurity'; +import PDFStream from '../objects/PDFStream'; +import PDFName from '../objects/PDFName'; +import PDFRawStream from '../objects/PDFRawStream'; +import { isPDFInstance, PDFClasses } from '../../api/objects'; export interface SerializationInfo { size: number; @@ -20,39 +28,116 @@ export interface SerializationInfo { } class PDFWriter { + static className = () => PDFClasses.PDFWriter; + myClass(): PDFClasses { + return PDFClasses.PDFWriter; + } static forContext = (context: PDFContext, objectsPerTick: number) => - new PDFWriter(context, objectsPerTick); + new PDFWriter(context, objectsPerTick, defaultDocumentSnapshot); + + static forContextWithSnapshot = ( + context: PDFContext, + objectsPerTick: number, + snapshot: DocumentSnapshot, + ) => new PDFWriter(context, objectsPerTick, snapshot); protected readonly context: PDFContext; protected readonly objectsPerTick: number; + protected readonly snapshot: DocumentSnapshot; private parsedObjects = 0; - protected constructor(context: PDFContext, objectsPerTick: number) { + protected constructor( + context: PDFContext, + objectsPerTick: number, + snapshot: DocumentSnapshot, + ) { this.context = context; this.objectsPerTick = objectsPerTick; + this.snapshot = snapshot; + } + + /** + * If PDF has an XRef Stream, then the last object will be probably be skipped on saving. + * If that's the case, this property will have that object number, and the PDF /Size can + * be corrected, to be accurate. + */ + protected _largestSkippedObjectNum: number = 0; + + /** + * Used to check wheter an object should be saved or not, preserves the object number of the + * last XRef Stream object, if there is one. + */ + protected _lastXRefObjectNumber: number = 0; + /** + * For incremental saves, defers the decision to the snapshot. + * For full saves, checks that the object is not the last XRef stream object. + * @param {boolean} incremental If making an incremental save, or a full save of the PDF + * @param {number} objNum Object number + * @param {[PDFRef, PDFObject][]} objects List of objects that form the PDF + * @returns {boolean} whether the object should be saved or not + */ + protected shouldSave( + incremental: boolean, + objNum: number, + objects: [PDFRef, PDFObject][], + ): boolean { + let should = true; + if (incremental) { + should = this.snapshot.shouldSave(objNum); + } else { + // only the last XRef Stream will be regenerated on save + if (!this._lastXRefObjectNumber) { + // if no XRef Stream, then nothing should be skipped + // if we are adding a XRef Stream, then its number if this.context.largestObjectNumber + 1, so adding 10 ensures we won't skip current generade XRref Stream + this._lastXRefObjectNumber = this.context.largestObjectNumber + 10; + const checkWatermark = this._lastXRefObjectNumber - 20; // max number of objects in the final part of the PDF to check + // search the last XRef Stream, if there is one, objects are expected to be in object number order + for (let idx = objects.length - 1; idx > 0; idx--) { + // if not in last 'rangeToCheck' objects, there is none that should be skipped, most probably a linearized PDF, or without XRef Streams + if (objects[idx][0].objectNumber < checkWatermark) break; + const object = objects[idx][1]; + if ( + isPDFInstance(object, PDFClasses.PDFRawStream) && + (object as PDFRawStream).dict.lookup(PDFName.of('Type')) === + PDFName.of('XRef') + ) { + this._lastXRefObjectNumber = objects[idx][0].objectNumber; + break; + } + } + } + should = objNum !== this._lastXRefObjectNumber; + } + if (!should && this._largestSkippedObjectNum < objNum) + this._largestSkippedObjectNum = objNum; + return should; } async serializeToBuffer(): Promise { - const { - size, - header, - indirectObjects, - xref, - trailerDict, - trailer, - } = await this.computeBufferSize(); + const incremental = !isPDFInstance( + this.snapshot, + PDFClasses.DefaultDocumentSnapshot, + ); + const { size, header, indirectObjects, xref, trailerDict, trailer } = + await this.computeBufferSize(incremental); let offset = 0; const buffer = new Uint8Array(size); - offset += header.copyBytesInto(buffer, offset); - buffer[offset++] = CharCodes.Newline; + if (!incremental) { + offset += header.copyBytesInto(buffer, offset); + buffer[offset++] = CharCodes.Newline; + } buffer[offset++] = CharCodes.Newline; for (let idx = 0, len = indirectObjects.length; idx < len; idx++) { const [ref, object] = indirectObjects[idx]; + if (!this.shouldSave(incremental, ref.objectNumber, indirectObjects)) { + continue; + } + const objectNumber = String(ref.objectNumber); offset += copyStringIntoBuffer(objectNumber, buffer, offset); buffer[offset++] = CharCodes.Space; @@ -78,8 +163,9 @@ class PDFWriter { buffer[offset++] = CharCodes.Newline; buffer[offset++] = CharCodes.Newline; - const n = - object instanceof PDFObjectStream ? object.getObjectsCount() : 1; + const n = isPDFInstance(object, PDFClasses.PDFObjectStream) + ? (object as PDFObjectStream).getObjectsCount() + : 1; if (this.shouldWaitForTick(n)) await waitForTick(); } @@ -108,45 +194,94 @@ class PDFWriter { return refSize + objectSize; } - protected createTrailerDict(): PDFDict { + protected createTrailerDict(prevStartXRef?: number): PDFDict { + /** + * if last object (XRef Stream) is not in the output, then size is one less. + * An XRef Stream object should always be the largest object number in PDF + */ + const size = + this.context.largestObjectNumber + + (this._largestSkippedObjectNum === this.context.largestObjectNumber + ? 0 + : 1); return this.context.obj({ - Size: this.context.largestObjectNumber + 1, + Size: size, Root: this.context.trailerInfo.Root, Encrypt: this.context.trailerInfo.Encrypt, Info: this.context.trailerInfo.Info, ID: this.context.trailerInfo.ID, + Prev: prevStartXRef ? PDFNumber.of(prevStartXRef) : undefined, }); } - protected async computeBufferSize(): Promise { + protected async computeBufferSize( + incremental: boolean, + ): Promise { + this._largestSkippedObjectNum = 0; + this._lastXRefObjectNumber = 0; const header = PDFHeader.forVersion(1, 7); - let size = header.sizeInBytes() + 2; + let size = this.snapshot.pdfSize; + if (!incremental) { + size += header.sizeInBytes() + 1; + } + size += 1; const xref = PDFCrossRefSection.create(); + const security = this.context.security; + const indirectObjects = this.context.enumerateIndirectObjects(); for (let idx = 0, len = indirectObjects.length; idx < len; idx++) { const indirectObject = indirectObjects[idx]; - const [ref] = indirectObject; + const [ref, object] = indirectObject; + if (!this.shouldSave(incremental, ref.objectNumber, indirectObjects)) + continue; + if (security) this.encrypt(ref, object, security); xref.addEntry(ref, size); size += this.computeIndirectObjectSize(indirectObject); if (this.shouldWaitForTick(1)) await waitForTick(); } + // deleted objects + for (let idx = 0; idx < this.snapshot.deletedCount; idx++) { + const dref = this.snapshot.deletedRef(idx); + if (!dref) break; + const nextdref = this.snapshot.deletedRef(idx + 1); + // add 1 to generation number for deleted ref + xref.addDeletedEntry( + PDFRef.of(dref.objectNumber, dref.generationNumber + 1), + nextdref ? nextdref.objectNumber : 0, + ); + } const xrefOffset = size; size += xref.sizeInBytes() + 1; // '\n' - const trailerDict = PDFTrailerDict.of(this.createTrailerDict()); + const trailerDict = PDFTrailerDict.of( + this.createTrailerDict(this.snapshot.prevStartXRef), + ); size += trailerDict.sizeInBytes() + 2; // '\n\n' const trailer = PDFTrailer.forLastCrossRefSectionOffset(xrefOffset); size += trailer.sizeInBytes(); + size -= this.snapshot.pdfSize; return { size, header, indirectObjects, xref, trailerDict, trailer }; } + protected encrypt(ref: PDFRef, object: PDFObject, security: PDFSecurity) { + if (isPDFInstance(object, PDFClasses.PDFStream)) { + const encryptFn = security.getEncryptFn( + ref.objectNumber, + ref.generationNumber, + ); + const unencryptedContents = (object as PDFStream).getContents(); + const encryptedContents = encryptFn(unencryptedContents); + (object as PDFStream).updateContents(encryptedContents); + } + } + protected shouldWaitForTick = (n: number) => { this.parsedObjects += n; return this.parsedObjects % this.objectsPerTick === 0; diff --git a/src/index.ts b/src/index.ts index ef8785539..c87b6dceb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -export * from 'src/api/index'; -export * from 'src/core/index'; -export * from 'src/types/index'; -export * from 'src/utils/index'; +export * from './api'; +export * from './core'; +export * from './types'; +export * from './utils'; diff --git a/src/types/index.ts b/src/types/index.ts index 74861daca..40ff250a9 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1 +1,38 @@ -export { TransformationMatrix } from 'src/types/matrix'; +import Arc from '../utils/elements/Arc'; +import Circle from '../utils/elements/Circle'; +import Ellipse from '../utils/elements/Ellipse'; +import Line from '../utils/elements/Line'; +import Plot from '../utils/elements/Plot'; +import Point from '../utils/elements/Point'; +import Rectangle from '../utils/elements/Rectangle'; +import Segment from '../utils/elements/Segment'; +export { TransformationMatrix } from './matrix'; + +export type Size = { + width: number; + height: number; +}; + +export type Coordinates = { + x: number; + y: number; +}; + +export type GraphicElement = + | Arc + | Circle + | Ellipse + | Line + | Plot + | Point + | Rectangle + | Segment; + +export type Space = { + topLeft: Coordinates; + topRight: Coordinates; + bottomRight: Coordinates; + bottomLeft: Coordinates; +}; + +export type LinkElement = Rectangle | Ellipse; diff --git a/src/utils/arrays.ts b/src/utils/arrays.ts index 954f40049..f7a1bc1a4 100644 --- a/src/utils/arrays.ts +++ b/src/utils/arrays.ts @@ -1,5 +1,5 @@ -import { decodeFromBase64DataUri } from 'src/utils/base64'; -import { charFromCode } from 'src/utils/strings'; +import { decodeFromBase64DataUri } from './base64'; +import { charFromCode } from './strings'; export const last = (array: T[]): T => array[array.length - 1]; @@ -84,6 +84,18 @@ export const sortedUniq = (array: T[], indexer: (elem: T) => any): T[] => { return uniq; }; +export const isArrayEqual = (arr1: ArrayLike, arr2: ArrayLike) => { + if (arr1.length !== arr2.length) { + return false; + } + for (let i = 0, ii = arr1.length; i < ii; i++) { + if (arr1[i] !== arr2[i]) { + return false; + } + } + return true; +}; + // Arrays and TypedArrays in JS both have .reverse() methods, which would seem // to negate the need for this function. However, not all runtimes support this // method (e.g. React Native). This function compensates for that fact. @@ -144,3 +156,22 @@ export const toUint8Array = (input: string | ArrayBuffer | Uint8Array) => { ); } }; + +// Precompute hex octets for best performance +// Credit: https://stackoverflow.com/questions/40031688/javascript-arraybuffer-to-hex/40031979#40031979 + +const byteToHex: string[] = []; + +for (let byte = 0x00; byte <= 0xff; ++byte) { + byteToHex[byte] = byte.toString(16).padStart(2, '0'); +} + +export const byteArrayToHexString = (array: Uint8Array) => { + const hexOctets = new Array(array.length); + + for (let idx = 0; idx < array.length; ++idx) { + hexOctets[idx] = byteToHex[array[idx]]; + } + + return hexOctets.join(''); +}; diff --git a/src/utils/base64.ts b/src/utils/base64.ts index c862106cd..ede48435e 100644 --- a/src/utils/base64.ts +++ b/src/utils/base64.ts @@ -73,7 +73,8 @@ export const decodeFromBase64 = (base64: string): Uint8Array => { // This regex is designed to be as flexible as possible. It will parse certain // invalid data URIs. -const DATA_URI_PREFIX_REGEX = /^(data)?:?([\w\/\+]+)?;?(charset=[\w-]+|base64)?.*,/i; +const DATA_URI_PREFIX_REGEX = + /^(data)?:?([\w/+]+)?;?(charset=[\w-]+|base64)?.*,/i; /** * If the `dataUri` input is a data URI, then the data URI prefix must not be diff --git a/src/utils/elements/Arc.ts b/src/utils/elements/Arc.ts new file mode 100644 index 000000000..f7a8eb852 --- /dev/null +++ b/src/utils/elements/Arc.ts @@ -0,0 +1,112 @@ +import { isPDFInstance, PDFClasses } from '../../api/objects'; +import { angleABC, distance, distanceCoords, rotate, vector } from '../maths'; + +import Circle from './Circle'; +import GraphElement from './GraphElement'; +import Point from './Point'; + +export default class Arc extends GraphElement { + static className = () => PDFClasses.Arc; + myClass(): PDFClasses { + return PDFClasses.Arc; + } + O: Point; + A: Point; + B: Point; + /** Last sweep. Used to deduce the angle orientation */ + lastSweep: number; + + constructor( + O: Point = new Point(), + A: Point = new Point(), + B: Point = new Point(), + lastSweep = 0, + ) { + super(); + this.O = O; + this.A = A; + this.B = B; + this.lastSweep = lastSweep; + } + + center() { + return this.O; + } + + origin() { + return this.A; + } + + destination() { + return this.getCircle().orthoProjection(this.B); + } + + sweep() { + this.lastSweep = angleABC( + this.origin(), + this.center(), + this.destination(), + this.lastSweep, + ); + return this.lastSweep; + } + + ray() { + return distance(this.center(), this.origin()); + } + + isEqual(element: GraphElement): boolean { + if (!isPDFInstance(element, PDFClasses.Arc)) return false; + const dest = this.destination(); + const o = this.origin(); + const eDest = (element as Arc).destination(); + const eO = (element as Arc).origin(); + return ( + this.getCircle().isEqual((element as Arc).getCircle()) && + ((dest.isEqual(eDest) && o.isEqual(eO)) || + (dest.isEqual(eO) && o.isEqual(eDest))) + ); + } + + getCircle() { + const circle = new Circle(this.center(), this.ray()); + return circle; + } + + originVect() { + return vector(this.center(), this.origin()); + } + + middle() { + const halfSweep = this.sweep() / 2; + const mid = this.center().plus( + rotate(vector(this.center(), this.origin()), halfSweep), + ); + return mid; + } + + includes(P: Point) { + // As angles are returned between -π and π, we need the middle of the arc + return ( + this.getCircle().includes(P) && + Math.abs(angleABC(this.middle(), this.center(), P)) <= + Math.abs(this.sweep() / 2) + ); + } + + orthoProjection(P: Point) { + const H = this.getCircle().orthoProjection(P); + if (this.includes(H)) return H; + else { + const origin = this.origin().toCoords(); + const destination = this.destination().toCoords(); + // Returns the closest between origin and destination + const coords = + distanceCoords(H.toCoords(), origin) < + distanceCoords(H.toCoords(), destination) + ? origin + : destination; + return new Point(coords); + } + } +} diff --git a/src/utils/elements/Circle.ts b/src/utils/elements/Circle.ts new file mode 100644 index 000000000..9e40d034d --- /dev/null +++ b/src/utils/elements/Circle.ts @@ -0,0 +1,60 @@ +import { isPDFInstance, PDFClasses } from '../../api/objects'; +import { + distance, + distanceCoords, + isEqual, + minus, + plus, + times, + unitVector, +} from '../maths'; + +import GraphElement from './GraphElement'; +import Point from './Point'; +export default class Circle extends GraphElement { + static className = () => PDFClasses.Circle; + myClass(): PDFClasses { + return PDFClasses.Circle; + } + O: Point; + r: number; + + constructor(O: Point = new Point(), r = 1) { + super(); + this.O = O; + this.r = r; + } + + ray() { + return this.r; + } + + center() { + return this.O; + } + + /** This is used to standardize type Circle | Arc */ + getCircle() { + return this; + } + + isEqual(element: GraphElement): boolean { + return ( + isPDFInstance(element, PDFClasses.Circle) && + this.center().isEqual((element as Circle).center()) && + isEqual(this.ray(), (element as Circle).ray()) + ); + } + + includes(P: Point) { + return isEqual(distance(this.center(), P), this.ray()); + } + + orthoProjection(P: Point) { + const center = this.center().toCoords(); + const coords = P.toCoords(); + if (distanceCoords(coords, center) < this.ray()) return P; + const vect = times(unitVector(minus(coords, center)), this.ray()); + return new Point(plus(center, vect)); + } +} diff --git a/src/utils/elements/Ellipse.ts b/src/utils/elements/Ellipse.ts new file mode 100644 index 000000000..8e2036601 --- /dev/null +++ b/src/utils/elements/Ellipse.ts @@ -0,0 +1,140 @@ +import { isPDFInstance, PDFClasses } from '../../api/objects'; +import { Size } from '../../types'; +import { + angle, + distance, + isEqual, + orientation, + orthogonal, + times, + unitVector, + vector, +} from '../maths'; + +import GraphElement from './GraphElement'; +import Point from './Point'; +import Segment from './Segment'; + +export default class Ellipse extends GraphElement { + static className = () => PDFClasses.Ellipse; + myClass(): PDFClasses { + return PDFClasses.Ellipse; + } + A: Point; + B: Point; + C: Point; + + constructor( + A: Point = new Point(), + B: Point = new Point(), + C: Point = new Point(), + ) { + super(); + this.A = A; + this.B = B; + this.C = C; + } + + center(): Point { + const center = this.axis().middle(); + return center; + } + + axis(): Segment { + const axis = new Segment(this.A, this.B); + return axis; + } + + a(): number { + const axis = this.axis(); + return Math.max(axis.length() / 2, axis.distance(this.C)); + } + + b(): number { + const axis = this.axis(); + return Math.min(axis.length() / 2, axis.distance(this.C)); + } + + rotation(): number { + const axis = this.axis(); + return axis.length() / 2 > axis.distance(this.C) + ? orientation(axis.dirVect()) + : orientation(orthogonal(axis.dirVect())); + } + + getSize(): Size { + return { width: 2 * this.a(), height: 2 * this.b() }; + } + + isEqual(element: GraphElement): boolean { + if (!isPDFInstance(element, PDFClasses.Ellipse)) return false; + const a = this.a(); + const b = this.b(); + const rotation = this.rotation(); + const eltA = (element as Ellipse).a(); + const eltB = (element as Ellipse).b(); + const eltRotation = (element as Ellipse).rotation(); + // If the main axis is the same on both ellipse + if (eltA < eltB === a < b) { + // The rotation is equivalent module PI as the element is symetrical + return ( + isEqual(eltA, a) && + isEqual(eltB, b) && + isEqual( + rotation + (Math.PI % Math.PI), + eltRotation + (Math.PI % Math.PI), + ) + ); + } + // If the small axis is different + else { + // We add a rotation of PI / 2 to emulate the fact that the main axis are actually orthogonal + return ( + isEqual(eltA, b) && + isEqual(eltB, a) && + isEqual( + rotation + (Math.PI % Math.PI), + eltRotation + (((3 * Math.PI) / 2) % Math.PI), + ) + ); + } + } + + includes(P: Point) { + const { x, y } = P.toCoords(); + const { x: cx, y: cy } = this.center().toCoords(); + const teta = this.rotation(); + return isEqual( + Math.pow( + ((x - cx) * Math.cos(teta) + (y - cy) * Math.sin(teta)) / this.a(), + 2, + ) + + Math.pow( + ((x - cx) * Math.sin(teta) - (y - cy) * Math.cos(teta)) / this.b(), + 2, + ), + 1, + ); + } + + orthoProjection(P: Point) { + // We will consider that the parametric projection is a correct approximation of the distance for the current case, even if it is not orthogonal + const C = this.center(); + const axis = this.axis(); + const CP = vector(C, P); + const teta = angle(axis.dirVect(), vector(C, P)); + const ray = this.polarRay(teta); + if (distance(P, this.center()) < ray) return P; + const vect = times(unitVector(CP), ray); + return new Point(this.center().plus(vect).toCoords()); + } + + polarRay(teta: number) { + const a = this.a(); + const b = this.b(); + const excentricity = Math.sqrt(Math.abs(a * a - b * b)) / Math.max(a, b); + return ( + Math.min(a, b) / Math.sqrt(1 - Math.pow(excentricity * Math.cos(teta), 2)) + ); + } +} diff --git a/src/utils/elements/GraphElement.ts b/src/utils/elements/GraphElement.ts new file mode 100644 index 000000000..e5979b17a --- /dev/null +++ b/src/utils/elements/GraphElement.ts @@ -0,0 +1,17 @@ +import { PDFClasses } from '../../api/objects'; +import { distance } from '../maths'; + +import Point from './Point'; + +export default abstract class GraphElement { + abstract myClass(): PDFClasses; + + abstract isEqual(element: GraphElement): boolean; + + abstract orthoProjection(P: Point): Point; + + distance(P: Point) { + const H = this.orthoProjection(P); + return distance(H, P); + } +} diff --git a/src/utils/elements/Line.ts b/src/utils/elements/Line.ts new file mode 100644 index 000000000..239084d10 --- /dev/null +++ b/src/utils/elements/Line.ts @@ -0,0 +1,93 @@ +import { isPDFInstance, PDFClasses } from '../../api/objects'; +import { Coordinates } from '../../types'; +import { intersectionLine } from '../intersections'; +import { isColinear, isEqual, orthogonal, vector } from '../maths'; + +import GraphElement from './GraphElement'; +import Point from './Point'; + +export default class Line extends GraphElement { + static className = () => PDFClasses.Line; + myClass(): PDFClasses { + return PDFClasses.Line; + } + origin(): Point { + return this.A; + } + + dirVect(): Coordinates { + return vector(this.A, this.B); + } + + A: Point; + B: Point; + + constructor(A: Point = new Point(), B: Point = new Point()) { + super(); + this.A = A; + this.B = B; + } + + /** Line equation */ + y(x: number) { + const a = this.a(); + const b = this.b(); + return a * x + b; + } + + /** The slope */ + a() { + const dirVect = this.dirVect(); + return dirVect.y / dirVect.x; + } + + /** Origin y coordinate */ + b() { + const O = this.origin().toCoords(); + const a = this.a(); + return O.y - a * O.x; + } + + isEqual(element: GraphElement): boolean { + const vect = this.dirVect(); + return ( + isPDFInstance(element, PDFClasses.Line) && + isColinear(vect, (element as Line).dirVect()) && + (isEqual(vect.x, 0) + ? // We need to take care of the case of the vertical line + isEqual( + this.origin().toCoords().x, + (element as Line).origin().toCoords().x, + ) + : isEqual(this.b(), (element as Line).b())) + ); + } + + /** Reversed line equation */ + x(y: number) { + const dirVect = this.dirVect(); + return ((y - this.b()) * dirVect.x) / dirVect.y; + } + + includes(P: Point) { + const { x, y } = P.toCoords(); + const vect = this.dirVect(); + return isEqual(vect.x, 0) + ? isEqual(this.origin().toCoords().x, x) + : isEqual(this.y(x), y); + } + + /** This is used to standarsize type Segment | HalfLine | Line */ + getLine() { + const line = new Line(this.origin(), this.B); + return line; + } + + orthoProjection(P: Point): Point { + const vectOrtho = orthogonal(this.dirVect()); + const A = new Point(P.toCoords()); + const ortho = new Line(A, A.plus(vectOrtho)); + const H = intersectionLine(this, ortho)[0]; + return new Point(H); + } +} diff --git a/src/utils/elements/Plot.ts b/src/utils/elements/Plot.ts new file mode 100644 index 000000000..802177adc --- /dev/null +++ b/src/utils/elements/Plot.ts @@ -0,0 +1,57 @@ +import { isPDFInstance, PDFClasses } from '../../api/objects'; +import { Coordinates } from '../../types'; +import { plus } from '../maths'; + +import GraphElement from './GraphElement'; +import Point from './Point'; +import Segment from './Segment'; +export default class Plot extends GraphElement { + static className = () => PDFClasses.Plot; + myClass(): PDFClasses { + return PDFClasses.Plot; + } + points: Coordinates[]; + + constructor(points: Coordinates[] = []) { + super(); + this.points = points; + } + + getPoints() { + return [...this.points]; + } + + translate(translationVector: Coordinates) { + this.points = this.points.map((point) => plus(point, translationVector)); + } + + isEqual(element: GraphElement): boolean { + if (!isPDFInstance(element, PDFClasses.Plot)) return false; + const points = this.getPoints().map((coord) => new Point(coord)); + const points2 = (element as Plot) + .getPoints() + .map((coord) => new Point(coord)); + return ( + points.every((point, i) => point.isEqual(points2[i])) || + points.reverse().every((point, i) => point.isEqual(points2[i])) + ); + } + + orthoProjection(P: Point) { + const points = this.getPoints(); + const orthos = points + .slice(0, -1) + .map((pt, i) => new Segment(new Point(pt), new Point(points[i + 1]))) + .map((seg) => seg.orthoProjection(P)); + let min = Number.POSITIVE_INFINITY; + let closest: Point = new Point(points[0]); + orthos.forEach((ortho) => { + const d = ortho.distance(P); + if (d < min) { + min = d; + closest = ortho; + } + }); + return closest; + } +} diff --git a/src/utils/elements/Point.ts b/src/utils/elements/Point.ts new file mode 100644 index 000000000..439c937dd --- /dev/null +++ b/src/utils/elements/Point.ts @@ -0,0 +1,42 @@ +import { isPDFInstance, PDFClasses } from '../../api/objects'; +import type { Coordinates } from '../../types'; + +import { isEqual, plus } from '../maths'; +import GraphElement from './GraphElement'; + +export default class Point extends GraphElement { + static className = () => PDFClasses.Point; + myClass(): PDFClasses { + return PDFClasses.Point; + } + static type = 'PointFixed'; + + x: number; + y: number; + + constructor(coords = { x: 0, y: 0 }) { + super(); + this.x = coords.x; + this.y = coords.y; + } + + toCoords() { + return { x: this.x, y: this.y }; + } + + isEqual(element: GraphElement): boolean { + if (!isPDFInstance(element, PDFClasses.Point)) return false; + const A = this.toCoords(); + const B = (element as Point).toCoords(); + return isEqual(A.x, B.x) && isEqual(A.y, B.y); + } + + orthoProjection() { + return new Point(this.toCoords()); + } + + plus(vect: Coordinates) { + const P = new Point(plus(this.toCoords(), vect)); + return P; + } +} diff --git a/src/utils/elements/Rectangle.ts b/src/utils/elements/Rectangle.ts new file mode 100644 index 000000000..dfa25706d --- /dev/null +++ b/src/utils/elements/Rectangle.ts @@ -0,0 +1,70 @@ +import { isPDFInstance, PDFClasses } from '../../api/objects'; +import GraphElement from './GraphElement'; +import Point from './Point'; +import Segment from './Segment'; + +export default class Rectangle extends GraphElement { + static className = () => PDFClasses.Rectangle; + myClass(): PDFClasses { + return PDFClasses.Rectangle; + } + static type = 'Rectangle'; + start: Point; + end: Point; + constructor(start: Point = new Point(), end: Point = new Point()) { + super(); + this.start = start; + this.end = end; + } + + getSize() { + const start = this.start.toCoords(); + const end = this.end.toCoords(); + return { + width: Math.abs(start.x - end.x), + height: Math.abs(start.y - end.y), + }; + } + + getCoords() { + const start = this.start.toCoords(); + const end = this.end.toCoords(); + return { + x: Math.min(start.x, end.x), + y: Math.max(start.y, end.y), + }; + } + + getStart() { + const start = new Point(this.getCoords()); + return start; + } + + getEnd() { + const { width, height } = this.getSize(); + const end = new Point(this.getStart()).plus({ x: width, y: -height }); + return end; + } + + center() { + const center = new Segment(this.getStart(), this.getEnd()).middle(); + return center; + } + + isEqual(element: GraphElement): boolean { + return ( + isPDFInstance(element, PDFClasses.Rectangle) && + this.getStart().isEqual((element as Rectangle).getStart()) && + this.getEnd().isEqual((element as Rectangle).getEnd()) + ); + } + + orthoProjection(P: Point) { + const { x, y } = this.getCoords(); + const end = this.getEnd().toCoords(); + const { x: Px, y: Py } = P.toCoords(); + const Hx = Px < x ? x : Px > end.x ? end.x : Px; + const Hy = Py > y ? y : Py < end.y ? end.y : Py; + return new Point({ x: Hx, y: Hy }); + } +} diff --git a/src/utils/elements/Segment.ts b/src/utils/elements/Segment.ts new file mode 100644 index 000000000..75bbd3063 --- /dev/null +++ b/src/utils/elements/Segment.ts @@ -0,0 +1,96 @@ +import { isPDFInstance, PDFClasses } from '../../api/objects'; +import { + distance, + isColinear, + norm, + scalar, + vector, + plus, + times, +} from '../maths'; + +import GraphElement from './GraphElement'; +import Line from './Line'; +import Point from './Point'; + +export default class Segment extends GraphElement { + static className = () => PDFClasses.Segment; + myClass(): PDFClasses { + return PDFClasses.Segment; + } + static type = 'Segment'; + A: Point; + B: Point; + constructor(A: Point = new Point(), B: Point = new Point()) { + super(); + this.A = A; + this.B = B; + } + + origin(): Point { + return this.A; + } + + destination(): Point { + return this.B; + } + + dirVect() { + return vector(this.origin(), this.destination()); + } + + length() { + return distance(this.destination(), this.origin()); + } + + isEqual(element: GraphElement): boolean { + if (!isPDFInstance(element, PDFClasses.Segment)) return false; + const o = this.origin(); + const dest = this.destination(); + const oE = (element as Segment).origin(); + const destE = (element as Segment).destination(); + return ( + (o.isEqual(oE) && dest.isEqual(destE)) || + (o.isEqual(destE) && dest.isEqual(oE)) + ); + } + + /** Returns an equivalent line object */ + getLine() { + const line = new Line(this.origin(), this.destination()); + return line; + } + + includes(P: Point) { + const vect = this.dirVect(); + const otherVect = vector(this.origin(), P); + // The vectors are not even colinear + if (!isColinear(vect, otherVect)) return false; + // The point is behind the origin + else if (scalar(vect, otherVect) < 0) return false; + // The point is after the destination + else if (norm(vect) < norm(otherVect)) return false; + else return true; + } + + middle() { + const mid = new Point( + plus(this.origin().toCoords(), times(this.dirVect(), 0.5)), + ); + return mid; + } + + orthoProjection(P: Point) { + const H = this.getLine().orthoProjection(P); + const vect = this.dirVect(); + const origin = this.origin().toCoords(); + const destination = this.destination().toCoords(); + const otherVect = vector(this.origin(), H); + // The point is before the origin + if (scalar(vect, otherVect) < 0) return new Point(origin); + // The point is after the destination + else if (norm(vect) < norm(otherVect)) return new Point(destination); + // The point is within the segment + else return H; + } +} diff --git a/src/utils/elements/index.ts b/src/utils/elements/index.ts new file mode 100644 index 000000000..bb83f4bb7 --- /dev/null +++ b/src/utils/elements/index.ts @@ -0,0 +1,9 @@ +export { default as Arc } from './Arc'; +export { default as Circle } from './Circle'; +export { default as GraphElement } from './GraphElement'; +export { default as Ellipse } from './Ellipse'; +export { default as Line } from './Line'; +export { default as SegmePlotnt } from './Plot'; +export { default as Point } from './Point'; +export { default as Rectangle } from './Rectangle'; +export { default as Segment } from './Segment'; diff --git a/src/utils/index.ts b/src/utils/index.ts index dd674114c..333592cee 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,11 +1,11 @@ -export * from 'src/utils/arrays'; -export * from 'src/utils/async'; -export * from 'src/utils/strings'; -export * from 'src/utils/unicode'; -export * from 'src/utils/numbers'; -export * from 'src/utils/errors'; -export * from 'src/utils/base64'; -export * from 'src/utils/objects'; -export * from 'src/utils/validators'; -export * from 'src/utils/pdfDocEncoding'; -export { default as Cache } from 'src/utils/Cache'; +export * from './arrays'; +export * from './async'; +export * from './strings'; +export * from './unicode'; +export * from './numbers'; +export * from './errors'; +export * from './base64'; +export * from './objects'; +export * from './validators'; +export * from './pdfDocEncoding'; +export { default as Cache } from './Cache'; diff --git a/src/utils/intersections.ts b/src/utils/intersections.ts new file mode 100644 index 000000000..e82fe1b06 --- /dev/null +++ b/src/utils/intersections.ts @@ -0,0 +1,310 @@ +import Arc from './elements/Arc'; +import Circle from './elements/Circle'; +import Ellipse from './elements/Ellipse'; +import Line from './elements/Line'; +import Plot from './elements/Plot'; +import Point from './elements/Point'; +import Rectangle from './elements/Rectangle'; +import Segment from './elements/Segment'; +import { Coordinates, GraphicElement } from '../types'; +import { + distance, + isColinear, + isEqual, + norm, + orthogonal, + times, + unitVector, + vector, + rotate, +} from './maths'; +import { isPDFInstance, PDFClasses } from '../api/objects'; + +export const intersections = ( + A: GraphicElement, + B: GraphicElement, +): Coordinates[] => { + if (isPDFInstance(A, PDFClasses.Point) || isPDFInstance(B, PDFClasses.Point)) + return []; + else if (A instanceof Text || B instanceof Text) return []; + else if (A instanceof Image || B instanceof Image) return []; + // TODO: calculate the coords of the intersection: https://www.emathzone.com/tutorials/geometry/intersection-of-line-and-ellipse.html + else if (isPDFInstance(A, PDFClasses.Line)) + return intersectionsLine( + A as Line, + B as Arc | Circle | Ellipse | Line | Plot | Rectangle | Segment, + ); + else if (isPDFInstance(A, PDFClasses.Segment)) { + return intersectionsLine( + (A as Segment).getLine(), + B as Arc | Circle | Ellipse | Line | Plot | Rectangle | Segment, + ).filter((P) => (A as Segment).includes(new Point(P))); + } else if (isPDFInstance(A, PDFClasses.Circle)) + return intersectionsCircle( + A as Circle, + B as Arc | Circle | Ellipse | Line | Plot | Rectangle | Segment, + ); + else if (isPDFInstance(A, PDFClasses.Arc)) { + return intersectionsCircle( + (A as Arc).getCircle(), + B as Arc | Circle | Ellipse | Line | Plot | Rectangle | Segment, + ).filter((P) => (A as Arc).includes(new Point(P))); + } else if (isPDFInstance(A, PDFClasses.Plot)) + return intersectionsPlot(A as Plot, B); + else if (isPDFInstance(A, PDFClasses.Rectangle)) + return intersectionsRectangle(A as Rectangle, B); + else if (isPDFInstance(A, PDFClasses.Ellipse)) + return intersectionsEllipse( + A as Ellipse, + B as Arc | Circle | Ellipse | Line | Plot | Rectangle | Segment, + ); + return A as never; +}; + +export const intersection = ( + A: GraphicElement, + B: GraphicElement, +): Coordinates | undefined => intersections(A, B)[0]; + +const intersectionsLine = ( + A: Line, + B: Exclude, +): Coordinates[] => { + if (isPDFInstance(B, PDFClasses.Line)) return intersectionLine(A, B as Line); + else if (isPDFInstance(B, PDFClasses.Segment)) { + return intersectionLine(A, (B as Segment).getLine()).filter((P) => + (B as Segment).includes(new Point(P)), + ); + } else if (isPDFInstance(B, PDFClasses.Circle)) + return intersectionCircleLine(B as Circle, A); + else if (isPDFInstance(B, PDFClasses.Arc)) { + return intersectionsCircle((B as Arc).getCircle(), A).filter((P) => + (B as Arc).includes(new Point(P)), + ); + } else if (isPDFInstance(B, PDFClasses.Plot)) + return intersectionsPlot(B as Plot, A); + else if (isPDFInstance(B, PDFClasses.Rectangle)) + return intersectionsRectangle(B as Rectangle, A); + else if (isPDFInstance(B, PDFClasses.Ellipse)) + return intersectionsEllipse(B as Ellipse, A); + return B as never; +}; + +const intersectionsEllipse = ( + A: Ellipse, + B: Exclude, +): Coordinates[] => { + if (isPDFInstance(B, PDFClasses.Line)) + return intersectionsLineAndEllipse(A, B as Line); + else if (isPDFInstance(B, PDFClasses.Segment)) { + return intersectionsEllipse(A, (B as Segment).getLine()).filter((P) => + (B as Segment).includes(new Point(P)), + ); + } + // TODO: + // else if (isPDFInstnace(B, PDFClasses.Circle)) return intersectionEllipseCircle(B as Circle, A); + else if (isPDFInstance(B, PDFClasses.Circle)) return []; + // TODO: + // else if (isPDFInstance(B, PDFClasses.Ellipse)) return intersectionEllipseEllipse(B as Ellipse, A); + else if (isPDFInstance(B, PDFClasses.Ellipse)) return []; + else if (isPDFInstance(B, PDFClasses.Arc)) { + return intersectionsEllipse(A, (B as Arc).getCircle()).filter((P) => + (B as Arc).includes(new Point(P)), + ); + } else if (isPDFInstance(B, PDFClasses.Plot)) + return intersectionsPlot(B as Plot, A); + else if (isPDFInstance(B, PDFClasses.Rectangle)) + return intersectionsRectangle(B as Rectangle, A); + return B as never; +}; + +const intersectionsLineAndEllipse = (A: Ellipse, B: Line): Coordinates[] => { + const center = A.center().toCoords(); + const a = A.a(); + const b = A.b(); + const rotation = A.rotation(); + const isLineParallel2YAxis = isEqual(B.dirVect().x, 0); + + // this is a dummy value to represent a point on the line + const p1Y = isLineParallel2YAxis ? 1 : B.y(1); + const p1X = isLineParallel2YAxis ? B.origin().toCoords().x : 1; + const p1 = { x: p1X, y: p1Y }; + + // this is a dummy value to represent a point on the line + const p2Y = isLineParallel2YAxis ? 2 : B.y(2); + const p2X = isLineParallel2YAxis ? B.origin().toCoords().x : 2; + const p2 = { x: p2X, y: p2Y }; + + const p1Normalized = rotate( + { x: p1.x - center.x, y: p1.y - center.y }, + -rotation, + ); + const p2Normalized = rotate( + { x: p2.x - center.x, y: p2.y - center.y }, + -rotation, + ); + + const angular = + (p1Normalized.y - p2Normalized.y) / (p1Normalized.x - p2Normalized.x); + const linear = p1Normalized.y - angular * p1Normalized.x; + + const lineY = (x: number) => angular * x + linear; + const denormalize = (coord: Coordinates) => { + const rotated = rotate(coord, rotation); + return { + x: rotated.x + center.x, + y: rotated.y + center.y, + }; + }; + + // Intersection with vertical line + if (isEqual(p1Normalized.x - p2Normalized.x, 0)) { + const x = p1Normalized.x; + const vDelta = b ** 2 - (x ** 2 * b ** 2) / a ** 2; + if (vDelta < 0) return []; + else if (vDelta === 0) { + return [{ x, y: 0 }].map(denormalize); + } else { + const y1 = Math.sqrt((b ** 2 * (a ** 2 - x ** 2)) / a ** 2); + const y2 = -y1; + return [ + { x, y: y1 }, + { x, y: y2 }, + ].map(denormalize); + } + } + + // Intersection with any line + + // the quadratic equation is: + // alpha * x ** 2 + beta * x + gamma = 0 + const alpha = a ** 2 * angular ** 2 + b ** 2; + const beta = 2 * a ** 2 * (angular * linear); + const gamma = a ** 2 * (linear ** 2 - b ** 2); + + const delta = beta ** 2 - 4 * alpha * gamma; + if (delta < 0) return []; + else if (delta === 0) { + const x = -(beta ** 2) / (2 * alpha); + const y = lineY(x); + return [{ x, y }].map(denormalize); + } else { + const x1 = (-beta + Math.sqrt(delta)) / (2 * alpha); + const y1 = lineY(x1); + const x2 = (-beta - Math.sqrt(delta)) / (2 * alpha); + const y2 = lineY(x2); + return [ + { x: x1, y: y1 }, + { x: x2, y: y2 }, + ].map(denormalize); + } +}; + +export const intersectionLine = (A: Line, B: Line): Coordinates[] => { + if (isColinear(A.dirVect(), B.dirVect())) return []; + else { + const { x: ux, y: uy } = A.dirVect(); + const { x: vx, y: vy } = B.dirVect(); + const { x: xA, y: yA } = A.origin().toCoords(); + const { x: xB, y: yB } = B.origin().toCoords(); + const x = + (ux * (vx * (yA - yB) + vy * xB) - uy * vx * xA) / (ux * vy - uy * vx); + const y = + (uy * (vy * (xA - xB) + vx * yB) - ux * vy * yA) / (uy * vx - ux * vy); + return [{ x, y }]; + } +}; + +const intersectionsPlot = (A: Plot, B: GraphicElement): Coordinates[] => { + const points = A.getPoints().map((pt) => new Point(pt)); + const head = points.pop(); + const segments = points.map( + (pt, i) => new Segment(pt, points[i + 1] || head), + ); + // @ts-ignore + const inters = segments.map((s) => intersections(s, B)).flat(); + return inters; +}; + +const intersectionsRectangle = ( + A: Rectangle, + B: GraphicElement, +): Coordinates[] => { + const P1 = A.getCoords(); + const P3 = A.getEnd(); + const P2 = { x: P1.x, y: P3.y }; + const P4 = { x: P3.x, y: P1.y }; + return intersections(new Plot([P1, P2, P3, P4, P1]), B); +}; + +export const intersectionCircleLine = (A: Circle, B: Line): Coordinates[] => { + const rA = A.ray(); + const O = A.center(); + const H = B.orthoProjection(O); + const OH = distance(O, H); + // The line is tangeant + if (isEqual(OH, rA)) return [H]; + // The line is too far from the circle + else if (OH > A.ray()) return []; + // The line cut the circle in 2 points + else { + // Pythagore + const HP = Math.sqrt(rA * rA - OH * OH); + const vect = unitVector(B.dirVect()); + return [H.plus(times(vect, HP)), H.plus(times(vect, -HP))]; + } +}; + +export const intersectionCircle = (A: Circle, B: Circle): Coordinates[] => { + const oA = A.center(); + const oB = B.center(); + const rA = A.ray(); + const rB = B.ray(); + const axis = vector(oA, oB); + const CC = norm(axis); + // The circles are tangeant + if (isEqual(CC, rA + rB)) return [A.orthoProjection(oB).toCoords()]; + // The circles are too far from eachother + else if (CC > rA + rB) return []; + // The intersections belong to an orthogonal axis + else { + const ratio = 1 / 2 + (rA * rA - rB * rB) / (CC * CC) / 2; + const H = oA.plus(times(axis, ratio)); + return intersectionCircleLine(A, new Line(H, H.plus(orthogonal(axis)))); + } +}; + +const intersectionsCircle = ( + A: Circle, + B: Exclude, +): Coordinates[] => { + if (isPDFInstance(B, PDFClasses.Circle)) + return intersectionCircle(A, B as Circle); + else if (isPDFInstance(B, PDFClasses.Line)) + return intersectionCircleLine(A, B as Line); + else if (isPDFInstance(B, PDFClasses.Segment)) { + return intersectionCircleLine(A, (B as Segment).getLine()).filter((P) => + (B as Segment).includes(new Point(P)), + ); + } else if (isPDFInstance(B, PDFClasses.Arc)) { + return intersectionCircle(A, (B as Arc).getCircle()).filter((P) => + (B as Arc).includes(new Point(P)), + ); + } else if (isPDFInstance(B, PDFClasses.Plot)) + return intersectionsPlot(B as Plot, A); + else if (isPDFInstance(B, PDFClasses.Rectangle)) + return intersectionsRectangle(B as Rectangle, A); + else if (isPDFInstance(B, PDFClasses.Ellipse)) + return intersectionsEllipse(B as Ellipse, A); + return B as never; +}; + +export const getIntersections = (elements: GraphicElement[]) => { + const checked: GraphicElement[] = []; + const inters: Coordinates[] = []; + elements.forEach((elt) => { + checked.forEach((e) => inters.push(...intersections(e, elt))); + checked.push(elt); + }); + return inters; +}; diff --git a/src/utils/maths.ts b/src/utils/maths.ts new file mode 100644 index 000000000..0ceac2184 --- /dev/null +++ b/src/utils/maths.ts @@ -0,0 +1,108 @@ +import Point from './elements/Point'; +import { Coordinates } from '../types'; + +/** This value represents the precision we accept for float values */ +export const FLOAT_APPROXIMATION = 0.000001; + +/** Calculates the distance between 2 points */ +export const distance = (A: Point, B: Point) => norm(vector(A, B)); + +export const distanceCoords = (A: Coordinates, B: Coordinates) => + norm(minus(B, A)); + +/** Calculates the distance denoted by a vector */ +export const norm = (vect: Coordinates) => + Math.sqrt(vect.x * vect.x + vect.y * vect.y); + +/** Calculates the orthogonal vector of provided vector */ +export const orthogonal = ({ x, y }: Coordinates): Coordinates => ({ + x: -y, + y: x, +}); + +/** Check if 2 vectors are proportional */ +export const isColinear = ( + { x: ux, y: uy }: Coordinates, + { x: vx, y: vy }: Coordinates, +): boolean => isEqual(ux * vy, uy * vx); + +/** Check if 2 floating values can be considered equals */ +export const isEqual = (a: number, b: number): boolean => + Math.round(Math.abs(a - b) / FLOAT_APPROXIMATION) === 0; + +/** Return true if a is proportional to b: (a = kb), considering float imprecision */ +export const isProportional = (a: number, b: number): boolean => + isEqual((Math.abs(a) + FLOAT_APPROXIMATION / 10) % b, 0); + +/** Calculate the scalar product between 2 vectors */ +export const scalar = ( + { x: ux, y: uy }: Coordinates, + { x: vx, y: vy }: Coordinates, +): number => ux * vx + uy * vy; + +/** Calculate the sum of 2 vectors */ +export const plus = ( + { x: ux, y: uy }: Coordinates, + { x: vx, y: vy }: Coordinates, +): Coordinates => ({ x: ux + vx, y: uy + vy }); + +/** Calculate the vector multiplied by a scalar */ +export const times = ({ x, y }: Coordinates, k = 1): Coordinates => ({ + x: k * x, + y: k * y, +}); + +/** Calculate the difference of 2 vectors */ +export const minus = (u: Coordinates, v: Coordinates): Coordinates => + plus(u, times(v, -1)); + +/** Returns the vector between 2 points. */ +export const vector = (A: Point, B: Point): Coordinates => + minus(B.toCoords(), A.toCoords()); + +/** + * Returns the angle between the vector and the horizontal axis (Ox). + * The return value is between -PI and PI. + * @returns {number} angle in radian between -Pi and Pi + */ +export const orientation = ({ x, y }: Coordinates): number => { + const alpha = Math.acos(x / Math.sqrt(x * x + y * y)); + return y > 0 ? alpha : -alpha; +}; + +/** Returns the unit vector associated to the provided vector, + * or the Null vector (0, 0) if the vector is null + */ +export const unitVector = (u: Coordinates): Coordinates => { + const l = norm(u); + return l > 0 ? times(u, 1 / l) : u; +}; + +/** Returns the angle from u to v in radian */ +export const angle = (u: Coordinates, v: Coordinates, previousAngle = 0) => { + let sweep = orientation(v) - orientation(u); + // If the angle has the same sign as the arc orientation, we return the angle as is + // Otherwise, we need to correct the value, adding or removing 2π + while (Math.abs(previousAngle - sweep) > Math.PI) { + sweep += Math.sign(previousAngle - sweep) * 2 * Math.PI; + } + return sweep; +}; + +/** Returns the angle between the lines (BA) and (BC) in radian + * @returns {number} the angle in radian, between -Pi and Pi + */ +export const angleABC = ( + A: Point, + B: Point, + C: Point, + previousAngle = 0, +): number => angle(vector(B, A), vector(B, C), previousAngle); + +/** Rotate the vector by an angle in radian */ +export const rotate = (vect: Coordinates, teta: number): Coordinates => { + const { x, y } = vect; + const nx = x * Math.cos(teta) - y * Math.sin(teta); + const ny = y * Math.cos(teta) + x * Math.sin(teta); + return { x: nx, y: ny }; +}; diff --git a/src/utils/pdfDocEncoding.ts b/src/utils/pdfDocEncoding.ts index 1249dc570..7c8dc955f 100644 --- a/src/utils/pdfDocEncoding.ts +++ b/src/utils/pdfDocEncoding.ts @@ -1,4 +1,4 @@ -import { toCharCode } from 'src/utils/strings'; +import { toCharCode } from './strings'; // Mapping from PDFDocEncoding to Unicode code point const pdfDocEncodingToUnicode = new Uint16Array(256); diff --git a/src/utils/png.ts b/src/utils/png.ts index 60aad74e5..2c1cb7e2c 100644 --- a/src/utils/png.ts +++ b/src/utils/png.ts @@ -1,4 +1,4 @@ -import UPNG from '@pdf-lib/upng'; +import UPNG from '@adnsistemas/upng'; const getImageType = (ctype: number) => { if (ctype === 0) return PngType.Greyscale; @@ -51,7 +51,7 @@ export class PNG { const upng = UPNG.decode(pngData); const frames = UPNG.toRGBA8(upng); - if (frames.length > 1) throw new Error(`Animated PNGs are not supported`); + if (frames.length > 1) throw new Error('Animated PNGs are not supported'); const frame = new Uint8Array(frames[0]); const { rgbChannel, alphaChannel } = splitAlphaChannel(frame); diff --git a/src/utils/strings.ts b/src/utils/strings.ts index 56a000aca..ab8d224d9 100644 --- a/src/utils/strings.ts +++ b/src/utils/strings.ts @@ -19,6 +19,12 @@ export const padStart = (value: string, length: number, padChar: string) => { return padding + value; }; +export const stringAsByteArray = (str: string): Uint8Array => { + const buffer = new Uint8Array(str.length); + copyStringIntoBuffer(str, buffer, 0); + return buffer; +}; + export const copyStringIntoBuffer = ( str: string, buffer: Uint8Array, @@ -44,11 +50,14 @@ export const escapedNewlineChars = ['\\n', '\\f', '\\r', '\\u000B']; export const newlineChars = ['\n', '\f', '\r', '\u000B']; +// eslint-disable-next-line no-control-regex export const isNewlineChar = (text: string) => /^[\n\f\r\u000B]$/.test(text); +// eslint-disable-next-line no-control-regex export const lineSplit = (text: string) => text.split(/[\n\f\r\u000B]/); export const mergeLines = (text: string) => + // eslint-disable-next-line no-control-regex text.replace(/[\n\f\r\u000B]/g, ' '); // JavaScript's String.charAt() method doesn work on strings containing UTF-16 @@ -139,7 +148,8 @@ export const breakTextIntoLines = ( }; // See section "7.9.4 Dates" of the PDF specification -const dateRegex = /^D:(\d\d\d\d)(\d\d)?(\d\d)?(\d\d)?(\d\d)?(\d\d)?([+\-Z])?(\d\d)?'?(\d\d)?'?$/; +const dateRegex = + /^D:(\d\d\d\d)(\d\d)?(\d\d)?(\d\d)?(\d\d)?(\d\d)?([+\-Z])?(\d\d)?'?(\d\d)?'?$/; export const parseDate = (dateStr: string): Date | undefined => { const match = dateStr.match(dateRegex); diff --git a/src/utils/unicode.ts b/src/utils/unicode.ts index 9d1c55154..2931a49f8 100644 --- a/src/utils/unicode.ts +++ b/src/utils/unicode.ts @@ -1,4 +1,4 @@ -import { toHexString } from 'src/utils/strings'; +import { toHexString } from './strings'; /** * Encodes a string to UTF-8. diff --git a/src/utils/validators.ts b/src/utils/validators.ts index f1d46e29e..19928d6a9 100644 --- a/src/utils/validators.ts +++ b/src/utils/validators.ts @@ -1,6 +1,6 @@ /* tslint:disable:ban-types */ -import { values as objectValues } from 'src/utils/objects'; +import { values as objectValues } from './objects'; export const backtick = (val: any) => `\`${val}\``; export const singleQuote = (val: any) => `'${val}'`; diff --git a/tests/api/PDFDocument.spec.ts b/tests/api/PDFDocument.spec.ts index d1cacbae4..7379e4930 100644 --- a/tests/api/PDFDocument.spec.ts +++ b/tests/api/PDFDocument.spec.ts @@ -8,16 +8,24 @@ import { PDFDocument, PDFHexString, PDFName, + PDFNumber, PDFPage, Duplex, NonFullScreenPageMode, PrintScaling, ReadingDirection, ViewerPreferences, -} from 'src/index'; - -const examplePngImage = - 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TxaoVBzuIdMhQnSyIijhKFYtgobQVWnUwufQLmjQkKS6OgmvBwY/FqoOLs64OroIg+AHi5uak6CIl/i8ptIjx4Lgf7+497t4BQqPCVLNrAlA1y0jFY2I2tyr2vKIfAgLoRVhipp5IL2bgOb7u4ePrXZRneZ/7cwwoeZMBPpF4jumGRbxBPLNp6Zz3iUOsJCnE58TjBl2Q+JHrsstvnIsOCzwzZGRS88QhYrHYwXIHs5KhEk8TRxRVo3wh67LCeYuzWqmx1j35C4N5bSXNdZphxLGEBJIQIaOGMiqwEKVVI8VEivZjHv4Rx58kl0yuMhg5FlCFCsnxg//B727NwtSkmxSMAd0vtv0xCvTsAs26bX8f23bzBPA/A1da219tALOfpNfbWuQIGNwGLq7bmrwHXO4Aw0+6ZEiO5KcpFArA+xl9Uw4YugX61tzeWvs4fQAy1NXyDXBwCIwVKXvd492Bzt7+PdPq7wcdn3KFLu4iBAAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAlFJREFUeNrt289r02AYB/Dvk6Sl4EDKpllTlFKsnUdBHXgUBEHwqHj2IJ72B0zwKHhxJ08i/gDxX/AiRfSkBxELXTcVxTa2s2xTsHNN8ngQbQL70RZqG/Z9b29JnvflkydP37whghG3ZaegoxzfwB5vBCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgwB5rstWPtnP0LqBX/vZNyLF6vVrpN/hucewhb4g+B2AyAwiwY7NGOXijviS9vBeYh6CEP4edBLDADCAAAQhAAAIQgAAEIAABCDAUAFF/GIN1DM+PBYCo/ohMXDQ1WPjoeUZH1mMBEEh0oqLGvsHCy0S4NzWVWotJBogbvZB+brDwQT7UWSmXy5sxyQB9HQEROdVv4HQ+vx+QmS4iXsWmCK7Usu8AhOqAXMzlcn3VgWTbugQgEYrxMkZ/gyUPgnuhe2C6/Stxvdeg2ezMJERvhOuoZ+JBrNYBRuDdBtDuXkDM25nCHLbZSv9X6A4VHU+DpwCcbvbjcetLtTaOANtuirrux08HM0euisjDEMKC7RQuq+C+pVJqpzx3NZ3+eeBza9I0rWJgyHnxg2sAJrqnaHUzFcyN60Jox13hprv8aNopZBS4GcqWWVHM+lAkN0zY7ncgkYBukRoKLPpiXVj9UFkfV4Bdl8Jf60u3IMZZAG/6iLuhkDvaSZ74VqtUx3kp3NN7gUZt8RmA43a2eEY1OCfQ04AcBpAGkAKwpkBLIG8BfQE/eNJsvG/G4VlARj0BfjDBx2ECEIAABCAAAQhAAAIQgAAE+P/tN8YvpvbTDBOlAAAAAElFTkSuQmCC'; + StandardFonts, + AFRelationship, + PDFString, + PDFInvalidObject, + rgb, +} from '../../src/index'; +import { PDFAttachment } from '../../src/api/PDFDocument'; + +const examplePngImageBase64 = + 'iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TxaoVBzuIdMhQnSyIijhKFYtgobQVWnUwufQLmjQkKS6OgmvBwY/FqoOLs64OroIg+AHi5uak6CIl/i8ptIjx4Lgf7+497t4BQqPCVLNrAlA1y0jFY2I2tyr2vKIfAgLoRVhipp5IL2bgOb7u4ePrXZRneZ/7cwwoeZMBPpF4jumGRbxBPLNp6Zz3iUOsJCnE58TjBl2Q+JHrsstvnIsOCzwzZGRS88QhYrHYwXIHs5KhEk8TRxRVo3wh67LCeYuzWqmx1j35C4N5bSXNdZphxLGEBJIQIaOGMiqwEKVVI8VEivZjHv4Rx58kl0yuMhg5FlCFCsnxg//B727NwtSkmxSMAd0vtv0xCvTsAs26bX8f23bzBPA/A1da219tALOfpNfbWuQIGNwGLq7bmrwHXO4Aw0+6ZEiO5KcpFArA+xl9Uw4YugX61tzeWvs4fQAy1NXyDXBwCIwVKXvd492Bzt7+PdPq7wcdn3KFLu4iBAAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAlFJREFUeNrt289r02AYB/Dvk6Sl4EDKpllTlFKsnUdBHXgUBEHwqHj2IJ72B0zwKHhxJ08i/gDxX/AiRfSkBxELXTcVxTa2s2xTsHNN8ngQbQL70RZqG/Z9b29JnvflkydP37whghG3ZaegoxzfwB5vBCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgwB5rstWPtnP0LqBX/vZNyLF6vVrpN/hucewhb4g+B2AyAwiwY7NGOXijviS9vBeYh6CEP4edBLDADCAAAQhAAAIQgAAEIAABCDAUAFF/GIN1DM+PBYCo/ohMXDQ1WPjoeUZH1mMBEEh0oqLGvsHCy0S4NzWVWotJBogbvZB+brDwQT7UWSmXy5sxyQB9HQEROdVv4HQ+vx+QmS4iXsWmCK7Usu8AhOqAXMzlcn3VgWTbugQgEYrxMkZ/gyUPgnuhe2C6/Stxvdeg2ezMJERvhOuoZ+JBrNYBRuDdBtDuXkDM25nCHLbZSv9X6A4VHU+DpwCcbvbjcetLtTaOANtuirrux08HM0euisjDEMKC7RQuq+C+pVJqpzx3NZ3+eeBza9I0rWJgyHnxg2sAJrqnaHUzFcyN60Jox13hprv8aNopZBS4GcqWWVHM+lAkN0zY7ncgkYBukRoKLPpiXVj9UFkfV4Bdl8Jf60u3IMZZAG/6iLuhkDvaSZ74VqtUx3kp3NN7gUZt8RmA43a2eEY1OCfQ04AcBpAGkAKwpkBLIG8BfQE/eNJsvG/G4VlARj0BfjDBx2ECEIAABCAAAQhAAAIQgAAE+P/tN8YvpvbTDBOlAAAAAElFTkSuQmCC'; +const examplePngImage = `data:image/png;base64,${examplePngImageBase64}`; const unencryptedPdfBytes = fs.readFileSync('assets/pdfs/normal.pdf'); const oldEncryptedPdfBytes1 = fs.readFileSync('assets/pdfs/encrypted_old.pdf'); @@ -29,6 +37,9 @@ const oldEncryptedPdfBytes1 = fs.readFileSync('assets/pdfs/encrypted_old.pdf'); // const oldEncryptedPdfBytes2 = fs.readFileSync('pdf_specification.pdf'); const newEncryptedPdfBytes = fs.readFileSync('assets/pdfs/encrypted_new.pdf'); +const encryptedLiteralStringsPdfBytes = fs.readFileSync( + 'assets/pdfs/encrypted_literal_strings.pdf', +); const invalidObjectsPdfBytes = fs.readFileSync( 'assets/pdfs/with_invalid_objects.pdf', ); @@ -37,6 +48,16 @@ const normalPdfBytes = fs.readFileSync('assets/pdfs/normal.pdf'); const withViewerPrefsPdfBytes = fs.readFileSync( 'assets/pdfs/with_viewer_prefs.pdf', ); +const hasAttachmentPdfBytes = fs.readFileSync( + 'assets/pdfs/examples/add_attachments.pdf', +); + +const simplePdfBytes = fs.readFileSync('assets/pdfs/simple.pdf'); +const simpleStreamsPdfBytes = fs.readFileSync('assets/pdfs/simple_streams.pdf'); + +const v15PdfBytes = fs.readFileSync('assets/pdfs/v15xref.pdf'); +const v14PdfBytes = fs.readFileSync('assets/pdfs/bixby_guide.pdf'); +const v13PdfBytes = normalPdfBytes; describe(`PDFDocument`, () => { describe(`load() method`, () => { @@ -61,7 +82,7 @@ describe(`PDFDocument`, () => { console.warn = origConsoleWarn; }); - it(`does not throw an error for unencrypted PDFs`, async () => { + it('does not throw an error for unencrypted PDFs', async () => { const pdfDoc = await PDFDocument.load(unencryptedPdfBytes, { parseSpeed: ParseSpeeds.Fastest, }); @@ -69,7 +90,7 @@ describe(`PDFDocument`, () => { expect(pdfDoc.isEncrypted).toBe(false); }); - it(`throws an error for old encrypted PDFs (1)`, async () => { + it('throws an error for old encrypted PDFs (1)', async () => { await expect( PDFDocument.load(oldEncryptedPdfBytes1, { parseSpeed: ParseSpeeds.Fastest, @@ -85,7 +106,7 @@ describe(`PDFDocument`, () => { // ).rejects.toThrow(new EncryptedPDFError()); // }); - it(`throws an error for new encrypted PDFs`, async () => { + it('throws an error for new encrypted PDFs', async () => { await expect( PDFDocument.load(newEncryptedPdfBytes, { parseSpeed: ParseSpeeds.Fastest, @@ -93,7 +114,7 @@ describe(`PDFDocument`, () => { ).rejects.toThrow(new EncryptedPDFError()); }); - it(`does not throw an error for old encrypted PDFs when ignoreEncryption=true (1)`, async () => { + it('does not throw an error for old encrypted PDFs when ignoreEncryption=true (1)', async () => { const pdfDoc = await PDFDocument.load(oldEncryptedPdfBytes1, { ignoreEncryption: true, parseSpeed: ParseSpeeds.Fastest, @@ -111,7 +132,7 @@ describe(`PDFDocument`, () => { // expect(pdfDoc.isEncrypted).toBe(true); // }); - it(`does not throw an error for new encrypted PDFs when ignoreEncryption=true`, async () => { + it('does not throw an error for new encrypted PDFs when ignoreEncryption=true', async () => { const pdfDoc = await PDFDocument.load(newEncryptedPdfBytes, { ignoreEncryption: true, parseSpeed: ParseSpeeds.Fastest, @@ -120,7 +141,20 @@ describe(`PDFDocument`, () => { expect(pdfDoc.isEncrypted).toBe(true); }); - it(`does not throw an error for invalid PDFs when throwOnInvalidObject=false`, async () => { + it('decrypts literal strings', async () => { + const pdfDoc = await PDFDocument.load(encryptedLiteralStringsPdfBytes, { + password: '1234', + parseSpeed: ParseSpeeds.Fastest, + }); + expect(pdfDoc).toBeInstanceOf(PDFDocument); + expect(pdfDoc.isEncrypted).toBe(false); + expect(pdfDoc.getCreator()).toBe('Acrobat Pro DC 19.10.20069'); + expect(pdfDoc.getCreationDate()).toStrictEqual( + new Date('2025-12-07T01:14:12Z'), + ); + }); + + it('does not throw an error for invalid PDFs when throwOnInvalidObject=false', async () => { await expect( PDFDocument.load(invalidObjectsPdfBytes, { ignoreEncryption: true, @@ -130,7 +164,7 @@ describe(`PDFDocument`, () => { ).resolves.toBeInstanceOf(PDFDocument); }); - it(`throws an error for invalid PDFs when throwOnInvalidObject=true`, async () => { + it('throws an error for invalid PDFs when throwOnInvalidObject=true', async () => { const expectedError = new Error( 'Trying to parse invalid object: {"line":20,"column":13,"offset":126})', ); @@ -144,8 +178,34 @@ describe(`PDFDocument`, () => { }); }); - describe(`embedFont() method`, () => { - it(`serializes the same value on every save`, async () => { + describe('largestObjectNumber detection', () => { + it('loads pdfs with XREF streams', async () => { + const pdfDoc = await PDFDocument.load(simpleStreamsPdfBytes); + expect(pdfDoc.context.largestObjectNumber).toBe(8); + }); + + it('loads pdfs without XREF streams', async () => { + const pdfDoc = await PDFDocument.load(simplePdfBytes); + expect(pdfDoc.context.largestObjectNumber).toBe(8); + }); + + it('preserves deleted objects numbers if open for update', async () => { + const pdfBytes = fs.readFileSync( + './assets/pdfs/with_update_sections.pdf', + ); + const pdfDoc = await PDFDocument.load(pdfBytes, { + forIncrementalUpdate: false, + }); + expect(pdfDoc.context.largestObjectNumber).toBeGreaterThanOrEqual(131); + const pdfUpdDoc = await PDFDocument.load(pdfBytes, { + forIncrementalUpdate: true, + }); + expect(pdfUpdDoc.context.largestObjectNumber).toBe(334); + }); + }); + + describe('embedFont() method', () => { + it('serializes the same value on every save', async () => { const customFont = fs.readFileSync('assets/fonts/ubuntu/Ubuntu-B.ttf'); const pdfDoc1 = await PDFDocument.create({ updateMetadata: false }); const pdfDoc2 = await PDFDocument.create({ updateMetadata: false }); @@ -163,66 +223,82 @@ describe(`PDFDocument`, () => { }); }); - describe(`setLanguage() method`, () => { - it(`sets the language of the document`, async () => { + describe('embedStandardFont() method', () => { + it('Raises an exception if not a standard font', async () => { + const pdfDoc1 = await PDFDocument.create({ updateMetadata: false }); + expect(() => + pdfDoc1.embedStandardFont('MyCustomFont' as StandardFonts), + ).toThrow(); + }); + }); + + describe('setLanguage() method', () => { + it('sets the language of the document', async () => { const pdfDoc = await PDFDocument.create(); - expect(pdfDoc.catalog.get(PDFName.of('Lang'))).toBeUndefined(); + expect(pdfDoc.getLanguage()).toBeUndefined(); pdfDoc.setLanguage('fr-FR'); - expect(String(pdfDoc.catalog.get(PDFName.of('Lang')))).toBe('(fr-FR)'); + expect(pdfDoc.getLanguage()).toBe('fr-FR'); pdfDoc.setLanguage('en'); - expect(String(pdfDoc.catalog.get(PDFName.of('Lang')))).toBe('(en)'); + expect(pdfDoc.getLanguage()).toBe('en'); pdfDoc.setLanguage(''); - expect(String(pdfDoc.catalog.get(PDFName.of('Lang')))).toBe('()'); + expect(pdfDoc.getLanguage()).toBe(''); }); }); - describe(`getPageCount() method`, () => { + describe('getPageCount() method', () => { let pdfDoc: PDFDocument; beforeAll(async () => { const parseSpeed = ParseSpeeds.Fastest; pdfDoc = await PDFDocument.load(unencryptedPdfBytes, { parseSpeed }); }); - it(`returns the initial page count of the document`, () => { + it('returns the initial page count of the document', () => { expect(pdfDoc.getPageCount()).toBe(2); }); - it(`returns the updated page count after adding pages`, () => { + it('returns the updated page count after adding pages', () => { pdfDoc.addPage(); pdfDoc.addPage(); expect(pdfDoc.getPageCount()).toBe(4); }); - it(`returns the updated page count after inserting pages`, () => { + it('returns the updated page count after inserting pages', () => { pdfDoc.insertPage(0); pdfDoc.insertPage(4); expect(pdfDoc.getPageCount()).toBe(6); }); - it(`returns the updated page count after removing pages`, () => { + it('returns the updated page count after removing pages', () => { pdfDoc.removePage(5); pdfDoc.removePage(0); expect(pdfDoc.getPageCount()).toBe(4); }); - it(`returns 0 for brand new documents`, async () => { + it('returns 0 for brand new documents', async () => { const newDoc = await PDFDocument.create(); expect(newDoc.getPageCount()).toBe(0); }); }); - describe(`addPage() method`, () => { - it(`Can insert pages in brand new documents`, async () => { + describe('addPage() method', () => { + it('Can insert pages in brand new documents', async () => { const pdfDoc = await PDFDocument.create(); expect(pdfDoc.addPage()).toBeInstanceOf(PDFPage); }); }); - describe(`metadata getter methods`, () => { - it(`they can retrieve the title, author, subject, producer, creator, keywords, creation date, and modification date from a new document`, async () => { + describe('removePage() method', () => { + it('Raises an exception on empty paged documentas', async () => { + const pdfDoc = await PDFDocument.create(); + expect(() => pdfDoc.removePage(0)).toThrow(); + }); + }); + + describe('metadata getter methods', () => { + it('they can retrieve the title, author, subject, producer, creator, keywords, creation date, and modification date from a new document', async () => { const pdfDoc = await PDFDocument.create(); // Everything is empty or has its initial value. @@ -268,7 +344,7 @@ describe(`PDFDocument`, () => { expect(pdfDoc.getModificationDate()).toStrictEqual(modificationDate); }); - it(`they can retrieve the title, author, subject, producer, creator, and keywords from an existing document`, async () => { + it('they can retrieve the title, author, subject, producer, creator, and keywords from an existing document', async () => { const pdfDoc = await PDFDocument.load(justMetadataPdfbytes); expect(pdfDoc.getTitle()).toBe( @@ -288,7 +364,7 @@ describe(`PDFDocument`, () => { ); }); - it(`they can retrieve the creation date and modification date from an existing document`, async () => { + it('they can retrieve the creation date and modification date from an existing document', async () => { const pdfDoc = await PDFDocument.load(normalPdfBytes, { updateMetadata: false, }); @@ -302,8 +378,8 @@ describe(`PDFDocument`, () => { }); }); - describe(`ViewerPreferences`, () => { - it(`defaults to an undefined ViewerPreferences dict`, async () => { + describe('ViewerPreferences', () => { + it('defaults to an undefined ViewerPreferences dict', async () => { const pdfDoc = await PDFDocument.create(); expect( @@ -311,7 +387,7 @@ describe(`PDFDocument`, () => { ).toBeUndefined(); }); - it(`can get/set HideToolbar, HideMenubar, HideWindowUI, FitWindow, CenterWindow, DisplayDocTitle, NonFullScreenPageMode, Direction, PrintScaling, Duplex, PickTrayByPDFSize, PrintPageRange, NumCopies from a new document`, async () => { + it('can get/set HideToolbar, HideMenubar, HideWindowUI, FitWindow, CenterWindow, DisplayDocTitle, NonFullScreenPageMode, Direction, PrintScaling, Duplex, PickTrayByPDFSize, PrintPageRange, NumCopies from a new document', async () => { const pdfDoc = await PDFDocument.create(); const viewerPrefs = pdfDoc.catalog.getOrCreateViewerPreferences(); @@ -374,7 +450,7 @@ describe(`PDFDocument`, () => { expect(viewerPrefs.getPrintPageRange()).toEqual([pageRange]); }); - it(`they can be retrieved from an existing document`, async () => { + it('they can be retrieved from an existing document', async () => { const pdfDoc = await PDFDocument.load(withViewerPrefsPdfBytes); const viewerPrefs = pdfDoc.catalog.getViewerPreferences()!; @@ -409,8 +485,8 @@ describe(`PDFDocument`, () => { }); }); - describe(`setTitle() method with options`, () => { - it(`does not set the ViewerPreferences dict if the option is not set`, async () => { + describe('setTitle() method with options', () => { + it('does not set the ViewerPreferences dict if the option is not set', async () => { const pdfDoc = await PDFDocument.create(); pdfDoc.setTitle('Testing setTitle Title'); @@ -422,7 +498,7 @@ describe(`PDFDocument`, () => { expect(pdfDoc.getTitle()).toBe('Testing setTitle Title'); }); - it(`creates the ViewerPreferences dict when the option is set`, async () => { + it('creates the ViewerPreferences dict when the option is set', async () => { const pdfDoc = await PDFDocument.create(); pdfDoc.setTitle('ViewerPrefs Test Creation', { @@ -435,8 +511,8 @@ describe(`PDFDocument`, () => { }); }); - describe(`addJavaScript() method`, () => { - it(`adds the script to the catalog`, async () => { + describe('addJavaScript() method', () => { + it('adds the script to the catalog', async () => { const pdfDoc = await PDFDocument.create(); pdfDoc.addJavaScript( 'main', @@ -453,7 +529,7 @@ describe(`PDFDocument`, () => { expect(JSNames.lookup(0, PDFHexString).decodeText()).toEqual('main'); }); - it(`does not overwrite scripts`, async () => { + it('does not overwrite scripts', async () => { const pdfDoc = await PDFDocument.create(); pdfDoc.addJavaScript( 'first', @@ -473,8 +549,8 @@ describe(`PDFDocument`, () => { }); }); - describe(`embedPng() method`, () => { - it(`does not prevent the PDFDocument from being modified after embedding an image`, async () => { + describe('embedPng() method', () => { + it('does not prevent the PDFDocument from being modified after embedding an image', async () => { const pdfDoc = await PDFDocument.create(); const pdfPage = pdfDoc.addPage(); @@ -493,8 +569,8 @@ describe(`PDFDocument`, () => { }); }); - describe(`save() method`, () => { - it(`can called multiple times on the same PDFDocument with different changes`, async () => { + describe('save() method', () => { + it('can be called multiple times on the same PDFDocument with different changes', async () => { const pdfDoc = await PDFDocument.create(); const embeddedImage = await pdfDoc.embedPng(examplePngImage); @@ -526,9 +602,887 @@ describe(`PDFDocument`, () => { await expect(noErrorFunc()).resolves.not.toThrowError(); }); + + it('returns the full pdf, when pdf not open for incremental update', async () => { + const pdfDoc = await PDFDocument.load(simplePdfBytes); + const snapshot = pdfDoc.takeSnapshot(); + const page = pdfDoc.getPage(0); + snapshot.markRefForSave(page.ref); + const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman); + const fontSize = 30; + page.drawText('Incremental saving is also awesome!', { + x: 50, + y: 4 * fontSize, + size: fontSize, + font: timesRomanFont, + }); + const firstFullPDF = await pdfDoc.save(); + expect(firstFullPDF.byteLength).toBeGreaterThan( + simplePdfBytes.byteLength, + ); + pdfDoc.takeSnapshot(); + const secondFullPDF = await pdfDoc.save(); + expect(secondFullPDF).toEqual(firstFullPDF); + }); + + it('returns the full pdf when open for incremental update', async () => { + const pdfDoc = await PDFDocument.load(simplePdfBytes, { + forIncrementalUpdate: true, + }); + const snapshot = pdfDoc.takeSnapshot(); + const page = pdfDoc.getPage(0); + snapshot.markRefForSave(page.ref); + const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman); + const fontSize = 30; + page.drawText('Incremental saving is also awesome!', { + x: 50, + y: 4 * fontSize, + size: fontSize, + font: timesRomanFont, + }); + const firstFullPDF = await pdfDoc.save(); + expect(firstFullPDF.byteLength).toBeGreaterThan( + simplePdfBytes.byteLength, + ); + for (let bi = 0; bi < simplePdfBytes.byteLength; bi++) { + expect(firstFullPDF[bi]).toBe(simplePdfBytes[bi]); + } + pdfDoc.takeSnapshot(); + const secondFullPDF = await pdfDoc.save(); + expect(secondFullPDF).toEqual(firstFullPDF); + }); + + it('respects PDF version when saving incrementally', async () => { + const getIncrementedLastChunk = async (pdfBytes: Buffer) => { + const pdfDoc = await PDFDocument.load(pdfBytes, { + forIncrementalUpdate: true, + }); + const page = pdfDoc.getPage(0); + const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman); + const fontSize = 30; + page.drawText('Incremental saving is also awesome!', { + x: 50, + y: 4 * fontSize, + size: fontSize, + font: timesRomanFont, + }); + const incrementedPDFBytes = await pdfDoc.save(); + const str = Buffer.from(incrementedPDFBytes).toString(); + return str.substring(str.length - 512); + }; + // should not use xrefStreams, introduced on v 1.5 + expect(await getIncrementedLastChunk(v13PdfBytes)).toMatch( + `xref\n0 1\n${''.padEnd(10, '0')} 65535 f \n`, + ); + // should not use xrefStreams, introduced on v 1.5 + expect(await getIncrementedLastChunk(v14PdfBytes)).toMatch( + `xref\n0 1\n${''.padEnd(10, '0')} 65535 f \n`, + ); + // 1.7 should use xrefStreams, introduced on v 1.5 + expect(await getIncrementedLastChunk(simplePdfBytes)).not.toMatch( + `xref\n0 1\n${''.padEnd(10, '0')} 65535 f \n`, + ); + }, 15000); + + it('objectStreams usage can be forced', async () => { + const pdfDoc = await PDFDocument.load(v13PdfBytes, { + forIncrementalUpdate: true, + }); + const page = pdfDoc.getPage(0); + const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman); + const fontSize = 30; + page.drawText('Incremental saving is also awesome!', { + x: 50, + y: 4 * fontSize, + size: fontSize, + font: timesRomanFont, + }); + const incrementedPDFBytes = await pdfDoc.save({ useObjectStreams: true }); + const str = Buffer.from(incrementedPDFBytes).toString(); + expect(str.substring(str.length - 512)).not.toMatch( + `xref\n0 1\n${''.padEnd(10, '0')} 65535 f \n`, + ); + }, 15000); + + it('properly handles XRef Streams on full save', async () => { + const pdfDoc = await PDFDocument.load(v15PdfBytes); + const stmB = await pdfDoc.save(); + const str = Buffer.from(stmB).toString(); + const match = str.match(/XRef/g); + expect(match?.length).toBe(1); + const noStmB = await pdfDoc.save({ useObjectStreams: false }); + const noStrmStr = Buffer.from(noStmB).toString(); + const matchNoStm = noStrmStr.match(/XRef/g); + expect(matchNoStm).toBeNull(); + }); + + it('calculates correct pdf size', async () => { + const pdfDoc = await PDFDocument.load(v15PdfBytes); + const stmB = await pdfDoc.save(); + const str = Buffer.from(stmB).toString(); + let match = str.match(/Size(.*)/g); + expect(match?.length).toBe(1); + if (!match) return; + expect(match[0]).toBe('Size 16'); + match = str.match(/Index(.*)/g); + if (!match) return; + expect(match[0]).toBe('Index [ 0 13 14 2 ]'); + let tail = str.substring(str.length - 64); + tail = tail.substring(tail.indexOf('startxref') + 9).trim(); + expect(tail.startsWith('3280')).toBeTruthy(); + const noStmB = await pdfDoc.save({ useObjectStreams: false }); + const noStrmStr = Buffer.from(noStmB).toString(); + let matchNoStm = noStrmStr.match(/Size(.*)/g); + expect(matchNoStm?.length).toBe(1); + if (!matchNoStm) return; + expect(matchNoStm[0]).toBe('Size 13'); + matchNoStm = noStrmStr.match(/Index(.*)/g); + expect(matchNoStm).toBeNull(); + tail = noStrmStr.substring(str.length - 64); + tail = tail.substring(tail.indexOf('startxref') + 9).trim(); + expect(tail.startsWith('3631')).toBeTruthy(); + }); + }); + + describe(`saveIncremental() method`, () => { + it(`can be used with different pages`, async () => { + const noErrorFunc = async (pageIndex: number) => { + const pdfDoc = await PDFDocument.load(simplePdfBytes); + const snapshot = pdfDoc.takeSnapshot(); + const page = pdfDoc.getPage(pageIndex); + snapshot.markRefForSave(page.ref); + const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman); + const fontSize = 30; + page.drawText('Incremental saving is also awesome!', { + x: 50, + y: 4 * fontSize, + size: fontSize, + font: timesRomanFont, + }); + + const pdfIncrementalBytes = await pdfDoc.saveIncremental(snapshot); + expect(pdfIncrementalBytes.byteLength).toBeGreaterThan(0); + }; + + await expect(noErrorFunc(0)).resolves.not.toThrowError(); + await expect(noErrorFunc(1)).resolves.not.toThrowError(); + }); + + it(`can be used with object-stream PDFs`, async () => { + const noErrorFunc = async () => { + const pdfDoc = await PDFDocument.load(simpleStreamsPdfBytes); + const snapshot = pdfDoc.takeSnapshot(); + const page = pdfDoc.getPage(0); + snapshot.markRefForSave(page.ref); + const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman); + const fontSize = 30; + page.drawText('Incremental saving is also awesome!', { + x: 50, + y: 4 * fontSize, + size: fontSize, + font: timesRomanFont, + }); + + const pdfIncrementalBytes = await pdfDoc.saveIncremental(snapshot); + expect(pdfIncrementalBytes.byteLength).toBeGreaterThan(0); + }; + + await expect(noErrorFunc()).resolves.not.toThrowError(); + }); + + it(`saves deleted objects`, async () => { + const noErrorFunc = async (pageIndex: number) => { + const pdfDoc = await PDFDocument.load(simplePdfBytes); + const snapshot = pdfDoc.takeSnapshot(); + const page = pdfDoc.getPage(pageIndex); + snapshot.markDeletedRef(page.ref); + const pdfIncrementalBytes = await pdfDoc.saveIncremental(snapshot, { + useObjectStreams: false, + }); + expect(pdfIncrementalBytes.byteLength).toBeGreaterThan(0); + expect(Buffer.from(pdfIncrementalBytes).toString()).toMatch( + `xref\n0 1\n${page.ref.objectNumber.toString().padStart(10, '0')} 65535 f \n${page.ref.objectNumber.toString()} 1\n0000000000 00001 f`, + ); + }; + + await expect(noErrorFunc(0)).resolves.not.toThrowError(); + await expect(noErrorFunc(1)).resolves.not.toThrowError(); + }); + + it('respects PDF version for XREF generation', async () => { + const getIncrementedLastChunk = async (pdfBytes: Buffer) => { + const pdfDoc = await PDFDocument.load(pdfBytes); + const snapshot = pdfDoc.takeSnapshot(); + const page = pdfDoc.getPage(0); + snapshot.markRefForSave(page.ref); + const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman); + const fontSize = 30; + page.drawText('Incremental saving is also awesome!', { + x: 50, + y: 4 * fontSize, + size: fontSize, + font: timesRomanFont, + }); + const pdfIncrementalBytes = await pdfDoc.saveIncremental(snapshot); + const str = Buffer.from(pdfIncrementalBytes).toString(); + return str.substring(str.length - 512); + }; + // should not use xrefStreams, introduced on v 1.5 + expect(await getIncrementedLastChunk(v13PdfBytes)).toMatch( + `xref\n0 1\n${''.padEnd(10, '0')} 65535 f \n`, + ); + // should not use xrefStreams, introduced on v 1.5 + expect(await getIncrementedLastChunk(v14PdfBytes)).toMatch( + `xref\n0 1\n${''.padEnd(10, '0')} 65535 f \n`, + ); + // 1.7 should use xrefStreams, introduced on v 1.5 + expect(await getIncrementedLastChunk(simplePdfBytes)).not.toMatch( + `xref\n0 1\n${''.padEnd(10, '0')} 65535 f \n`, + ); + }, 15000); + + it('objectStreams usage can be forced', async () => { + const pdfDoc = await PDFDocument.load(v13PdfBytes); + const snapshot = pdfDoc.takeSnapshot(); + const page = pdfDoc.getPage(0); + snapshot.markRefForSave(page.ref); + const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman); + const fontSize = 30; + page.drawText('Incremental saving is also awesome!', { + x: 50, + y: 4 * fontSize, + size: fontSize, + font: timesRomanFont, + }); + const pdfIncrementalBytes = await pdfDoc.saveIncremental(snapshot, { + useObjectStreams: true, + }); + const str = Buffer.from(pdfIncrementalBytes).toString(); + expect(str.substring(str.length - 512)).not.toMatch( + `xref\n0 1\n${''.padEnd(10, '0')} 65535 f \n`, + ); + }, 15000); + }); + + describe('saveAndContinue() method', () => { + it('allows multiple incremental updates without reloading', async () => { + const pdfDoc = await PDFDocument.load(simplePdfBytes, { + forIncrementalUpdate: true, + }); + + const page = pdfDoc.getPage(0); + const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman); + + page.drawText('First update', { + x: 50, + y: 200, + size: 30, + font: timesRomanFont, + }); + const firstCommit = await pdfDoc.saveAndContinue(); + expect(firstCommit.byteLength).toBeGreaterThan(simplePdfBytes.byteLength); + expect( + Array.from(firstCommit.slice(0, simplePdfBytes.byteLength)), + ).toEqual(Array.from(simplePdfBytes)); + + page.drawText('Second update', { + x: 50, + y: 160, + size: 30, + font: timesRomanFont, + }); + const secondCommit = await pdfDoc.saveAndContinue(); + expect(secondCommit.byteLength).toBeGreaterThan(firstCommit.byteLength); + expect(Array.from(secondCommit.slice(0, firstCommit.byteLength))).toEqual( + Array.from(firstCommit), + ); + + page.drawText('Third update', { + x: 50, + y: 120, + size: 30, + font: timesRomanFont, + }); + const thirdCommit = await pdfDoc.saveAndContinue(); + expect(thirdCommit.byteLength).toBeGreaterThan(secondCommit.byteLength); + expect(Array.from(thirdCommit.slice(0, secondCommit.byteLength))).toEqual( + Array.from(secondCommit), + ); + + const finalDoc = await PDFDocument.load(thirdCommit); + expect(finalDoc.getPageCount()).toBe(pdfDoc.getPageCount()); + }); + + it('throws error if document was not loaded with forIncrementalUpdate', async () => { + const pdfDoc = await PDFDocument.load(simplePdfBytes); + await expect(pdfDoc.saveAndContinue()).rejects.toThrow( + 'saveAndContinue() requires the document to be loaded with forIncrementalUpdate: true', + ); + }); + + it('works with newly created documents after first save', async () => { + const pdfDoc = await PDFDocument.create(); + pdfDoc.addPage(); + const firstSave = await pdfDoc.save(); + + const loadedDoc = await PDFDocument.load(firstSave, { + forIncrementalUpdate: true, + }); + loadedDoc.getPage(0).drawText('Update after creation'); + const committed = await loadedDoc.saveAndContinue(); + + expect(committed.byteLength).toBeGreaterThan(firstSave.byteLength); + }); + + it('replaces existing context snapshot after saveAndContinue', async () => { + const pdfDoc = await PDFDocument.load(simplePdfBytes, { + forIncrementalUpdate: true, + }); + + const initialSnapshot = pdfDoc.takeSnapshot(); + pdfDoc.context.snapshot = initialSnapshot; + + const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman); + pdfDoc.getPage(0).drawText('Test using existing snapshot', { + x: 50, + y: 200, + size: 20, + font: timesRomanFont, + }); + + const originalTakeSnapshot = pdfDoc.takeSnapshot.bind(pdfDoc); + let takeSnapshotCalled = false; + pdfDoc.takeSnapshot = function () { + takeSnapshotCalled = true; + return originalTakeSnapshot(); + }; + + const committed = await pdfDoc.saveAndContinue(); + + expect(takeSnapshotCalled).toBe(true); + expect(committed.byteLength).toBeGreaterThan(simplePdfBytes.byteLength); + expect(pdfDoc.context.snapshot).toBeDefined(); + expect(pdfDoc.context.snapshot).not.toBe(initialSnapshot); + }); + + it('does not create duplicate font objects on multiple saves', async () => { + const pdfDoc = await PDFDocument.load(simplePdfBytes, { + forIncrementalUpdate: true, + }); + + const page = pdfDoc.getPage(0); + const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman); + + page.drawText('First commit', { + x: 50, + y: 200, + size: 20, + font: timesRomanFont, + }); + const firstCommit = await pdfDoc.saveAndContinue(); + const objectCountAfterFirst = pdfDoc.context.largestObjectNumber; + + page.drawText('Second commit', { + x: 50, + y: 160, + size: 20, + font: timesRomanFont, + }); + const secondCommit = await pdfDoc.saveAndContinue(); + const objectCountAfterSecond = pdfDoc.context.largestObjectNumber; + + const newObjectCount = objectCountAfterSecond - objectCountAfterFirst; + expect(newObjectCount).toBeLessThan(4); + expect(secondCommit.byteLength).toBeGreaterThan(firstCommit.byteLength); + }); + + it('does not create duplicate image objects on multiple saves', async () => { + const pdfDoc = await PDFDocument.load(simplePdfBytes, { + forIncrementalUpdate: true, + }); + + const originalPageCount = pdfDoc.getPageCount(); + const page = pdfDoc.getPage(0); + const pngImage = await pdfDoc.embedPng(examplePngImage); + + page.drawImage(pngImage, { x: 50, y: 400, width: 50, height: 50 }); + const firstCommit = await pdfDoc.saveAndContinue(); + const objectCountAfterFirst = pdfDoc.context.largestObjectNumber; + + page.drawImage(pngImage, { x: 150, y: 400, width: 50, height: 50 }); + const secondCommit = await pdfDoc.saveAndContinue(); + const objectCountAfterSecond = pdfDoc.context.largestObjectNumber; + + const newObjectCount = objectCountAfterSecond - objectCountAfterFirst; + expect(newObjectCount).toBeLessThan(3); + expect(secondCommit.byteLength).toBeGreaterThan(firstCommit.byteLength); + + const finalDoc = await PDFDocument.load(secondCommit); + expect(finalDoc.getPageCount()).toBe(originalPageCount); + }); + + it('handles adding pages between saves', async () => { + const pdfDoc = await PDFDocument.load(simplePdfBytes, { + forIncrementalUpdate: true, + }); + const initialPageCount = pdfDoc.getPageCount(); + + pdfDoc.getPage(0).drawText('Before adding page'); + const firstCommit = await pdfDoc.saveAndContinue(); + + const newPage = pdfDoc.addPage(); + newPage.drawText('New page content', { x: 50, y: 700 }); + const secondCommit = await pdfDoc.saveAndContinue(); + + expect(secondCommit.byteLength).toBeGreaterThan(firstCommit.byteLength); + + const finalDoc = await PDFDocument.load(secondCommit); + expect(finalDoc.getPageCount()).toBe(initialPageCount + 1); + }); + + it('handles removing pages between saves', async () => { + const createDoc = await PDFDocument.create(); + createDoc.addPage(); + createDoc.addPage(); + createDoc.addPage(); + const multiPagePdfBytes = await createDoc.save(); + + const pdfDoc = await PDFDocument.load(multiPagePdfBytes, { + forIncrementalUpdate: true, + }); + expect(pdfDoc.getPageCount()).toBe(3); + + pdfDoc.getPage(0).drawText('First page'); + await pdfDoc.saveAndContinue(); + + pdfDoc.removePage(2); + const secondCommit = await pdfDoc.saveAndContinue(); + + const finalDoc = await PDFDocument.load(secondCommit); + expect(finalDoc.getPageCount()).toBe(2); + }); + + it('works correctly with PDFs using object streams', async () => { + const pdfDoc = await PDFDocument.load(simpleStreamsPdfBytes, { + forIncrementalUpdate: true, + }); + + pdfDoc.getPage(0).drawText('Object streams test', { x: 50, y: 200 }); + const firstCommit = await pdfDoc.saveAndContinue(); + + expect(firstCommit.byteLength).toBeGreaterThan( + simpleStreamsPdfBytes.byteLength, + ); + expect( + Array.from(firstCommit.slice(0, simpleStreamsPdfBytes.byteLength)), + ).toEqual(Array.from(simpleStreamsPdfBytes)); + + pdfDoc + .getPage(0) + .drawText('Second object streams update', { x: 50, y: 160 }); + const secondCommit = await pdfDoc.saveAndContinue(); + + expect(secondCommit.byteLength).toBeGreaterThan(firstCommit.byteLength); + + const finalDoc = await PDFDocument.load(secondCommit); + expect(finalDoc.getPageCount()).toBe(pdfDoc.getPageCount()); + }); + + it('produces valid XREF chain after multiple saves', async () => { + const pdfDoc = await PDFDocument.load(simplePdfBytes, { + forIncrementalUpdate: true, + }); + const page = pdfDoc.getPage(0); + + page.drawText('Commit 1', { x: 50, y: 700 }); + const commit1 = await pdfDoc.saveAndContinue(); + + page.drawText('Commit 2', { x: 50, y: 650 }); + const commit2 = await pdfDoc.saveAndContinue(); + + page.drawText('Commit 3', { x: 50, y: 600 }); + const commit3 = await pdfDoc.saveAndContinue(); + + page.drawText('Commit 4', { x: 50, y: 550 }); + const commit4 = await pdfDoc.saveAndContinue(); + + expect(commit2.byteLength).toBeGreaterThan(commit1.byteLength); + expect(commit3.byteLength).toBeGreaterThan(commit2.byteLength); + expect(commit4.byteLength).toBeGreaterThan(commit3.byteLength); + + const finalDoc = await PDFDocument.load(commit4); + expect(finalDoc.getPageCount()).toBe(pdfDoc.getPageCount()); + + const doc1 = await PDFDocument.load(commit1); + const doc2 = await PDFDocument.load(commit2); + const doc3 = await PDFDocument.load(commit3); + expect(doc1.getPageCount()).toBe(pdfDoc.getPageCount()); + expect(doc2.getPageCount()).toBe(pdfDoc.getPageCount()); + expect(doc3.getPageCount()).toBe(pdfDoc.getPageCount()); + }); + + it('tracks metadata changes between saves', async () => { + const pdfDoc = await PDFDocument.load(simplePdfBytes, { + forIncrementalUpdate: true, + }); + + pdfDoc.setTitle('First Title'); + pdfDoc.setAuthor('First Author'); + const firstCommit = await pdfDoc.saveAndContinue(); + + pdfDoc.setTitle('Second Title'); + pdfDoc.setAuthor('Second Author'); + const secondCommit = await pdfDoc.saveAndContinue(); + + const finalDoc = await PDFDocument.load(secondCommit); + expect(finalDoc.getTitle()).toBe('Second Title'); + expect(finalDoc.getAuthor()).toBe('Second Author'); + + const intermediateDoc = await PDFDocument.load(firstCommit); + expect(intermediateDoc.getTitle()).toBe('First Title'); + expect(intermediateDoc.getAuthor()).toBe('First Author'); + }); + + it('does not duplicate custom fonts on multiple saves', async () => { + const customFontBytes = fs.readFileSync( + 'assets/fonts/ubuntu/Ubuntu-R.ttf', + ); + const pdfDoc = await PDFDocument.load(simplePdfBytes, { + forIncrementalUpdate: true, + }); + + pdfDoc.registerFontkit(fontkit); + const customFont = await pdfDoc.embedFont(customFontBytes); + const page = pdfDoc.getPage(0); + + page.drawText('Custom font first', { + x: 50, + y: 200, + size: 20, + font: customFont, + }); + const firstCommit = await pdfDoc.saveAndContinue(); + const objectCountAfterFirst = pdfDoc.context.largestObjectNumber; + + page.drawText('Custom font second', { + x: 50, + y: 160, + size: 20, + font: customFont, + }); + const secondCommit = await pdfDoc.saveAndContinue(); + const objectCountAfterSecond = pdfDoc.context.largestObjectNumber; + + const newObjectCount = objectCountAfterSecond - objectCountAfterFirst; + expect(newObjectCount).toBeLessThan(4); + expect(secondCommit.byteLength).toBeGreaterThan(firstCommit.byteLength); + + const finalDoc = await PDFDocument.load(secondCommit); + expect(finalDoc.getPageCount()).toBe(pdfDoc.getPageCount()); + }); + + it('handles saves with no changes gracefully', async () => { + const pdfDoc = await PDFDocument.load(simplePdfBytes, { + forIncrementalUpdate: true, + }); + + pdfDoc.getPage(0).drawText('Initial change'); + const firstCommit = await pdfDoc.saveAndContinue(); + const secondCommit = await pdfDoc.saveAndContinue(); + + const doc1 = await PDFDocument.load(firstCommit); + const doc2 = await PDFDocument.load(secondCommit); + expect(doc1.getPageCount()).toBe(pdfDoc.getPageCount()); + expect(doc2.getPageCount()).toBe(pdfDoc.getPageCount()); + expect(secondCommit.byteLength).toBeGreaterThanOrEqual( + firstCommit.byteLength, + ); + }); + + it('save() still works correctly after saveAndContinue()', async () => { + const pdfDoc = await PDFDocument.load(simplePdfBytes, { + forIncrementalUpdate: true, + }); + + pdfDoc.getPage(0).drawText('Before commit'); + await pdfDoc.saveAndContinue(); + + pdfDoc.getPage(0).drawText('After commit', { y: 100 }); + const regularSave = await pdfDoc.save(); + const rewriteSave = await pdfDoc.save({ rewrite: true }); + + const doc1 = await PDFDocument.load(regularSave); + const doc2 = await PDFDocument.load(rewriteSave); + expect(doc1.getPageCount()).toBe(pdfDoc.getPageCount()); + expect(doc2.getPageCount()).toBe(pdfDoc.getPageCount()); + }); + + it('saveAndContinue() after save() works correctly', async () => { + const pdfDoc = await PDFDocument.load(simplePdfBytes, { + forIncrementalUpdate: true, + }); + + pdfDoc.getPage(0).drawText('Before save'); + const savedBytes = await pdfDoc.save(); + + pdfDoc.getPage(0).drawText('After save, before commit', { y: 100 }); + const committed = await pdfDoc.saveAndContinue(); + + const doc1 = await PDFDocument.load(savedBytes); + const doc2 = await PDFDocument.load(committed); + expect(doc1.getPageCount()).toBe(pdfDoc.getPageCount()); + expect(doc2.getPageCount()).toBe(pdfDoc.getPageCount()); + expect(committed.byteLength).toBeGreaterThan(0); + }); + + it('handles multiple fonts embedded before first commit', async () => { + const pdfDoc = await PDFDocument.load(simplePdfBytes, { + forIncrementalUpdate: true, + }); + + const page = pdfDoc.getPage(0); + const timesRoman = await pdfDoc.embedFont(StandardFonts.TimesRoman); + const helvetica = await pdfDoc.embedFont(StandardFonts.Helvetica); + const courier = await pdfDoc.embedFont(StandardFonts.Courier); + + page.drawText('Times Roman', { x: 50, y: 700, font: timesRoman }); + page.drawText('Helvetica', { x: 50, y: 650, font: helvetica }); + page.drawText('Courier', { x: 50, y: 600, font: courier }); + await pdfDoc.saveAndContinue(); + const objectCountAfterFirst = pdfDoc.context.largestObjectNumber; + + page.drawText('Times Roman 2', { x: 50, y: 500, font: timesRoman }); + page.drawText('Helvetica 2', { x: 50, y: 450, font: helvetica }); + page.drawText('Courier 2', { x: 50, y: 400, font: courier }); + await pdfDoc.saveAndContinue(); + const objectCountAfterSecond = pdfDoc.context.largestObjectNumber; + + const newObjectCount = objectCountAfterSecond - objectCountAfterFirst; + expect(newObjectCount).toBeLessThan(5); + + const finalBytes = await pdfDoc.save(); + const finalDoc = await PDFDocument.load(finalBytes); + expect(finalDoc.getPageCount()).toBe(pdfDoc.getPageCount()); + }); + + it('handles drawing on different pages between saves', async () => { + const createDoc = await PDFDocument.create(); + createDoc.addPage(); + createDoc.addPage(); + createDoc.addPage(); + const multiPageBytes = await createDoc.save(); + + const pdfDoc = await PDFDocument.load(multiPageBytes, { + forIncrementalUpdate: true, + }); + + pdfDoc.getPage(0).drawText('Page 1 - Commit 1', { x: 50, y: 700 }); + const commit1 = await pdfDoc.saveAndContinue(); + + pdfDoc.getPage(1).drawText('Page 2 - Commit 2', { x: 50, y: 700 }); + const commit2 = await pdfDoc.saveAndContinue(); + + pdfDoc.getPage(2).drawText('Page 3 - Commit 3', { x: 50, y: 700 }); + const commit3 = await pdfDoc.saveAndContinue(); + + expect(commit2.byteLength).toBeGreaterThan(commit1.byteLength); + expect(commit3.byteLength).toBeGreaterThan(commit2.byteLength); + + const finalDoc = await PDFDocument.load(commit3); + expect(finalDoc.getPageCount()).toBe(3); + }); + + it('preserves signature field widgets after incremental updates', async () => { + const signaturePdfBytes = fs.readFileSync( + 'assets/pdfs/with_signature.pdf', + ); + const pdfDoc = await PDFDocument.load(signaturePdfBytes, { + forIncrementalUpdate: true, + }); + + const originalLength = signaturePdfBytes.byteLength; + + pdfDoc.getPage(0).drawText('Incremental update preserving signature', { + x: 50, + y: 50, + }); + const committed = await pdfDoc.saveAndContinue(); + + expect(committed.byteLength).toBeGreaterThan(originalLength); + expect(Array.from(committed.slice(0, originalLength))).toEqual( + Array.from(signaturePdfBytes), + ); + + const reloadedDoc = await PDFDocument.load(committed); + expect(reloadedDoc.getPageCount()).toBe(pdfDoc.getPageCount()); + }); + + it('preserves bytes exactly for signature validity', async () => { + const pdfDoc = await PDFDocument.load(simplePdfBytes, { + forIncrementalUpdate: true, + }); + + pdfDoc.getPage(0).drawText('Update 1', { x: 50, y: 700 }); + const commit1 = await pdfDoc.saveAndContinue(); + + for (let i = 0; i < simplePdfBytes.byteLength; i++) { + expect(commit1[i]).toBe(simplePdfBytes[i]); + } + + pdfDoc.getPage(0).drawText('Update 2', { x: 50, y: 650 }); + const commit2 = await pdfDoc.saveAndContinue(); + + for (let i = 0; i < commit1.byteLength; i++) { + expect(commit2[i]).toBe(commit1[i]); + } + + expect(commit2.byteLength).toBeGreaterThan(commit1.byteLength); + }); + + it('tracks PDFArray modifications for incremental saves', async () => { + const pdfDoc = await PDFDocument.load(simplePdfBytes, { + forIncrementalUpdate: true, + }); + + const page = pdfDoc.getPage(0); + const pageDict = page.node; + const context = pdfDoc.context; + + const annotDict = context.obj({ + Type: 'Annot', + Subtype: 'Text', + Rect: [100, 100, 200, 200], + Contents: 'Test annotation', + }); + const annotRef = context.register(annotDict); + + const annotsArray = context.obj([annotRef]); + const annotsRef = context.register(annotsArray); + pageDict.set(PDFName.of('Annots'), annotsRef); + + const committed = await pdfDoc.saveAndContinue(); + + const reloaded = await PDFDocument.load(committed); + const reloadedPage = reloaded.getPage(0); + const reloadedAnnots = reloadedPage.node.lookup( + PDFName.of('Annots'), + PDFArray, + ); + expect(reloadedAnnots).toBeDefined(); + expect(reloadedAnnots!.size()).toBe(1); + }); + + it('tracks PDFArray.push() for existing arrays', async () => { + const createDoc = await PDFDocument.create(); + const createPage = createDoc.addPage(); + const createContext = createDoc.context; + + const initialAnnot = createContext.obj({ + Type: 'Annot', + Subtype: 'Text', + Rect: [10, 10, 50, 50], + Contents: 'Initial', + }); + const initialRef = createContext.register(initialAnnot); + const annotsArray = createContext.obj([initialRef]); + const annotsRef = createContext.register(annotsArray); + createPage.node.set(PDFName.of('Annots'), annotsRef); + + const initialBytes = await createDoc.save(); + + const pdfDoc = await PDFDocument.load(initialBytes, { + forIncrementalUpdate: true, + }); + + const page = pdfDoc.getPage(0); + const pageDict = page.node; + const context = pdfDoc.context; + + const existingAnnots = pageDict.lookup(PDFName.of('Annots'), PDFArray); + expect(existingAnnots).toBeDefined(); + expect(existingAnnots!.size()).toBe(1); + + const newAnnot = context.obj({ + Type: 'Annot', + Subtype: 'Text', + Rect: [100, 100, 150, 150], + Contents: 'New annotation', + }); + const newRef = context.register(newAnnot); + existingAnnots!.push(newRef); + + const committed = await pdfDoc.saveAndContinue(); + + const reloaded = await PDFDocument.load(committed); + const reloadedAnnots = reloaded + .getPage(0) + .node.lookup(PDFName.of('Annots'), PDFArray); + expect(reloadedAnnots).toBeDefined(); + expect(reloadedAnnots!.size()).toBe(2); + }); + + it('tracks PDFStream content updates for incremental saves', async () => { + const pdfDoc = await PDFDocument.load(simplePdfBytes, { + forIncrementalUpdate: true, + }); + + const page = pdfDoc.getPage(0); + page.drawText('Modified stream content', { x: 50, y: 300 }); + + const committed = await pdfDoc.saveAndContinue(); + + expect(committed.byteLength).toBeGreaterThan(simplePdfBytes.byteLength); + + const reloaded = await PDFDocument.load(committed); + expect(reloaded.getPageCount()).toBe(pdfDoc.getPageCount()); + }); + + it('throws error for encrypted PDFs with forIncrementalUpdate', async () => { + await expect( + PDFDocument.load(oldEncryptedPdfBytes1, { + forIncrementalUpdate: true, + }), + ).rejects.toThrow(); + }); + + it('tracks inline array modifications for incremental saves', async () => { + // Create a simple PDF + const createDoc = await PDFDocument.create(); + createDoc.addPage([200, 200]); + const initialBytes = await createDoc.save(); + + // Load for incremental update + const pdfDoc = await PDFDocument.load(initialBytes, { + forIncrementalUpdate: true, + }); + const page = pdfDoc.getPage(0); + + // Get the MediaBox (inline array, not registered as indirect object) + const mediaBox = page.node.lookup(PDFName.MediaBox, PDFArray); + expect(mediaBox).toBeDefined(); + + // Verify it's NOT registered (inline) + const ref = pdfDoc.context.getRef(mediaBox!); + expect(ref).toBeUndefined(); + + // Modify it directly + mediaBox!.set(2, PDFNumber.of(300)); // Change width + mediaBox!.set(3, PDFNumber.of(400)); // Change height + + // Commit + const committed = await pdfDoc.saveAndContinue(); + + // Reload and verify changes were saved + const reloaded = await PDFDocument.load(committed); + const reloadedMediaBox = reloaded + .getPage(0) + .node.lookup(PDFName.MediaBox, PDFArray); + expect(reloadedMediaBox!.lookup(2, PDFNumber).asNumber()).toBe(300); + expect(reloadedMediaBox!.lookup(3, PDFNumber).asNumber()).toBe(400); + }); }); - describe(`copy() method`, () => { + describe('copy() method', () => { let pdfDoc: PDFDocument; let srcDoc: PDFDocument; beforeAll(async () => { @@ -556,11 +1510,11 @@ describe(`PDFDocument`, () => { pdfDoc = await srcDoc.copy(); }); - it(`Returns a pdf with the same number of pages`, async () => { + it('Returns a pdf with the same number of pages', async () => { expect(pdfDoc.getPageCount()).toBe(srcDoc.getPageCount()); }); - it(`Can copy author, creationDate, creator, producer, subject, title, defaultWordBreaks`, async () => { + it('Can copy author, creationDate, creator, producer, subject, title, defaultWordBreaks', async () => { expect(pdfDoc.getAuthor()).toBe(srcDoc.getAuthor()); expect(pdfDoc.getCreationDate()).toStrictEqual(srcDoc.getCreationDate()); expect(pdfDoc.getCreator()).toBe(srcDoc.getCreator()); @@ -573,4 +1527,617 @@ describe(`PDFDocument`, () => { expect(pdfDoc.defaultWordBreaks).toEqual(srcDoc.defaultWordBreaks); }); }); + + describe(`load({forIncrementalUpdate}) cycle`, () => { + it(`can be used with different pages`, async () => { + const noErrorFunc = async (pageIndex: number) => { + const pdfDoc = await PDFDocument.load(simplePdfBytes, { + forIncrementalUpdate: true, + }); + const page = pdfDoc.getPage(pageIndex); + const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman); + const fontSize = 30; + page.drawText('Incremental saving is also awesome!', { + x: 50, + y: 4 * fontSize, + size: fontSize, + font: timesRomanFont, + }); + + const pdfIncrementalBytes = await pdfDoc.save(); + const rewritedBytes = await pdfDoc.save({ rewrite: true }); + expect(pdfIncrementalBytes.byteLength).toBeGreaterThan( + simplePdfBytes.byteLength, + ); + expect(rewritedBytes.byteLength).toBeGreaterThan(0); + expect(rewritedBytes.byteLength).toBeLessThan( + pdfIncrementalBytes.byteLength, + ); + }; + + await expect(noErrorFunc(0)).resolves.not.toThrowError(); + await expect(noErrorFunc(1)).resolves.not.toThrowError(); + }); + + it(`can be used with object-stream PDFs`, async () => { + const noErrorFunc = async () => { + const pdfDoc = await PDFDocument.load(simpleStreamsPdfBytes, { + forIncrementalUpdate: true, + }); + const page = pdfDoc.getPage(0); + const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman); + const fontSize = 30; + page.drawText('Incremental saving is also awesome!', { + x: 50, + y: 4 * fontSize, + size: fontSize, + font: timesRomanFont, + }); + + const pdfIncrementalBytes = await pdfDoc.save(); + const pdfRewriteBytes = await pdfDoc.save({ rewrite: true }); + expect(pdfIncrementalBytes.byteLength).toBeGreaterThan( + simpleStreamsPdfBytes.byteLength, + ); + expect(pdfRewriteBytes.byteLength).toBeGreaterThan( + simpleStreamsPdfBytes.byteLength, + ); + }; + + await expect(noErrorFunc()).resolves.not.toThrowError(); + }); + + it(`registers deleted objects`, async () => { + const pdfDoc = await PDFDocument.load(simplePdfBytes, { + forIncrementalUpdate: true, + }); + let page = pdfDoc.getPage(0); + const delONum = page.ref.objectNumber; + const delOGen = (page.ref.generationNumber + 1).toString(); + pdfDoc.context.delete(page.ref); + page = pdfDoc.getPage(1); + const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman); + const fontSize = 30; + page.drawText('Incremental saving is also awesome!', { + x: 50, + y: 4 * fontSize, + size: fontSize, + font: timesRomanFont, + }); + + const pdfIncrementalBytes = await pdfDoc.save({ + useObjectStreams: false, + }); + const pdfRewriteBytes = await pdfDoc.save({ + rewrite: true, + useObjectStreams: false, + }); + expect(pdfIncrementalBytes.byteLength).toBeGreaterThan( + simpleStreamsPdfBytes.byteLength, + ); + expect(pdfRewriteBytes.byteLength).toBeGreaterThan( + simpleStreamsPdfBytes.byteLength, + ); + // first element in table must point to deleted page, deleted page must have next gen number + const rex = new RegExp( + `xref[\n|\r\n]0 .*[\n|\r\n]${delONum.toString().padStart(10, '0')} 65535 f[\\s\\S]*0000000000 ${delOGen.padStart(5, '0')} f`, + ); + expect(Buffer.from(pdfIncrementalBytes).toString()).toMatch(rex); + }); + + it(`produces same output than manual incremental update`, async () => { + const noErrorFunc = async (pageIndex: number) => { + const pdfDoc = await PDFDocument.load(simplePdfBytes, { + forIncrementalUpdate: true, + }); + const snapshot = pdfDoc.takeSnapshot(); + const page = pdfDoc.getPage(pageIndex); + snapshot.markObjForSave(pdfDoc.catalog); + snapshot.markRefForSave(page.ref); + const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman); + const fontSize = 30; + page.drawText('Incremental saving is also awesome!', { + x: 50, + y: 4 * fontSize, + size: fontSize, + font: timesRomanFont, + }); + + const pdfIncrementalBytes = await pdfDoc.saveIncremental(snapshot, { + useObjectStreams: false, + }); + const finalPdfBytes = Buffer.concat([ + simplePdfBytes, + pdfIncrementalBytes, + ]); + const pdfSaveBytes = Buffer.from( + await pdfDoc.save({ useObjectStreams: false }), + ); + expect(pdfIncrementalBytes.byteLength).toBeGreaterThan(0); + expect(finalPdfBytes).toEqual(pdfSaveBytes); + }; + + await expect(noErrorFunc(0)).resolves.not.toThrowError(); + await expect(noErrorFunc(1)).resolves.not.toThrowError(); + }); + + it('registers all objects in incremental update, with or without using objects streams', async () => { + const pdfDoc = await PDFDocument.load(simplePdfBytes, { + forIncrementalUpdate: true, + }); + const originalLargestObjectNumber = pdfDoc.context.largestObjectNumber; + const page = pdfDoc.addPage([500, 300]); + const font = pdfDoc.embedStandardFont(StandardFonts.Helvetica); + const fontBold = pdfDoc.embedStandardFont( + StandardFonts.HelveticaBoldOblique, + ); + page.drawRectangle({ + x: 10, + y: 250, + width: 490, + height: 50, + borderWidth: 2, + borderColor: rgb(0.45, 0.45, 0.45), + }); + page.drawText('ELECTRONIC SIGNATURE TEST', { + x: 20, + y: 100, + size: 14, + font, + }); + page.drawText('PDF-LIB', { x: 50, y: 150, size: 12, font: fontBold }); + const byteRange = PDFArray.withContext(pdfDoc.context); + byteRange.push(PDFNumber.of(0)); + byteRange.push(PDFName.of('**********')); + byteRange.push(PDFName.of('**********')); + byteRange.push(PDFName.of('**********')); + const placeholder = PDFHexString.of(String.fromCharCode(0).repeat(2048)); + const signatureDict = pdfDoc.context.obj({ + Type: 'Sig', + Filter: 'Adobe.PPKLite', + SubFilter: 'adbe.pkcs7.detached', + ByteRange: byteRange, + Contents: placeholder, + Reason: PDFString.of('PDF-LIB Test'), + M: PDFString.fromDate(new Date()), + ContactInfo: PDFString.of('dabdala@adnsistemas.com.ar'), + Name: PDFString.of('Test'), + Location: PDFString.of('Ether'), + Prop_Build: { + Filter: { Name: 'Adobe.PPKLite' }, + }, + }); + const signatureBuffer = new Uint8Array(signatureDict.sizeInBytes()); + signatureDict.copyBytesInto(signatureBuffer, 0); + const signatureObj = PDFInvalidObject.of(signatureBuffer); + const signatureDictRef = pdfDoc.context.register(signatureObj); + const rect = PDFArray.withContext(pdfDoc.context); + const widgetRect = [0, 100, 0, 50]; + widgetRect.forEach((c) => rect.push(PDFNumber.of(c))); + const apStream = pdfDoc.context.formXObject([], { + BBox: widgetRect, + Resources: {}, + }); + const widgetDict = pdfDoc.context.obj({ + Type: 'Annot', + Subtype: 'Widget', + FT: 'Sig', + Rect: rect, + V: signatureDictRef, + T: PDFString.of('Signature1'), + F: 4, + P: page.ref, + AP: { N: pdfDoc.context.register(apStream) }, + TU: 'Testing pdf-lib signature', + }); + const widgetDictRef = pdfDoc.context.register(widgetDict); + let annotations = page.node.lookupMaybe(PDFName.of('Annots'), PDFArray); + if (typeof annotations === 'undefined') { + annotations = pdfDoc.context.obj([]); + } + annotations.push(widgetDictRef); + page.node.set(PDFName.of('Annots'), annotations); + const acroForm = pdfDoc.catalog.getOrCreateAcroForm(); + let sigFlags; + if (acroForm.dict.has(PDFName.of('SigFlags'))) { + sigFlags = acroForm.dict.get(PDFName.of('SigFlags')); + } else { + sigFlags = PDFNumber.of(0); + } + const updatedFlags = PDFNumber.of( + (sigFlags! as PDFNumber).asNumber() | 1 | 2, + ); + acroForm.dict.set(PDFName.of('SigFlags'), updatedFlags); + let fields = acroForm.dict.get(PDFName.of('Fields')); + if (!(fields instanceof PDFArray)) { + fields = pdfDoc.context.obj([]); + acroForm.dict.set(PDFName.of('Fields'), fields); + } + (fields as PDFArray).push(widgetDictRef); + const pdfSaveBytes = Buffer.from( + await pdfDoc.save({ useObjectStreams: false }), + ); + const pdfStreamBytes = Buffer.from( + await pdfDoc.save({ useObjectStreams: true }), + ); + // read the PDF and get all the information from the incremental update + const signedPDFNBS = await PDFDocument.load(pdfSaveBytes, { + preserveObjectsVersions: true, + }); + const signedPDFBS = await PDFDocument.load(pdfStreamBytes, { + preserveObjectsVersions: true, + }); + const modifiedObjects = signedPDFNBS.getChangedObjects(); + // PageTree, Catalog, PageLeaf (added page), 2 Fonts, PDFStream (Page Content), SignatureDict, Signature, SignatureWidget, WidgetDict + expect(modifiedObjects.length).toBe(10); + for (const mod of modifiedObjects) { + expect(mod.actual).toBeDefined(); + if (mod.ref.objectNumber < originalLargestObjectNumber) + expect(mod.previous.length).toBeGreaterThan(0); + else expect(mod.previous.length).toBe(0); + } + const modifiedStreamObjects = signedPDFBS.getChangedObjects(); + // PageTree, Catalog, PageLeaf (added page), 2 Fonts, PDFStream (Page Content), SignatureDict, Signature, SignatureWidget, WidgetDict, 2 x ObjectStream + expect(modifiedStreamObjects.length).toBe(12); + for (const mod of modifiedStreamObjects) { + expect(mod.actual).toBeDefined(); + if (mod.ref.objectNumber < originalLargestObjectNumber) + expect(mod.previous.length).toBeGreaterThan(0); + else expect(mod.previous.length).toBe(0); + } + }); + }); + + describe('attach() method', () => { + it('Saves to the same value after attaching a file', async () => { + const pdfDoc1 = await PDFDocument.create({ updateMetadata: false }); + const pdfDoc2 = await PDFDocument.create({ updateMetadata: false }); + + const jpgAttachmentBytes = fs.readFileSync( + 'assets/images/cat_riding_unicorn.jpg', + ); + const pdfAttachmentBytes = fs.readFileSync( + 'assets/pdfs/us_constitution.pdf', + ); + + await pdfDoc1.attach(jpgAttachmentBytes, 'cat_riding_unicorn.jpg', { + mimeType: 'image/jpeg', + description: 'Cool cat riding a unicorn! 🦄🐈🕶️', + creationDate: new Date('2019/12/01'), + modificationDate: new Date('2020/04/19'), + }); + + await pdfDoc1.attach(pdfAttachmentBytes, 'us_constitution.pdf', { + mimeType: 'application/pdf', + description: 'Constitution of the United States 🇺🇸🦅', + creationDate: new Date('1787/09/17'), + modificationDate: new Date('1992/05/07'), + }); + + await pdfDoc2.attach(jpgAttachmentBytes, 'cat_riding_unicorn.jpg', { + mimeType: 'image/jpeg', + description: 'Cool cat riding a unicorn! 🦄🐈🕶️', + creationDate: new Date('2019/12/01'), + modificationDate: new Date('2020/04/19'), + }); + + await pdfDoc2.attach(pdfAttachmentBytes, 'us_constitution.pdf', { + mimeType: 'application/pdf', + description: 'Constitution of the United States 🇺🇸🦅', + creationDate: new Date('1787/09/17'), + modificationDate: new Date('1992/05/07'), + }); + + const savedDoc1 = await pdfDoc1.save(); + const savedDoc2 = await pdfDoc2.save(); + + expect(savedDoc1).toEqual(savedDoc2); + }); + }); + + describe('getAttachments() method', () => { + it('Can read attachments from an existing pdf file', async () => { + const pdfDoc = await PDFDocument.load(hasAttachmentPdfBytes); + const attachments = pdfDoc.getAttachments(); + expect(attachments.length).toEqual(2); + const jpgAttachment = attachments.find( + (attachment) => attachment.name === 'cat_riding_unicorn.jpg', + )!; + const pdfAttachment = attachments.find( + (attachment) => attachment.name === 'us_constitution.pdf', + )!; + expect(pdfAttachment).toBeDefined(); + expect(jpgAttachment).toBeDefined(); + expect(jpgAttachment.description).toBe( + 'Cool cat riding a unicorn! 🦄🐈🕶️', + ); + expect(pdfAttachment.description).toBe( + 'Constitution of the United States 🇺🇸🦅', + ); + expect(jpgAttachment.mimeType).toBe('image/jpeg'); + expect(pdfAttachment.mimeType).toBe('application/pdf'); + expect(jpgAttachment.afRelationship).not.toBeDefined(); + expect(pdfAttachment.afRelationship).not.toBeDefined(); + const jpgAttachmentBytes = fs.readFileSync( + 'assets/images/cat_riding_unicorn.jpg', + ); + const pdfAttachmentBytes = fs.readFileSync( + 'assets/pdfs/us_constitution.pdf', + ); + expect(jpgAttachmentBytes).toEqual(Buffer.from(jpgAttachment.data)); + expect(pdfAttachmentBytes).toEqual(Buffer.from(pdfAttachment.data)); + }); + + it('Can get saved and unsaved attachments', async () => { + const pdfDoc = await PDFDocument.load(hasAttachmentPdfBytes); + const haiku = `Cradled in silence, + sunlight warms the fragile shell — + breakfast is reborn.`; + const creationDate = new Date(Date.now() - 60 * 60 * 1000); + const modificationDate = new Date(); + await pdfDoc.attach(Buffer.from(haiku), 'haiku.txt', { + mimeType: 'text/plain', + description: '🥚 Haikus are short. So is the life of an egg. 🍳', + afRelationship: AFRelationship.Supplement, + creationDate, + modificationDate, + }); + await pdfDoc.attach(examplePngImage, 'example.png', { + mimeType: 'image/png', + description: 'An example image', + afRelationship: AFRelationship.Alternative, + creationDate, + modificationDate, + }); + + const attachments = pdfDoc.getAttachments(); + expect(attachments.length).toEqual(4); + const jpgAttachment = attachments.find( + (attachment) => attachment.name === 'cat_riding_unicorn.jpg', + )!; + const pdfAttachment = attachments.find( + (attachment) => attachment.name === 'us_constitution.pdf', + )!; + const txtAttachment = attachments.find( + (attachment) => attachment.name === 'haiku.txt', + )!; + const pngAttachment = attachments.find( + (attachment) => attachment.name === 'example.png', + )!; + expect(pdfAttachment).toBeDefined(); + expect(jpgAttachment).toBeDefined(); + expect(txtAttachment).toBeDefined(); + expect(jpgAttachment.description).toBe( + 'Cool cat riding a unicorn! 🦄🐈🕶️', + ); + expect(pdfAttachment.description).toBe( + 'Constitution of the United States 🇺🇸🦅', + ); + expect(txtAttachment.description).toBe( + '🥚 Haikus are short. So is the life of an egg. 🍳', + ); + expect(pngAttachment.description).toBe('An example image'); + expect(jpgAttachment.mimeType).toBe('image/jpeg'); + expect(pdfAttachment.mimeType).toBe('application/pdf'); + expect(txtAttachment.mimeType).toBe('text/plain'); + expect(pngAttachment.mimeType).toBe('image/png'); + expect(jpgAttachment.afRelationship).not.toBeDefined(); + expect(pdfAttachment.afRelationship).not.toBeDefined(); + expect(txtAttachment.afRelationship).toBe(AFRelationship.Supplement); + expect(pngAttachment.afRelationship).toBe(AFRelationship.Alternative); + const jpgAttachmentBytes = fs.readFileSync( + 'assets/images/cat_riding_unicorn.jpg', + ); + const pdfAttachmentBytes = fs.readFileSync( + 'assets/pdfs/us_constitution.pdf', + ); + expect(jpgAttachmentBytes).toEqual(Buffer.from(jpgAttachment.data)); + expect(pdfAttachmentBytes).toEqual(Buffer.from(pdfAttachment.data)); + expect(new TextDecoder().decode(txtAttachment.data)).toBe(haiku); + const expectedImageBytes = Uint8Array.from( + atob(examplePngImageBase64), + (c) => c.charCodeAt(0), + ); + expect(pngAttachment.data).toEqual(expectedImageBytes); + expect(jpgAttachment.creationDate).toBeDefined(); + expect(pdfAttachment.creationDate).toBeDefined(); + expect(txtAttachment.creationDate).toBe(creationDate); + expect(pngAttachment.creationDate).toBe(creationDate); + expect(jpgAttachment.modificationDate).toBeDefined(); + expect(pdfAttachment.modificationDate).toBeDefined(); + expect(txtAttachment.modificationDate).toBe(modificationDate); + expect(pngAttachment.modificationDate).toBe(modificationDate); + }); + + describe('allow attachment data to be passed in different formats', () => { + let pdfDoc: PDFDocument; + const mimeType = 'text/plain'; + const description = '🥚 Haikus are short. So is the life of an egg. 🍳'; + const attachment = `Cradled in silence, + sunlight warms the fragile shell — + breakfast is reborn.`; + const afRelationship = AFRelationship.Alternative; + let attachments: PDFAttachment[]; + + beforeAll(async () => { + const parseSpeed = ParseSpeeds.Fastest; + pdfDoc = await PDFDocument.load(unencryptedPdfBytes, { parseSpeed }); + const base64 = Buffer.from(attachment).toString('base64'); + const dataUrl = `data:${mimeType};base64,${base64}`; + + await pdfDoc.attach(dataUrl, 'string.txt', { + mimeType, + description, + afRelationship, + }); + + await pdfDoc.attach( + new TextEncoder().encode(attachment), + 'uint8array.txt', + { + mimeType, + description, + afRelationship, + }, + ); + + await pdfDoc.attach(Buffer.from(attachment), 'buffer.txt', { + mimeType, + description, + afRelationship, + }); + + const pdfBytes = await pdfDoc.save(); + pdfDoc = await PDFDocument.load(pdfBytes); + attachments = pdfDoc.getAttachments(); + }); + + it('should attach 3 attachments', () => { + expect(attachments).toHaveLength(3); + }); + + it('should attach data URL attachments', () => { + const stringAttachments = attachments.filter( + (a) => a.name === 'string.txt', + ); + expect(stringAttachments.length).toBe(1); + const extracted = new TextDecoder().decode(stringAttachments[0].data); + expect(extracted).toEqual(attachment); + expect(stringAttachments[0].mimeType).toBe(mimeType); + expect(stringAttachments[0].afRelationship).toBe(afRelationship); + expect(stringAttachments[0].description).toBe(description); + }); + + it('should attach Uint8Array attachments', () => { + const stringAttachments = attachments.filter( + (a) => a.name === 'uint8array.txt', + ); + expect(stringAttachments.length).toBe(1); + const extracted = new TextDecoder().decode(stringAttachments[0].data); + expect(extracted).toEqual(attachment); + expect(stringAttachments[0].mimeType).toBe(mimeType); + expect(stringAttachments[0].afRelationship).toBe(afRelationship); + expect(stringAttachments[0].description).toBe(description); + }); + + it('should attach buffer attachments', () => { + const stringAttachments = attachments.filter( + (a) => a.name === 'buffer.txt', + ); + expect(stringAttachments.length).toBe(1); + const extracted = new TextDecoder().decode(stringAttachments[0].data); + expect(extracted).toEqual(attachment); + expect(stringAttachments[0].mimeType).toBe(mimeType); + expect(stringAttachments[0].afRelationship).toBe(afRelationship); + expect(stringAttachments[0].description).toBe(description); + }); + }); + }); + + describe('detach() method', () => { + it('removes the specified attachment', async () => { + const pdfDoc = await PDFDocument.load(hasAttachmentPdfBytes); + let attachments = pdfDoc.getAttachments(); + expect(attachments.length).toEqual(2); + + pdfDoc.detach('cat_riding_unicorn.jpg'); + attachments = pdfDoc.getAttachments(); + expect(attachments.length).toEqual(1); + expect(attachments[0].name).toEqual('us_constitution.pdf'); + pdfDoc.detach('us_constitution.pdf'); + attachments = pdfDoc.getAttachments(); + expect(attachments.length).toEqual(0); + }); + + it('removes the attachment after saving', async () => { + const pdfDoc = await PDFDocument.load(hasAttachmentPdfBytes); + pdfDoc.attach(examplePngImage, 'example.png', { + mimeType: 'image/png', + description: 'An example image', + }); + await pdfDoc.saveAsBase64(); + let attachments = pdfDoc.getAttachments(); + expect(attachments.length).toEqual(3); + pdfDoc.detach('example.png'); + attachments = pdfDoc.getAttachments(); + expect(attachments.length).toEqual(2); + }); + + it('does nothing if the specified attachment is not found', async () => { + const pdfDoc = await PDFDocument.load(hasAttachmentPdfBytes); + let attachments = pdfDoc.getAttachments(); + expect(attachments.length).toEqual(2); + + pdfDoc.detach('not_existing.txt'); + attachments = pdfDoc.getAttachments(); + expect(attachments.length).toEqual(2); + }); + }); + + describe('getChangedObjects', () => { + const pdfBytes = fs.readFileSync('./assets/pdfs/with_update_sections.pdf'); + + it('returns an empty array if not open for preserving objects versions', async () => { + const pdfDoc = await PDFDocument.load(pdfBytes, { + preserveObjectsVersions: false, + }); + expect(pdfDoc.getChangedObjects().length).toBe(0); + }); + + it("doesn't preserves objects versions by default", async () => { + const pdfDoc = await PDFDocument.load(pdfBytes); + expect(pdfDoc.getChangedObjects().length).toBe(0); + }); + + it('returns the actual state and previous versions of last updated objects', async () => { + const pdfDoc = await PDFDocument.load(pdfBytes, { + preserveObjectsVersions: true, + }); + const list = pdfDoc.getChangedObjects(); + expect(list.length).toBeGreaterThan(0); + for (const ov of list) { + if (!ov.actual) { + expect(ov.previous.length).toBeGreaterThan(0); + } else if (ov.previous.length) { + expect(ov.actual.constructor.name).toBe( + ov.previous[0].constructor.name, + ); + } + } + }); + + it('returns the actual state and previous versions of previous updates, updated objects', async () => { + const pdfDoc = await PDFDocument.load(pdfBytes, { + preserveObjectsVersions: true, + }); + const list2 = pdfDoc.getChangedObjects(2); + expect(list2.length).toBeGreaterThan(0); + // objects in this update, if exists in subsequent updates, should have an additional previos value + const list1 = pdfDoc.getChangedObjects(1); + expect(list1.length).toBeGreaterThan(0); + const list0 = pdfDoc.getChangedObjects(); + expect(list0.length).toBeGreaterThan(0); + for (const l2o of list2) { + const l1o = list1.find( + (l1o) => l1o.ref.objectNumber === l2o.ref.objectNumber, + ); + if (l1o) { + expect(l1o.previous.length).toBe(l2o.previous.length + 1); + expect(l1o.previous[0]).toEqual(l2o.actual); + } + const l0o = list0.find( + (l0o) => l0o.ref.objectNumber === l2o.ref.objectNumber, + ); + if (l0o) { + if (l1o) { + expect(l0o.previous.length).toBe(l2o.previous.length + 2); + expect(l0o.previous[1]).toEqual(l2o.actual); + } else { + expect(l0o.previous.length).toBe(l2o.previous.length + 1); + expect(l0o.previous[0]).toEqual(l2o.actual); + } + } + } + }); + }); }); diff --git a/tests/api/PDFImage.spec.ts b/tests/api/PDFImage.spec.ts index 5ed03b63d..b0e901b9d 100644 --- a/tests/api/PDFImage.spec.ts +++ b/tests/api/PDFImage.spec.ts @@ -1,13 +1,13 @@ -import { PDFDocument, PDFImage } from 'src/api'; -import { PngEmbedder } from 'src/core'; -import { toUint8Array } from 'src/utils'; +import { PDFDocument, PDFImage } from '../../src/api'; +import { PngEmbedder } from '../../src/core'; +import { toUint8Array } from '../../src/utils'; const examplePngImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TxaoVBzuIdMhQnSyIijhKFYtgobQVWnUwufQLmjQkKS6OgmvBwY/FqoOLs64OroIg+AHi5uak6CIl/i8ptIjx4Lgf7+497t4BQqPCVLNrAlA1y0jFY2I2tyr2vKIfAgLoRVhipp5IL2bgOb7u4ePrXZRneZ/7cwwoeZMBPpF4jumGRbxBPLNp6Zz3iUOsJCnE58TjBl2Q+JHrsstvnIsOCzwzZGRS88QhYrHYwXIHs5KhEk8TRxRVo3wh67LCeYuzWqmx1j35C4N5bSXNdZphxLGEBJIQIaOGMiqwEKVVI8VEivZjHv4Rx58kl0yuMhg5FlCFCsnxg//B727NwtSkmxSMAd0vtv0xCvTsAs26bX8f23bzBPA/A1da219tALOfpNfbWuQIGNwGLq7bmrwHXO4Aw0+6ZEiO5KcpFArA+xl9Uw4YugX61tzeWvs4fQAy1NXyDXBwCIwVKXvd492Bzt7+PdPq7wcdn3KFLu4iBAAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAlFJREFUeNrt289r02AYB/Dvk6Sl4EDKpllTlFKsnUdBHXgUBEHwqHj2IJ72B0zwKHhxJ08i/gDxX/AiRfSkBxELXTcVxTa2s2xTsHNN8ngQbQL70RZqG/Z9b29JnvflkydP37whghG3ZaegoxzfwB5vBCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgwB5rstWPtnP0LqBX/vZNyLF6vVrpN/hucewhb4g+B2AyAwiwY7NGOXijviS9vBeYh6CEP4edBLDADCAAAQhAAAIQgAAEIAABCDAUAFF/GIN1DM+PBYCo/ohMXDQ1WPjoeUZH1mMBEEh0oqLGvsHCy0S4NzWVWotJBogbvZB+brDwQT7UWSmXy5sxyQB9HQEROdVv4HQ+vx+QmS4iXsWmCK7Usu8AhOqAXMzlcn3VgWTbugQgEYrxMkZ/gyUPgnuhe2C6/Stxvdeg2ezMJERvhOuoZ+JBrNYBRuDdBtDuXkDM25nCHLbZSv9X6A4VHU+DpwCcbvbjcetLtTaOANtuirrux08HM0euisjDEMKC7RQuq+C+pVJqpzx3NZ3+eeBza9I0rWJgyHnxg2sAJrqnaHUzFcyN60Jox13hprv8aNopZBS4GcqWWVHM+lAkN0zY7ncgkYBukRoKLPpiXVj9UFkfV4Bdl8Jf60u3IMZZAG/6iLuhkDvaSZ74VqtUx3kp3NN7gUZt8RmA43a2eEY1OCfQ04AcBpAGkAKwpkBLIG8BfQE/eNJsvG/G4VlARj0BfjDBx2ECEIAABCAAAQhAAAIQgAAE+P/tN8YvpvbTDBOlAAAAAElFTkSuQmCC'; -describe(`PDFImage`, () => { - describe(`embed() method`, () => { - it(`clears the 'embedder' field after the first call`, async () => { +describe('PDFImage', () => { + describe('embed() method', () => { + it("clears the 'embedder' field after the first call", async () => { const pdfDoc = await PDFDocument.create(); const bytes = toUint8Array(examplePngImage); @@ -21,7 +21,7 @@ describe(`PDFImage`, () => { expect(pdfImage[embedderVariable]).toBeUndefined(); }); - it(`may be called multiple times without causing an error`, async () => { + it('may be called multiple times without causing an error', async () => { const pdfDoc = await PDFDocument.create(); const bytes = toUint8Array(examplePngImage); @@ -33,7 +33,7 @@ describe(`PDFImage`, () => { await expect(pdfImage.embed()).resolves.not.toThrowError(); }); - it(`may be called in parallel without causing an error`, async () => { + it('may be called in parallel without causing an error', async () => { const pdfDoc = await PDFDocument.create(); const bytes = toUint8Array(examplePngImage); diff --git a/tests/api/PDFPage.spec.ts b/tests/api/PDFPage.spec.ts index 3a5f0a949..00009ee6a 100644 --- a/tests/api/PDFPage.spec.ts +++ b/tests/api/PDFPage.spec.ts @@ -1,11 +1,12 @@ import fs from 'fs'; -import { PDFArray, PDFDocument, PDFName, StandardFonts } from 'src/index'; +import { PDFArray, PDFDocument, PDFName, StandardFonts } from '../../src/index'; const birdPng = fs.readFileSync('assets/images/greyscale_bird.png'); +const simplePDF = fs.readFileSync('assets/pdfs/simple.pdf'); -describe(`PDFDocument`, () => { - describe(`getSize() method`, () => { - it(`returns the width and height of the the page's MediaBox`, async () => { +describe('PDFDocument', () => { + describe('getSize() method', () => { + it("returns the width and height of the the page's MediaBox", async () => { const pdfDoc = await PDFDocument.create(); const page = pdfDoc.addPage(); page.node.set(PDFName.MediaBox, pdfDoc.context.obj([5, 5, 20, 50])); @@ -13,8 +14,45 @@ describe(`PDFDocument`, () => { }); }); - describe(`setSize() method`, () => { - it(`sets the width and height of only the the page's MediaBox when the other boxes are not defined`, async () => { + describe('page adding', () => { + it('adds page with sizes to existing doc', async () => { + const pdfDoc = await PDFDocument.load(simplePDF, { + forIncrementalUpdate: true, + }); + const ipc = pdfDoc.getPageCount(); + pdfDoc.addPage([500, 200]); + expect(pdfDoc.getPageCount()).toBe(ipc + 1); + }); + + it('adds pages to existing doc', async () => { + const pdfDoc = await PDFDocument.load(simplePDF, { + forIncrementalUpdate: true, + }); + const ipc = pdfDoc.getPageCount(); + pdfDoc.addPage(); + pdfDoc.insertPage(0); + expect(pdfDoc.getPageCount()).toBe(ipc + 2); + }); + }); + + describe('page deletion', () => { + it('deletes pages', async () => { + const pdfDoc = await PDFDocument.load(simplePDF, { + forIncrementalUpdate: true, + }); + const p0Num = pdfDoc.getPage(0).ref.objectNumber; + pdfDoc.removePage(0); + expect(pdfDoc.getPageCount()).toBe(1); + const pdfBytes = await pdfDoc.save({ useObjectStreams: false }); + const rex = new RegExp( + `xref[\r\n|\n]0 .*[\r\n|\n]${p0Num.toString().padStart(10, '0')} 65535 f`, + ); + expect(Buffer.from(pdfBytes).toString()).toMatch(rex); + }); + }); + + describe('setSize() method', () => { + it("sets the width and height of only the the page's MediaBox when the other boxes are not defined", async () => { const pdfDoc = await PDFDocument.create(); const page = pdfDoc.addPage(); @@ -36,7 +74,7 @@ describe(`PDFDocument`, () => { expect(page.node.ArtBox()).toBeUndefined(); }); - it(`sets the width and height of the the page's CropBox, BleedBox, TrimBox, and ArtBox when they equal the MediaBox`, async () => { + it("sets the width and height of the the page's CropBox, BleedBox, TrimBox, and ArtBox when they equal the MediaBox", async () => { const pdfDoc = await PDFDocument.create(); const page = pdfDoc.addPage(); @@ -67,7 +105,7 @@ describe(`PDFDocument`, () => { expect(page.getArtBox()).toEqual({ x: 5, y: 5, width: 15, height: 45 }); }); - it(`does not set the width and height of the the page's CropBox, BleedBox, TrimBox, or ArtBox when they do not equal the MediaBox`, async () => { + it("does not set the width and height of the the page's CropBox, BleedBox, TrimBox, or ArtBox when they do not equal the MediaBox", async () => { const pdfDoc = await PDFDocument.create(); const page = pdfDoc.addPage(); @@ -100,7 +138,7 @@ describe(`PDFDocument`, () => { }); // https://github.com/Hopding/pdf-lib/issues/1075 - it(`drawImage() does not reuse existing XObject keys`, async () => { + it('drawImage() does not reuse existing XObject keys', async () => { const pdfDoc1 = await PDFDocument.create(); const image1 = await pdfDoc1.embedPng(birdPng); const page1 = pdfDoc1.addPage(); @@ -125,7 +163,7 @@ describe(`PDFDocument`, () => { }); // https://github.com/Hopding/pdf-lib/issues/1075 - it(`setFont() does not reuse existing Font keys`, async () => { + it('setFont() does not reuse existing Font keys', async () => { const pdfDoc1 = await PDFDocument.create(); const font1 = await pdfDoc1.embedFont(StandardFonts.Helvetica); const page1 = pdfDoc1.addPage(); diff --git a/tests/api/form/PDFCheckBox.spec.ts b/tests/api/form/PDFCheckBox.spec.ts index 31230f746..85dae54ed 100644 --- a/tests/api/form/PDFCheckBox.spec.ts +++ b/tests/api/form/PDFCheckBox.spec.ts @@ -1,11 +1,11 @@ import fs from 'fs'; -import { PDFDocument, AnnotationFlags } from 'src/index'; +import { PDFDocument, AnnotationFlags } from '../../../src/index'; const fancyFieldsPdfBytes = fs.readFileSync('assets/pdfs/fancy_fields.pdf'); const pdfDocPromise = PDFDocument.load(fancyFieldsPdfBytes); -describe(`PDFCheckBox`, () => { - it(`can read its value`, async () => { +describe('PDFCheckBox', () => { + it('can read its value', async () => { const pdfDoc = await pdfDocPromise; const form = pdfDoc.getForm(); @@ -25,7 +25,7 @@ describe(`PDFCheckBox`, () => { expect(everLetMeDown.isChecked()).toBe(false); }); - it(`can read its flag states`, async () => { + it('can read its flag states', async () => { const pdfDoc = await pdfDocPromise; const form = pdfDoc.getForm(); @@ -37,7 +37,7 @@ describe(`PDFCheckBox`, () => { expect(isAFairy.isRequired()).toBe(false); }); - it(`produces printable widgets when added to a page`, async () => { + it('produces printable widgets when added to a page', async () => { const pdfDoc = await PDFDocument.create(); const page = pdfDoc.addPage(); @@ -53,7 +53,7 @@ describe(`PDFCheckBox`, () => { expect(widgets()[0].hasFlag(AnnotationFlags.Print)).toBe(true); }); - it(`sets page reference when added to a page`, async () => { + it('sets page reference when added to a page', async () => { const pdfDoc = await PDFDocument.create(); const page = pdfDoc.addPage(); diff --git a/tests/api/form/PDFDropdown.spec.ts b/tests/api/form/PDFDropdown.spec.ts index 82daeed0c..404000605 100644 --- a/tests/api/form/PDFDropdown.spec.ts +++ b/tests/api/form/PDFDropdown.spec.ts @@ -1,10 +1,10 @@ import fs from 'fs'; -import { PDFDocument, AnnotationFlags } from 'src/index'; +import { PDFDocument, AnnotationFlags } from '../../../src'; const fancyFieldsPdfBytes = fs.readFileSync('assets/pdfs/fancy_fields.pdf'); -describe(`PDFDropdown`, () => { - it(`can read its options`, async () => { +describe('PDFDropdown', () => { + it('can read its options', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); const gundams = form.getDropdown('Choose A Gundam 🤖'); @@ -16,14 +16,14 @@ describe(`PDFDropdown`, () => { ]); }); - it(`can read its selected value`, async () => { + it('can read its selected value', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); const gundams = form.getDropdown('Choose A Gundam 🤖'); expect(gundams.getSelected()).toEqual(['Dynames']); }); - it(`can clear its value`, async () => { + it('can clear its value', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); const gundams = form.getDropdown('Choose A Gundam 🤖'); @@ -31,7 +31,7 @@ describe(`PDFDropdown`, () => { expect(gundams.getSelected()).toEqual([]); }); - it(`can select a single value`, async () => { + it('can select a single value', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); const gundams = form.getDropdown('Choose A Gundam 🤖'); @@ -39,7 +39,7 @@ describe(`PDFDropdown`, () => { expect(gundams.getSelected()).toEqual(['Kyrios']); }); - it(`can select multiple values`, async () => { + it('can select multiple values', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); const gundams = form.getDropdown('Choose A Gundam 🤖'); @@ -47,7 +47,7 @@ describe(`PDFDropdown`, () => { expect(gundams.getSelected()).toEqual(['Exia', 'Virtue']); }); - it(`can select a value not in the options list`, async () => { + it('can select a value not in the options list', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); const gundams = form.getDropdown('Choose A Gundam 🤖'); @@ -61,7 +61,7 @@ describe(`PDFDropdown`, () => { expect(gundams.getSelected()).toEqual(['One Punch Man']); }); - it(`can merge options when selecting`, async () => { + it('can merge options when selecting', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); const gundams = form.getDropdown('Choose A Gundam 🤖'); @@ -69,7 +69,7 @@ describe(`PDFDropdown`, () => { expect(gundams.getSelected()).toEqual(['Dynames', 'Exia']); }); - it(`can read its flag states`, async () => { + it('can read its flag states', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); const gundams = form.getDropdown('Choose A Gundam 🤖'); @@ -84,7 +84,7 @@ describe(`PDFDropdown`, () => { expect(gundams.isSpellChecked()).toBe(true); }); - it(`produces printable widgets when added to a page`, async () => { + it('produces printable widgets when added to a page', async () => { const pdfDoc = await PDFDocument.create(); const page = pdfDoc.addPage(); @@ -100,7 +100,7 @@ describe(`PDFDropdown`, () => { expect(widgets()[0].hasFlag(AnnotationFlags.Print)).toBe(true); }); - it(`sets page reference when added to a page`, async () => { + it('sets page reference when added to a page', async () => { const pdfDoc = await PDFDocument.create(); const page = pdfDoc.addPage(); diff --git a/tests/api/form/PDFForm.spec.ts b/tests/api/form/PDFForm.spec.ts index 63c8edbcc..4060754c3 100644 --- a/tests/api/form/PDFForm.spec.ts +++ b/tests/api/form/PDFForm.spec.ts @@ -13,7 +13,7 @@ import { PDFForm, PDFAcroForm, PDFRef, -} from 'src/index'; +} from '../../../src/index'; const getWidgets = (pdfDoc: PDFDocument) => pdfDoc.context @@ -53,7 +53,7 @@ const fancyFieldsPdfBytes = fs.readFileSync('assets/pdfs/fancy_fields.pdf'); const xfaPdfBytes = fs.readFileSync('assets/pdfs/with_xfa_fields.pdf'); const signaturePdfBytes = fs.readFileSync('assets/pdfs/with_signature.pdf'); -describe(`PDFForm`, () => { +describe('PDFForm', () => { const origConsoleWarn = console.warn; beforeAll(() => { @@ -75,7 +75,7 @@ describe(`PDFForm`, () => { }); // prettier-ignore - it(`provides access to all terminal fields in an AcroForm`, async () => { + it('provides access to all terminal fields in an AcroForm', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); const fields = form.getFields(); @@ -119,7 +119,7 @@ describe(`PDFForm`, () => { }); // Need to also run this test with assets/pdfs/with_xfa_fields.pdf as it has "partial/50%" APs for checkboxes (is only missing the /Off APs) - it(`does not override existing appearance streams for check boxes and radio groups if they already exist`, async () => { + it('does not override existing appearance streams for check boxes and radio groups if they already exist', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); @@ -170,7 +170,7 @@ describe(`PDFForm`, () => { expect(flatten(widgets.map(getApRefs))).toEqual(originalAps); }); - it(`creates appearance streams for widgets that do not have any`, async () => { + it('creates appearance streams for widgets that do not have any', async () => { const pdfDoc = await PDFDocument.create(); const page = pdfDoc.addPage(); @@ -211,7 +211,7 @@ describe(`PDFForm`, () => { expect(aps()).toBe(5); }); - it(`removes XFA entries when it is accessed`, async () => { + it('removes XFA entries when it is accessed', async () => { const pdfDoc = await PDFDocument.load(xfaPdfBytes); const acroForm = pdfDoc.catalog.getOrCreateAcroForm(); expect(acroForm.dict.has(PDFName.of('XFA'))).toBe(true); @@ -219,14 +219,14 @@ describe(`PDFForm`, () => { expect(acroForm.dict.has(PDFName.of('XFA'))).toBe(false); }); - it(`is only created if it is accessed`, async () => { + it('is only created if it is accessed', async () => { const pdfDoc = await PDFDocument.create(); expect(pdfDoc.catalog.getAcroForm()).toBe(undefined); expect(pdfDoc.getForm()).toBeInstanceOf(PDFForm); expect(pdfDoc.catalog.getAcroForm()).toBeInstanceOf(PDFAcroForm); }); - it(`does not update appearance streams if "updateFieldAppearances" is true, but no fields are dirty`, async () => { + it('does not update appearance streams if "updateFieldAppearances" is true, but no fields are dirty', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const widgets = getWidgets(pdfDoc); @@ -242,7 +242,7 @@ describe(`PDFForm`, () => { expect(aps()).toBe(0); }); - it(`does not update appearance streams if "updateFieldAppearances" is false, even if fields are dirty`, async () => { + it('does not update appearance streams if "updateFieldAppearances" is false, even if fields are dirty', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const widgets = getWidgets(pdfDoc); @@ -261,7 +261,7 @@ describe(`PDFForm`, () => { expect(aps()).toBe(0); }); - it(`does update appearance streams if "updateFieldAppearances" is true, and fields are dirty`, async () => { + it('does update appearance streams if "updateFieldAppearances" is true, and fields are dirty', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const widgets = getWidgets(pdfDoc); @@ -280,7 +280,7 @@ describe(`PDFForm`, () => { expect(aps()).toBe(20); }); - it(`does not throw errors for PDFSignature fields`, async () => { + it('does not throw errors for PDFSignature fields', async () => { const pdfDoc = await PDFDocument.load(signaturePdfBytes); const widgets = getWidgets(pdfDoc); @@ -295,7 +295,7 @@ describe(`PDFForm`, () => { ).resolves.toBeInstanceOf(Uint8Array); }); - it(`it cleans references of removed fields and their widgets`, async () => { + it('it cleans references of removed fields and their widgets', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); @@ -328,7 +328,7 @@ describe(`PDFForm`, () => { rgWidgetRefs.forEach((ref) => expect(refs2).not.toContain(ref)); }); - it(`it cleans references of removed fields and their widgets when created with pdf-lib`, async () => { + it('it cleans references of removed fields and their widgets when created with pdf-lib', async () => { const pdfDoc = await PDFDocument.create(); const page = pdfDoc.addPage(); const form = pdfDoc.getForm(); diff --git a/tests/api/form/PDFOptionList.spec.ts b/tests/api/form/PDFOptionList.spec.ts index ef4be4e85..0026b546d 100644 --- a/tests/api/form/PDFOptionList.spec.ts +++ b/tests/api/form/PDFOptionList.spec.ts @@ -1,24 +1,24 @@ import fs from 'fs'; -import { PDFDocument, AnnotationFlags } from 'src/index'; +import { PDFDocument, AnnotationFlags } from '../../../src/index'; const fancyFieldsPdfBytes = fs.readFileSync('assets/pdfs/fancy_fields.pdf'); -describe(`PDFOptionList`, () => { - it(`can read its options`, async () => { +describe('PDFOptionList', () => { + it('can read its options', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); const planets = form.getOptionList('Which Are Planets? 🌎'); expect(planets.getOptions()).toEqual(['Earth', 'Mars', 'Pluto', 'Neptune']); }); - it(`can read its selected value`, async () => { + it('can read its selected value', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); const planets = form.getOptionList('Which Are Planets? 🌎'); expect(planets.getSelected()).toEqual(['Mars']); }); - it(`can clear its value`, async () => { + it('can clear its value', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); const planets = form.getOptionList('Which Are Planets? 🌎'); @@ -26,7 +26,7 @@ describe(`PDFOptionList`, () => { expect(planets.getSelected()).toEqual([]); }); - it(`can select a single value`, async () => { + it('can select a single value', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); const planets = form.getOptionList('Which Are Planets? 🌎'); @@ -34,7 +34,7 @@ describe(`PDFOptionList`, () => { expect(planets.getSelected()).toEqual(['Neptune']); }); - it(`can select multiple values`, async () => { + it('can select multiple values', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); const planets = form.getOptionList('Which Are Planets? 🌎'); @@ -42,14 +42,14 @@ describe(`PDFOptionList`, () => { expect(planets.getSelected()).toEqual(['Pluto', 'Neptune']); }); - it(`can't select a value not in the options list`, async () => { + it("can't select a value not in the options list", async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); const planets = form.getOptionList('Which Are Planets? 🌎'); expect(() => planets.select('One Punch Man')).toThrow(); }); - it(`can merge options when selecting`, async () => { + it('can merge options when selecting', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); const planets = form.getOptionList('Which Are Planets? 🌎'); @@ -57,7 +57,7 @@ describe(`PDFOptionList`, () => { expect(planets.getSelected()).toEqual(['Mars', 'Pluto']); }); - it(`can read its flag states`, async () => { + it('can read its flag states', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); const planets = form.getOptionList('Which Are Planets? 🌎'); @@ -70,7 +70,7 @@ describe(`PDFOptionList`, () => { expect(planets.isSorted()).toBe(false); }); - it(`produces printable widgets when added to a page`, async () => { + it('produces printable widgets when added to a page', async () => { const pdfDoc = await PDFDocument.create(); const page = pdfDoc.addPage(); @@ -86,7 +86,7 @@ describe(`PDFOptionList`, () => { expect(widgets()[0].hasFlag(AnnotationFlags.Print)).toBe(true); }); - it(`sets page reference when added to a page`, async () => { + it('sets page reference when added to a page', async () => { const pdfDoc = await PDFDocument.create(); const page = pdfDoc.addPage(); diff --git a/tests/api/form/PDFRadioGroup.spec.ts b/tests/api/form/PDFRadioGroup.spec.ts index 59315c922..966f8dd9c 100644 --- a/tests/api/form/PDFRadioGroup.spec.ts +++ b/tests/api/form/PDFRadioGroup.spec.ts @@ -5,12 +5,12 @@ import { PDFArray, PDFHexString, AnnotationFlags, -} from 'src/index'; +} from '../../../src/index'; const fancyFieldsPdfBytes = fs.readFileSync('assets/pdfs/fancy_fields.pdf'); -describe(`PDFRadioGroup`, () => { - it(`can read its options`, async () => { +describe('PDFRadioGroup', () => { + it('can read its options', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); const historicalFigures = form.getRadioGroup('Historical Figures 🐺'); @@ -22,14 +22,14 @@ describe(`PDFRadioGroup`, () => { ]); }); - it(`can read its selected value`, async () => { + it('can read its selected value', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); const historicalFigures = form.getRadioGroup('Historical Figures 🐺'); expect(historicalFigures.getSelected()).toEqual('Marcus Aurelius 🏛️'); }); - it(`can clear its value`, async () => { + it('can clear its value', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); const historicalFigures = form.getRadioGroup('Historical Figures 🐺'); @@ -37,7 +37,7 @@ describe(`PDFRadioGroup`, () => { expect(historicalFigures.getSelected()).toBe(undefined); }); - it(`can select a value`, async () => { + it('can select a value', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); const historicalFigures = form.getRadioGroup('Historical Figures 🐺'); @@ -45,7 +45,7 @@ describe(`PDFRadioGroup`, () => { expect(historicalFigures.getSelected()).toBe('Marie Curie ☢️'); }); - it(`can read its flag states`, async () => { + it('can read its flag states', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); const historicalFigures = form.getRadioGroup('Historical Figures 🐺'); @@ -57,7 +57,7 @@ describe(`PDFRadioGroup`, () => { expect(historicalFigures.isOffToggleable()).toBe(false); }); - it(`supports mutualExclusion=true`, async () => { + it('supports mutualExclusion=true', async () => { const pdfDoc = await PDFDocument.create(); const page = pdfDoc.addPage(); const form = pdfDoc.getForm(); @@ -103,7 +103,7 @@ describe(`PDFRadioGroup`, () => { expect((opt.get(3) as PDFHexString).decodeText()).toBe('qux'); }); - it(`supports mutualExclusion=false`, async () => { + it('supports mutualExclusion=false', async () => { const pdfDoc = await PDFDocument.create(); const page = pdfDoc.addPage(); const form = pdfDoc.getForm(); @@ -149,7 +149,7 @@ describe(`PDFRadioGroup`, () => { expect((opt.get(3) as PDFHexString).decodeText()).toBe('qux'); }); - it(`produces printable widgets when added to a page`, async () => { + it('produces printable widgets when added to a page', async () => { const pdfDoc = await PDFDocument.create(); const page = pdfDoc.addPage(); @@ -165,7 +165,7 @@ describe(`PDFRadioGroup`, () => { expect(widgets()[0].hasFlag(AnnotationFlags.Print)).toBe(true); }); - it(`sets page reference when added to a page`, async () => { + it('sets page reference when added to a page', async () => { const pdfDoc = await PDFDocument.create(); const page = pdfDoc.addPage(); diff --git a/tests/api/form/PDFTextField.spec.ts b/tests/api/form/PDFTextField.spec.ts index b2c8eecf1..874821b95 100644 --- a/tests/api/form/PDFTextField.spec.ts +++ b/tests/api/form/PDFTextField.spec.ts @@ -1,10 +1,14 @@ import fs from 'fs'; -import { PDFDocument, TextAlignment, AnnotationFlags } from 'src/index'; +import { + PDFDocument, + TextAlignment, + AnnotationFlags, +} from '../../../src/index'; const fancyFieldsPdfBytes = fs.readFileSync('assets/pdfs/fancy_fields.pdf'); -describe(`PDFTextField`, () => { - it(`can read its value`, async () => { +describe('PDFTextField', () => { + it('can read its value', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); @@ -20,7 +24,7 @@ describe(`PDFTextField`, () => { expect(lastName.getText()).toEqual('Lightningtwirls'); }); - it(`can read its alignment`, async () => { + it('can read its alignment', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); @@ -36,7 +40,7 @@ describe(`PDFTextField`, () => { expect(lastName.getAlignment()).toEqual(TextAlignment.Right); }); - it(`can write a value`, async () => { + it('can write a value', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); @@ -57,7 +61,7 @@ describe(`PDFTextField`, () => { expect(lastName.getText()).toEqual('And christmas trees! 🎄'); }); - it(`can read its flag states`, async () => { + it('can read its flag states', async () => { const pdfDoc = await PDFDocument.load(fancyFieldsPdfBytes); const form = pdfDoc.getForm(); const prefix = form.getTextField('Prefix ⚽️'); @@ -74,7 +78,7 @@ describe(`PDFTextField`, () => { expect(prefix.isCombed()).toBe(false); }); - it(`throws an error when setting text that exceeds the max length`, async () => { + it('throws an error when setting text that exceeds the max length', async () => { const pdfDoc = await PDFDocument.create(); const form = pdfDoc.getForm(); const textField = form.createTextField('foo.bar'); @@ -84,7 +88,7 @@ describe(`PDFTextField`, () => { expect(() => textField.setText('abcdef')).toThrow(); }); - it(`throws an error when setting a max length less than the text length`, async () => { + it('throws an error when setting a max length less than the text length', async () => { const pdfDoc = await PDFDocument.create(); const form = pdfDoc.getForm(); const textField = form.createTextField('foo.bar'); @@ -96,7 +100,7 @@ describe(`PDFTextField`, () => { expect(() => textField.setMaxLength(5)).toThrow(); }); - it(`produces printable widgets when added to a page`, async () => { + it('produces printable widgets when added to a page', async () => { const pdfDoc = await PDFDocument.create(); const page = pdfDoc.addPage(); @@ -112,7 +116,7 @@ describe(`PDFTextField`, () => { expect(widgets()[0].hasFlag(AnnotationFlags.Print)).toBe(true); }); - it(`sets page reference when added to a page`, async () => { + it('sets page reference when added to a page', async () => { const pdfDoc = await PDFDocument.create(); const page = pdfDoc.addPage(); @@ -128,7 +132,7 @@ describe(`PDFTextField`, () => { expect(widgets()[0].P()).toBe(page.ref); }); - it(`sets the 'hidden' flag when passed options.hidden`, async () => { + it("sets the 'hidden' flag when passed options.hidden", async () => { const pdfDoc = await PDFDocument.create(); const page = pdfDoc.addPage(); const form = pdfDoc.getForm(); diff --git a/tests/api/objects.spec.ts b/tests/api/objects.spec.ts new file mode 100644 index 000000000..cf2a5caee --- /dev/null +++ b/tests/api/objects.spec.ts @@ -0,0 +1,28 @@ +import { isPDFInstance, PDFClasses } from '../../src/api/objects'; +import { PDFNumber, PDFName, PDFNull } from '../../src/index'; + +describe('isPDFInstance', () => { + const pStr = PDFName.of('Hola'); + const pNum = PDFNumber.of(125); + + it('identifies PDF instances', () => { + expect(isPDFInstance(pStr, PDFClasses.PDFName)).toBeTruthy(); + expect(isPDFInstance(pNum, PDFClasses.PDFNumber)).toBeTruthy(); + expect(isPDFInstance(pNum, PDFClasses.PDFArray)).toBeFalsy(); + expect(isPDFInstance(pNum, PDFNumber as any)).toBeTruthy(); + }); + + it('identifies instances as being superclases', () => { + expect(isPDFInstance(pStr, PDFClasses.PDFObject)).toBeTruthy(); + expect(isPDFInstance(pNum, PDFClasses.PDFObject)).toBeTruthy(); + }); + + it('properly handles PDFNull', () => { + expect(isPDFInstance(pNum, PDFClasses.PDFNull)).toBeFalsy(); + expect(isPDFInstance(PDFNull, PDFClasses.PDFNull)).toBeTruthy(); + }); + + it('does not fail on incorrect usage', () => { + expect(isPDFInstance(pNum, (() => null) as any)).toBeFalsy(); + }); +}); diff --git a/tests/api/svgPath.spec.ts b/tests/api/svgPath.spec.ts index 167375aca..cd90cf6b1 100644 --- a/tests/api/svgPath.spec.ts +++ b/tests/api/svgPath.spec.ts @@ -1,26 +1,26 @@ -import { svgPathToOperators } from 'src/api/svgPath'; +import { svgPathToOperators } from '../../src/api/svgPath'; // Test paths adapted from https://svgwg.org/svg2-draft/paths.html -describe(`svgPathToOperators`, () => { - it(`can map triangle paths to PDF operators`, () => { +describe('svgPathToOperators', () => { + it('can map triangle paths to PDF operators', () => { const operators = svgPathToOperators('M 100 100 L 300 100 L 200 300 z'); expect(operators.length).toBe(4); expect(operators.toString()).toBe('100 100 m,300 100 l,200 300 l,h'); }); - it(`can map relative triangle paths to PDF operators`, () => { + it('can map relative triangle paths to PDF operators', () => { const operators = svgPathToOperators('m 100 100 l 200 0 l -100 200 z'); expect(operators.length).toBe(4); expect(operators.toString()).toBe('100 100 m,300 100 l,200 300 l,h'); }); - it(`can map triangle decimal paths to PDF operators`, () => { + it('can map triangle decimal paths to PDF operators', () => { const operators = svgPathToOperators('M 50.5 100 L 250.5 100 150.5 300 z'); expect(operators.length).toBe(4); expect(operators.toString()).toBe('50.5 100 m,250.5 100 l,150.5 300 l,h'); }); - it(`can map rectangle with lines paths to PDF operators`, () => { + it('can map rectangle with lines paths to PDF operators', () => { const operators = svgPathToOperators('M 50 50 V 100 H 100 v -100 h -50 Z'); expect(operators.length).toBe(6); expect(operators.toString()).toBe( @@ -28,7 +28,7 @@ describe(`svgPathToOperators`, () => { ); }); - it(`can map bezier curve paths to PDF operators`, () => { + it('can map bezier curve paths to PDF operators', () => { const operators = svgPathToOperators( 'M100,200 C100,100 250,100 250,200 S400,300 400,200', ); @@ -38,7 +38,7 @@ describe(`svgPathToOperators`, () => { ); }); - it(`can map relative bezier curve paths to PDF operators`, () => { + it('can map relative bezier curve paths to PDF operators', () => { const operators = svgPathToOperators( 'M100,200 c0,-100 150,-100 150,0 s150,100 150,0', ); @@ -48,7 +48,7 @@ describe(`svgPathToOperators`, () => { ); }); - it(`can map quadratic curve paths to PDF operators`, () => { + it('can map quadratic curve paths to PDF operators', () => { const operators = svgPathToOperators('M200,300 Q400,50 600,300 T1000,300'); expect(operators.length).toBe(3); expect(operators.toString()).toBe( @@ -56,7 +56,7 @@ describe(`svgPathToOperators`, () => { ); }); - it(`can map relative quadratic curve paths to PDF operators`, () => { + it('can map relative quadratic curve paths to PDF operators', () => { const operators = svgPathToOperators('M200,300 q200,-250 400,0 t400,0'); expect(operators.length).toBe(3); expect(operators.toString()).toBe( @@ -64,7 +64,7 @@ describe(`svgPathToOperators`, () => { ); }); - it(`can map arc paths to PDF operators`, () => { + it('can map arc paths to PDF operators', () => { const operators = svgPathToOperators( 'M300,200 h-150 a150,150 0 1,0 150,-150 z', ); @@ -74,7 +74,7 @@ describe(`svgPathToOperators`, () => { ); }); - it(`can map relative arc paths to PDF operators`, () => { + it('can map relative arc paths to PDF operators', () => { const operators = svgPathToOperators( 'M300,200 h-150 A150,150 0 1,0 300,50 z', ); @@ -84,7 +84,7 @@ describe(`svgPathToOperators`, () => { ); }); - it(`can map cubic bezier paths to PDF operators`, () => { + it('can map cubic bezier paths to PDF operators', () => { const operators = svgPathToOperators( 'm 100 100 S 200,100 200,200 200,200 100,200 T 0,250', ); @@ -94,7 +94,7 @@ describe(`svgPathToOperators`, () => { ); }); - it(`can map dashed line paths to PDF operators`, () => { + it('can map dashed line paths to PDF operators', () => { const operators = svgPathToOperators( 'M 0,25 5,25 M 10,25 15,25 M 20,25 25,25', ); @@ -104,7 +104,7 @@ describe(`svgPathToOperators`, () => { ); }); - it(`can map relative dashed line paths to PDF operators`, () => { + it('can map relative dashed line paths to PDF operators', () => { const operators = svgPathToOperators('m 0,25 5,0 m 5,0 5,0 m 5,0 5,0'); expect(operators.length).toBe(6); expect(operators.toString()).toBe( @@ -112,7 +112,7 @@ describe(`svgPathToOperators`, () => { ); }); - it(`can map paths with odd inputs to PDF operators`, () => { + it('can map paths with odd inputs to PDF operators', () => { const operators = svgPathToOperators('M 0,25 5,25 m 5-0 5..0 m 5,0 5,0'); expect(operators.length).toBe(6); expect(operators.toString()).toBe( @@ -120,7 +120,7 @@ describe(`svgPathToOperators`, () => { ); }); - it(`can map paths that reset cubic bezier control points to PDF operators`, () => { + it('can map paths that reset cubic bezier control points to PDF operators', () => { const operators = svgPathToOperators( 'M100 100 S200,100 200,200 M95 105 s100,0 100,100', ); @@ -130,7 +130,7 @@ describe(`svgPathToOperators`, () => { ); }); - it(`can map paths that reset quadratic bezier control points to PDF operators`, () => { + it('can map paths that reset quadratic bezier control points to PDF operators', () => { const operators = svgPathToOperators( 'M100 100 T100,200 200,200 M90,120 t0,100 100,0', ); @@ -139,4 +139,15 @@ describe(`svgPathToOperators`, () => { '100 100 m,100 100 100 200 v,100 300 200 200 v,90 120 m,90 120 90 220 v,90 320 190 220 v', ); }); + + it('correctly updates control points for T command', () => { + // See https://github.com/Hopding/pdf-lib/issues/1443 + const operators = svgPathToOperators( + 'M 10,25 Q 30,0 50,25 Q 70,50 90,25 T 130,25 T 170,25', + ); + expect(operators.length).toBe(5); + expect(operators.toString()).toBe( + '10 25 m,30 0 50 25 v,70 50 90 25 v,110 0 130 25 v,150 50 170 25 v', + ); + }); }); diff --git a/tests/api/text/layout.spec.ts b/tests/api/text/layout.spec.ts index 78f1366b4..90de0ec5f 100644 --- a/tests/api/text/layout.spec.ts +++ b/tests/api/text/layout.spec.ts @@ -1,11 +1,11 @@ -import { PDFDocument, StandardFonts, TextAlignment } from 'src/index'; +import { PDFDocument, StandardFonts, TextAlignment } from '../../../src/index'; -import { layoutMultilineText } from 'src/api/text/layout'; +import { layoutMultilineText } from '../../../src/api/text/layout'; const MIN_FONT_SIZE = 4; const MAX_FONT_SIZE = 500; -describe(`layoutMultilineText`, () => { +describe('layoutMultilineText', () => { it('should layout the text on one line when it fits near-perfectly', async () => { const pdfDoc = await PDFDocument.create(); const font = await pdfDoc.embedFont(StandardFonts.Helvetica); diff --git a/tests/core/PDFContext.spec.ts b/tests/core/PDFContext.spec.ts index 1e5fd2ce0..087f67b48 100644 --- a/tests/core/PDFContext.spec.ts +++ b/tests/core/PDFContext.spec.ts @@ -5,18 +5,20 @@ import { PDFBool, PDFContentStream, PDFContext, + PDFCrossRefSection, PDFDict, PDFHexString, PDFName, PDFNull, PDFNumber, + PDFObject, PDFRef, PDFString, -} from 'src/core'; -import { mergeIntoTypedArray } from 'src/utils'; +} from '../../src/core'; +import { mergeIntoTypedArray } from '../../src/utils'; -describe(`PDFContext`, () => { - it(`retains assigned objects`, () => { +describe('PDFContext', () => { + it('retains assigned objects', () => { const context = PDFContext.create(); const pdfBool = PDFBool.True; @@ -47,18 +49,55 @@ describe(`PDFContext`, () => { expect(context.lookup(PDFRef.of(7))).toBe(pdfArray); }); - it(`does not use object number 0 during registration`, () => { + it('returns references from objects and references', () => { + const context = PDFContext.create(); + + const pdfBool = PDFBool.True; + const pdfHexString = PDFHexString.of('ABC123'); + const pdfName = PDFName.of('Foo#Bar!'); + const pdfNull = PDFNull; + const pdfNumber = PDFNumber.of(-24.179); + const pdfString = PDFString.of('foobar'); + const pdfDict = context.obj({ Foo: PDFName.of('Bar') }); + const pdfArray = context.obj([PDFBool.True, pdfDict]); + + context.assign(PDFRef.of(0), pdfBool); + context.assign(PDFRef.of(1), pdfHexString); + context.assign(PDFRef.of(2), pdfName); + context.assign(PDFRef.of(3), pdfNull); + context.assign(PDFRef.of(4), pdfNumber); + context.assign(PDFRef.of(5), pdfString); + context.assign(PDFRef.of(6), pdfDict); + context.assign(PDFRef.of(7), pdfArray); + + const checkPDFObj = (pdfO: PDFObject, pdfR: number) => { + const pdfRef = PDFRef.of(pdfR); + expect(context.getObjectRef(pdfO)).toBe(pdfRef); + expect(context.getRef(pdfO)).toBe(pdfRef); + expect(context.getRef(pdfRef)).toBe(pdfRef); + }; + checkPDFObj(pdfBool, 0); + checkPDFObj(pdfHexString, 1); + checkPDFObj(pdfName, 2); + checkPDFObj(pdfNull, 3); + checkPDFObj(pdfNumber, 4); + checkPDFObj(pdfString, 5); + checkPDFObj(pdfDict, 6); + checkPDFObj(pdfArray, 7); + }); + + it('does not use object number 0 during registration', () => { const context = PDFContext.create(); expect(context.register(PDFBool.True)).toBe(PDFRef.of(1)); }); - it(`returns the given object during lookup if it is not a PDFRef`, () => { + it('returns the given object during lookup if it is not a PDFRef', () => { const context = PDFContext.create(); const pdfNumber = PDFNumber.of(21); expect(context.lookup(pdfNumber)).toBe(pdfNumber); }); - it(`assigns the next highest object number during registration`, () => { + it('assigns the next highest object number during registration', () => { const context = PDFContext.create(); const pdfBool = PDFBool.True; @@ -76,7 +115,7 @@ describe(`PDFContext`, () => { expect(context.lookup(numberRef)).toBe(pdfNumber); }); - it(`stream creation`, () => { + it('stream creation', () => { const context = PDFContext.create(); const stream = context.flateStream('stuff and things!'); @@ -96,29 +135,40 @@ describe(`PDFContext`, () => { ); }); - describe(`literal conversions`, () => { + describe('literal conversions', () => { const context = PDFContext.create(); - it(`converts null literals to the PDFNull instance`, () => { - expect(context.obj(null)).toBe(PDFNull); + it('converts null literals to the PDFNull instance', () => { + const literal = null; + const obj = context.obj(literal); + expect(obj).toBe(PDFNull); + expect(context.getLiteral(obj)).toBe(literal); }); - it(`converts string literals to PDFName instances`, () => { - expect(context.obj('foobar')).toBeInstanceOf(PDFName); - expect(context.obj('foobar').toString()).toBe('/foobar'); + it('converts string literals to PDFName instances', () => { + const literal = 'foobar'; + const obj = context.obj(literal); + expect(obj).toBeInstanceOf(PDFName); + expect(obj.toString()).toBe(`/${literal}`); + expect(context.getLiteral(obj)).toBe(literal); }); - it(`converts number literals to PDFNumber instances`, () => { - expect(context.obj(-21.4e-3)).toBeInstanceOf(PDFNumber); - expect(context.obj(-21.4e-3).toString()).toBe('-0.0214'); + it('converts number literals to PDFNumber instances', () => { + const literal = -21.4e-3; + const obj = context.obj(literal); + expect(obj).toBeInstanceOf(PDFNumber); + expect(obj.toString()).toBe('-0.0214'); + expect(context.getLiteral(obj)).toBe(literal); }); - it(`converts boolean literals to PDFBool instances`, () => { + it('converts boolean literals to PDFBool instances', () => { expect(context.obj(true)).toBe(PDFBool.True); + expect(context.getLiteral(PDFBool.True)).toBe(true); expect(context.obj(false)).toBe(PDFBool.False); + expect(context.getLiteral(PDFBool.False)).toBe(false); }); - it(`converts array literals to PDFArray instances`, () => { + it('converts array literals to PDFArray instances', () => { const array = [ PDFRef.of(21), true, @@ -127,13 +177,16 @@ describe(`PDFContext`, () => { [null, -24.179], { Foo: PDFName.of('Bar') }, ]; - expect(context.obj(array)).toBeInstanceOf(PDFArray); - expect(context.obj(array).toString()).toEqual( + const obj = context.obj(array); + expect(obj).toBeInstanceOf(PDFArray); + expect(obj.toString()).toEqual( '[ 21 0 R true /Foo#23Bar! [ null -24.179 ] <<\n/Foo /Bar\n>> ]', ); + (array[5] as any).Foo = 'Bar'; + expect(context.getLiteral(obj)).toEqual(array); }); - it(`converts object literals to PDFDict instances`, () => { + it('converts object literals to PDFDict instances', () => { const dict = { Ref: PDFRef.of(21), Boolean: true, @@ -143,8 +196,9 @@ describe(`PDFContext`, () => { Name: 'Foo#Bar!', Dictionary: { Array: [true, null] }, }; - expect(context.obj(dict)).toBeInstanceOf(PDFDict); - expect(context.obj(dict).toString()).toEqual( + const obj = context.obj(dict); + expect(obj).toBeInstanceOf(PDFDict); + expect(obj.toString()).toEqual( `<< /Ref 21 0 R /Boolean true @@ -157,10 +211,53 @@ describe(`PDFContext`, () => { >> >>`, ); + expect(context.getLiteral(obj)).toEqual(dict); + }); + + it('converts PDFObject instances to their literal representation', () => { + const dict = { + Ref: PDFRef.of(21), + Boolean: true, + String: PDFString.of('blub'), + HexString: PDFHexString.of('ABC123'), + Null: null, + Number: -3.5e-2, + Name: 'Foo#Bar()', + Dictionary: { Array: [true, null] }, + }; + const obj = context.obj(dict); + + // Default conversion + let lit = context.getLiteral(obj); + expect(lit).toEqual(dict); + + // Shallow conversion + lit = context.getLiteral(obj, { deep: false }); + expect(lit.Boolean).toBe(PDFBool.True); + expect(lit.Null).toBe(PDFNull); + expect(lit.Number).toBeInstanceOf(PDFNumber); + expect(lit.Name).toBeInstanceOf(PDFName); + expect(lit.Dictionary).toBeInstanceOf(PDFDict); + + // Extended conversion + lit = context.getLiteral(obj, { literalRef: true, literalString: true }); + expect(lit.Ref).toBe(21); + expect(lit.String).toBe('blub'); + expect(lit.HexString).toBe('ABC123'); + const stream = context.stream('foo', dict); + lit = context.getLiteral(stream, { + literalStreamDict: true, + }) as typeof dict; + expect(lit).toEqual(dict); + stream.updateDict(); + lit = context.getLiteral(stream, { literalStreamDict: true }) as { + Length: number; + }; + expect(lit.Length).toBe(3); }); }); - it(`can provide a reference to a "pushGraphicsState" content stream`, () => { + it('can provide a reference to a "pushGraphicsState" content stream', () => { const context = PDFContext.create(); expect(context.enumerateIndirectObjects().length).toBe(0); @@ -176,7 +273,7 @@ describe(`PDFContext`, () => { expect(context.lookup(ref1)).toBeInstanceOf(PDFContentStream); }); - it(`can provide a reference to a "popGraphicsState" content stream`, () => { + it('can provide a reference to a "popGraphicsState" content stream', () => { const context = PDFContext.create(); expect(context.enumerateIndirectObjects().length).toBe(0); @@ -191,4 +288,53 @@ describe(`PDFContext`, () => { expect(ref1).toBe(ref2); expect(context.lookup(ref1)).toBeInstanceOf(PDFContentStream); }); + + describe('Objects Versions Handling', () => { + it('lists all xrefs in pdf', () => { + const context = PDFContext.create(); + const xref = PDFCrossRefSection.create(); + xref.addEntry(PDFRef.of(25, 1), 125); + xref.addDeletedEntry(PDFRef.of(26, 1), 1234); + context.xrefs.push(xref); + const xref2 = PDFCrossRefSection.create(); + xref2.addEntry(PDFRef.of(35, 1), 1250); + xref2.addDeletedEntry(PDFRef.of(36, 1), 1212); + xref2.addEntry(PDFRef.of(45, 1), 1500); + context.xrefs.push(xref2); + let list = context.listXrefEntries(); + expect(list.length).toBe(3); + list = context.listXrefEntries(0); + expect(list.length).toBe(2); + }); + + it('registers objects versions', () => { + const context = PDFContext.create(true); + context.assign(PDFRef.of(16, 0), PDFNumber.of(35)); + context.assign(PDFRef.of(16, 0), PDFNumber.of(45)); + context.assign(PDFRef.of(16, 1), PDFNumber.of(55)); + context.assign(PDFRef.of(16, 0), PDFNumber.of(55)); + context.assign(PDFRef.of(17, 0), PDFNumber.of(30)); + context.assign(PDFRef.of(17, 0), PDFNumber.of(40)); + context.delete(PDFRef.of(17, 0)); + const previous16 = context.getObjectVersions(PDFRef.of(16, 0)); + expect(previous16.length).toBe(2); + expect(context.getObjectVersions(PDFRef.of(16, 1)).length).toBe(0); + expect(previous16[0]).toEqual(PDFNumber.of(45)); + expect(previous16[1]).toEqual(PDFNumber.of(35)); + const previous17 = context.getObjectVersions(PDFRef.of(17, 0)); + expect(previous17.length).toBe(2); + expect(previous17[0]).toEqual(PDFNumber.of(40)); + }); + + it('does not registers objects versions by default', () => { + const context = PDFContext.create(); + context.assign(PDFRef.of(16, 0), PDFNumber.of(35)); + context.assign(PDFRef.of(16, 0), PDFNumber.of(45)); + context.assign(PDFRef.of(16, 1), PDFNumber.of(55)); + context.assign(PDFRef.of(16, 0), PDFNumber.of(55)); + context.delete(PDFRef.of(16, 1)); + expect(context.getObjectVersions(PDFRef.of(16, 0)).length).toBe(0); + expect(context.getObjectVersions(PDFRef.of(16, 1)).length).toBe(0); + }); + }); }); diff --git a/tests/core/PDFObjectCopier.spec.ts b/tests/core/PDFObjectCopier.spec.ts index 7c5a78046..ae80c5b8f 100644 --- a/tests/core/PDFObjectCopier.spec.ts +++ b/tests/core/PDFObjectCopier.spec.ts @@ -14,10 +14,10 @@ import { PDFRawStream, PDFRef, PDFString, -} from 'src/index'; +} from '../../src/index'; -describe(`PDFObjectCopier`, () => { - it(`copies PDFDicts, including their indirect references`, () => { +describe('PDFObjectCopier', () => { + it('copies PDFDicts, including their indirect references', () => { // Arrange const src = PDFContext.create(); const origDict = src.obj({ @@ -72,7 +72,7 @@ describe(`PDFObjectCopier`, () => { expect(destBar1.get(Baz)).toBeInstanceOf(PDFName); }); - it(`copies PDFArrays, including their indirect references`, () => { + it('copies PDFArrays, including their indirect references', () => { // Arrange const src = PDFContext.create(); const origArray = src.obj([ @@ -126,7 +126,7 @@ describe(`PDFObjectCopier`, () => { expect(dest1Bar.get(0)).toBeInstanceOf(PDFName); }); - it(`copies PDFStreams, including their indirect references`, () => { + it('copies PDFStreams, including their indirect references', () => { // Arrange const src = PDFContext.create(); const origStream = src.stream(new Uint8Array([1, 2, 3, 4, 5]), { @@ -184,7 +184,7 @@ describe(`PDFObjectCopier`, () => { expect(destBar1.get(Baz)).toBeInstanceOf(PDFName); }); - it(`copies PDFRefs, including their indirect references`, () => { + it('copies PDFRefs, including their indirect references', () => { // Arrange const src = PDFContext.create(); const origRef = PDFRef.of(21); @@ -242,7 +242,7 @@ describe(`PDFObjectCopier`, () => { expect(destBar1.get(Baz)).toBeInstanceOf(PDFName); }); - it(`copies individual PDFPageLeaf objects, without bringing along the whole page tree`, () => { + it('copies individual PDFPageLeaf objects, without bringing along the whole page tree', () => { // Arrange const src = PDFContext.create(); @@ -309,7 +309,7 @@ describe(`PDFObjectCopier`, () => { expect(Rotate).toBeInstanceOf(PDFNumber); }); - it(`copies objects with cyclic references`, () => { + it('copies objects with cyclic references', () => { // Arrange const src = PDFContext.create(); @@ -333,7 +333,7 @@ describe(`PDFObjectCopier`, () => { ); }); - it(`copies all types of PDFObjects`, () => { + it('copies all types of PDFObjects', () => { // Arrange const src = PDFContext.create(); const dest = PDFContext.create(); @@ -394,7 +394,7 @@ describe(`PDFObjectCopier`, () => { expect(copiedString).toBeInstanceOf(PDFString); }); - it(`copies objects with undefined references`, () => { + it('copies objects with undefined references', () => { // Arrange const src = PDFContext.create(); const dest = PDFContext.create(); diff --git a/tests/core/acroform/PDFAcroField.spec.ts b/tests/core/acroform/PDFAcroField.spec.ts index 4c72988b5..ca13b9551 100644 --- a/tests/core/acroform/PDFAcroField.spec.ts +++ b/tests/core/acroform/PDFAcroField.spec.ts @@ -3,10 +3,10 @@ import { PDFContext, PDFString, PDFHexString, -} from 'src/index'; +} from '../../../src/index'; -describe(`PDFAcroField`, () => { - it(`returns undefined for missing (DAs)`, () => { +describe('PDFAcroField', () => { + it('returns undefined for missing (DAs)', () => { const context = PDFContext.create(); const dict = context.obj({ @@ -18,7 +18,7 @@ describe(`PDFAcroField`, () => { expect(field.getDefaultAppearance()).toBe(undefined); }); - it(`returns normal direct appearance strings (DAs)`, () => { + it('returns normal direct appearance strings (DAs)', () => { const context = PDFContext.create(); const dict = context.obj({ @@ -30,7 +30,7 @@ describe(`PDFAcroField`, () => { expect(field.getDefaultAppearance()).toBe('/ZaDb 10 Tf 0 g'); }); - it(`returns hexadecimal (non-standard) direct appearance strings (DAs)`, () => { + it('returns hexadecimal (non-standard) direct appearance strings (DAs)', () => { const context = PDFContext.create(); const dict = context.obj({ @@ -42,8 +42,8 @@ describe(`PDFAcroField`, () => { expect(field.getDefaultAppearance()).toBe('/ZaDb 10 Tf 0 g'); }); - describe(`setFontSize()`, () => { - it(`throws an error if the /DA entry is missing`, () => { + describe('setFontSize()', () => { + it('throws an error if the /DA entry is missing', () => { const context = PDFContext.create(); const dict = context.obj({ @@ -55,7 +55,7 @@ describe(`PDFAcroField`, () => { expect(() => field.setFontSize(8)).toThrow(); }); - it(`throw an error if the /DA string does not contain a Tf operator`, () => { + it('throw an error if the /DA string does not contain a Tf operator', () => { const context = PDFContext.create(); const dict = context.obj({ @@ -67,7 +67,7 @@ describe(`PDFAcroField`, () => { expect(() => field.setFontSize(8)).toThrow(); }); - it(`replaces the font size of the last occurring Tf operator`, () => { + it('replaces the font size of the last occurring Tf operator', () => { const context = PDFContext.create(); const dict = context.obj({ @@ -82,7 +82,7 @@ describe(`PDFAcroField`, () => { ); }); - it(`tolerates invalid Tfs with missing font sizes`, () => { + it('tolerates invalid Tfs with missing font sizes', () => { const context = PDFContext.create(); const dict = context.obj({ diff --git a/tests/core/acroform/PDFAcroTerminal.spec.ts b/tests/core/acroform/PDFAcroTerminal.spec.ts index 3f1a83c62..0c1bae7c1 100644 --- a/tests/core/acroform/PDFAcroTerminal.spec.ts +++ b/tests/core/acroform/PDFAcroTerminal.spec.ts @@ -1,7 +1,12 @@ -import { PDFAcroTerminal, PDFContext, PDFRef, PDFArray } from 'src/index'; - -describe(`PDFAcroTerminal`, () => { - it(`returns Kids when it has them`, () => { +import { + PDFAcroTerminal, + PDFContext, + PDFRef, + PDFArray, +} from '../../../src/index'; + +describe('PDFAcroTerminal', () => { + it('returns Kids when it has them', () => { const context = PDFContext.create(); const kids = context.obj(['Foo', PDFRef.of(21), 9001]); @@ -18,7 +23,7 @@ describe(`PDFAcroTerminal`, () => { expect(Kids).toBe(kids); }); - it(`returns itself as a Kid when it has none`, () => { + it('returns itself as a Kid when it has none', () => { const context = PDFContext.create(); const dict = context.obj({}); diff --git a/tests/core/annotation/PDFWidgetAnnotation.spec.ts b/tests/core/annotation/PDFWidgetAnnotation.spec.ts index a9fb66f4e..dba19dfb7 100644 --- a/tests/core/annotation/PDFWidgetAnnotation.spec.ts +++ b/tests/core/annotation/PDFWidgetAnnotation.spec.ts @@ -5,10 +5,10 @@ import { PDFHexString, PDFName, PDFNull, -} from 'src/index'; +} from '../../../src/index'; -describe(`PDFWidgetAnnotation`, () => { - it(`returns undefined for missing (DAs)`, () => { +describe('PDFWidgetAnnotation', () => { + it('returns undefined for missing (DAs)', () => { const context = PDFContext.create(); const parentRef = context.nextRef(); @@ -18,7 +18,7 @@ describe(`PDFWidgetAnnotation`, () => { expect(widget.getDefaultAppearance()).toBe(undefined); }); - it(`returns normal direct appearance strings (DAs)`, () => { + it('returns normal direct appearance strings (DAs)', () => { const context = PDFContext.create(); const parentRef = context.nextRef(); @@ -28,7 +28,7 @@ describe(`PDFWidgetAnnotation`, () => { expect(widget.getDefaultAppearance()).toBe('/ZaDb 10 Tf 0 g'); }); - it(`returns hexadecimal (non-standard) direct appearance strings (DAs)`, () => { + it('returns hexadecimal (non-standard) direct appearance strings (DAs)', () => { const context = PDFContext.create(); const parentRef = context.nextRef(); diff --git a/tests/core/document/PDFCrossRefSection.spec.ts b/tests/core/document/PDFCrossRefSection.spec.ts index 302c50378..968468b14 100644 --- a/tests/core/document/PDFCrossRefSection.spec.ts +++ b/tests/core/document/PDFCrossRefSection.spec.ts @@ -1,8 +1,8 @@ -import { PDFCrossRefSection, PDFRef } from 'src/core'; -import { toCharCode, typedArrayFor } from 'src/utils'; +import { PDFCrossRefSection, PDFRef } from '../../../src/core'; +import { toCharCode, typedArrayFor } from '../../../src/utils'; -describe(`PDFCrossRefSection`, () => { - it(`can be constructed from PDFCrossRefSection.create()`, () => { +describe('PDFCrossRefSection', () => { + it('can be constructed from PDFCrossRefSection.create()', () => { expect(PDFCrossRefSection.create()).toBeInstanceOf(PDFCrossRefSection); }); @@ -18,11 +18,16 @@ describe(`PDFCrossRefSection`, () => { xref2.addEntry(PDFRef.of(6), 192188923); xref2.addEntry(PDFRef.of(7), 129219); - it(`can be converted to a string with a single subsection`, () => { + const xref3 = PDFCrossRefSection.create(); + xref3.addEntry(PDFRef.of(23), 21); + xref3.addEntry(PDFRef.of(16), 192188923); + xref3.addEntry(PDFRef.of(78), 129219); + + it('can be converted to a string with a single subsection', () => { expect(String(xref1)).toEqual( 'xref\n' + '0 5\n' + - '0000000000 65535 f \n' + + '0000000002 65535 f \n' + '0000000021 00000 n \n' + '0000000024 00001 f \n' + '0192188923 00000 n \n' + @@ -30,11 +35,11 @@ describe(`PDFCrossRefSection`, () => { ); }); - it(`can be converted to a string with multiple subsections and without object number 1`, () => { + it('can be converted to a string with multiple subsections and without object number 1', () => { expect(String(xref2)).toEqual( 'xref\n' + '0 1\n' + - '0000000000 65535 f \n' + + '0000000004 65535 f \n' + '3 2\n' + '0000000021 00000 n \n' + '0000000024 00001 f \n' + @@ -44,22 +49,36 @@ describe(`PDFCrossRefSection`, () => { ); }); - it(`can provide its size in bytes with a single subsection`, () => { + it('can be converted to a string with multiple subsections correctly ordered', () => { + expect(String(xref3)).toEqual( + 'xref\n' + + '0 1\n' + + '0000000000 65535 f \n' + + '16 1\n' + + '0192188923 00000 n \n' + + '23 1\n' + + '0000000021 00000 n \n' + + '78 1\n' + + '0000129219 00000 n \n', + ); + }); + + it('can provide its size in bytes with a single subsection', () => { expect(xref1.sizeInBytes()).toBe(109); }); - it(`can provide its size in bytes with multiple subsections and without object number 1`, () => { + it('can provide its size in bytes with multiple subsections and without object number 1', () => { expect(xref2.sizeInBytes()).toBe(117); }); - it(`can be serialized with a single subsection`, () => { + it('can be serialized with a single subsection', () => { const buffer = new Uint8Array(113).fill(toCharCode(' ')); expect(xref1.copyBytesInto(buffer, 3)).toBe(109); expect(buffer).toEqual( typedArrayFor( ' xref\n' + '0 5\n' + - '0000000000 65535 f \n' + + '0000000002 65535 f \n' + '0000000021 00000 n \n' + '0000000024 00001 f \n' + '0192188923 00000 n \n' + @@ -68,14 +87,14 @@ describe(`PDFCrossRefSection`, () => { ); }); - it(`can be serialized with multiple subsections and without object number 1`, () => { + it('can be serialized with multiple subsections and without object number 1', () => { const buffer = new Uint8Array(121).fill(toCharCode(' ')); expect(xref2.copyBytesInto(buffer, 3)).toBe(117); expect(buffer).toEqual( typedArrayFor( ' xref\n' + '0 1\n' + - '0000000000 65535 f \n' + + '0000000004 65535 f \n' + '3 2\n' + '0000000021 00000 n \n' + '0000000024 00001 f \n' + @@ -85,4 +104,10 @@ describe(`PDFCrossRefSection`, () => { ), ); }); + + it('lists its entries, without entry 0', () => { + expect(xref1.listRefs().length).toBe(4); + expect(xref2.listRefs().length).toBe(4); + expect(xref3.listRefs().length).toBe(3); + }); }); diff --git a/tests/core/document/PDFHeader.spec.ts b/tests/core/document/PDFHeader.spec.ts index 12ec19717..a5a9945db 100644 --- a/tests/core/document/PDFHeader.spec.ts +++ b/tests/core/document/PDFHeader.spec.ts @@ -1,20 +1,20 @@ -import { PDFHeader } from 'src/core'; -import { toCharCode, typedArrayFor } from 'src/utils'; +import { PDFHeader } from '../../../src/core'; +import { toCharCode, typedArrayFor } from '../../../src/utils'; -describe(`PDFHeader`, () => { - it(`can be constructed from PDFHeader.forVersion(...)`, () => { +describe('PDFHeader', () => { + it('can be constructed from PDFHeader.forVersion(...)', () => { expect(PDFHeader.forVersion(1, 2)).toBeInstanceOf(PDFHeader); }); - it(`can be converted to a string`, () => { + it('can be converted to a string', () => { expect(String(PDFHeader.forVersion(1, 7))).toBe('%PDF-1.7\n%'); }); - it(`can provide its size in bytes`, () => { + it('can provide its size in bytes', () => { expect(PDFHeader.forVersion(81, 79).sizeInBytes()).toBe(16); }); - it(`can be serialized`, () => { + it('can be serialized', () => { const buffer = new Uint8Array(20).fill(toCharCode(' ')); expect(PDFHeader.forVersion(79, 81).copyBytesInto(buffer, 3)).toBe(16); expect(buffer).toEqual(typedArrayFor(' %PDF-79.81\n% ')); diff --git a/tests/core/document/PDFTrailer.spec.ts b/tests/core/document/PDFTrailer.spec.ts index 0f818cf15..d5ec7a94d 100644 --- a/tests/core/document/PDFTrailer.spec.ts +++ b/tests/core/document/PDFTrailer.spec.ts @@ -1,26 +1,26 @@ -import { PDFTrailer } from 'src/core'; -import { toCharCode, typedArrayFor } from 'src/utils'; +import { PDFTrailer } from '../../../src/core'; +import { toCharCode, typedArrayFor } from '../../../src/utils'; -describe(`PDFTrailer`, () => { - it(`can be constructed from PDFTrailer.forLastCrossRefSectionOffset(...)`, () => { +describe('PDFTrailer', () => { + it('can be constructed from PDFTrailer.forLastCrossRefSectionOffset(...)', () => { expect(PDFTrailer.forLastCrossRefSectionOffset(21)).toBeInstanceOf( PDFTrailer, ); }); - it(`can be converted to a string`, () => { + it('can be converted to a string', () => { expect(String(PDFTrailer.forLastCrossRefSectionOffset(799))).toBe( 'startxref\n799\n%%EOF', ); }); - it(`can provide its size in bytes`, () => { + it('can provide its size in bytes', () => { expect(PDFTrailer.forLastCrossRefSectionOffset(1919).sizeInBytes()).toBe( 20, ); }); - it(`can be serialized`, () => { + it('can be serialized', () => { const buffer = new Uint8Array(21).fill(toCharCode(' ')); expect(PDFTrailer.forLastCrossRefSectionOffset(1).copyBytesInto(buffer, 3)); expect(buffer).toEqual(typedArrayFor(' startxref\n1\n%%EOF ')); diff --git a/tests/core/document/PDFTrailerDict.spec.ts b/tests/core/document/PDFTrailerDict.spec.ts index ae18966bc..9ed3ccac0 100644 --- a/tests/core/document/PDFTrailerDict.spec.ts +++ b/tests/core/document/PDFTrailerDict.spec.ts @@ -1,22 +1,22 @@ -import { PDFContext, PDFTrailerDict } from 'src/core'; -import { toCharCode, typedArrayFor } from 'src/utils'; +import { PDFContext, PDFTrailerDict } from '../../../src/core'; +import { toCharCode, typedArrayFor } from '../../../src/utils'; -describe(`PDFTrailerDict`, () => { +describe('PDFTrailerDict', () => { const dict = PDFContext.create().obj({ Foo: 'Bar' }); - it(`can be constructed from PDFTrailerDict.of(...)`, () => { + it('can be constructed from PDFTrailerDict.of(...)', () => { expect(PDFTrailerDict.of(dict)).toBeInstanceOf(PDFTrailerDict); }); - it(`can be converted to a string`, () => { + it('can be converted to a string', () => { expect(String(PDFTrailerDict.of(dict))).toBe('trailer\n<<\n/Foo /Bar\n>>'); }); - it(`can provide its size in bytes`, () => { + it('can provide its size in bytes', () => { expect(PDFTrailerDict.of(dict).sizeInBytes()).toBe(23); }); - it(`can be serialized`, () => { + it('can be serialized', () => { const buffer = new Uint8Array(27).fill(toCharCode(' ')); expect(PDFTrailerDict.of(dict).copyBytesInto(buffer, 3)).toBe(23); expect(buffer).toEqual(typedArrayFor(' trailer\n<<\n/Foo /Bar\n>> ')); diff --git a/tests/core/embedders/CMap.spec.ts b/tests/core/embedders/CMap.spec.ts index 91f8e70d1..9d09312b6 100644 --- a/tests/core/embedders/CMap.spec.ts +++ b/tests/core/embedders/CMap.spec.ts @@ -1,8 +1,8 @@ import fontkit, { Font, Glyph } from '@pdf-lib/fontkit'; import fs from 'fs'; -import { createCmap } from 'src/core/embedders/CMap'; -import { byAscendingId, sortedUniq } from 'src/utils'; +import { createCmap } from '../../../src/core/embedders/CMap'; +import { byAscendingId, sortedUniq } from '../../../src/utils'; const ubuntuFont = fs.readFileSync('./assets/fonts/ubuntu/Ubuntu-R.ttf'); const sourceHansJpFont = fs.readFileSync( @@ -25,8 +25,8 @@ const allGlyphsInFontSortedById = (font: Font) => { return sortedUniq(glyphs.sort(byAscendingId), (g) => g.id); }; -describe(`createCmap`, () => { - it(`creates CMaps for embedded Ubuntu-R font files`, () => { +describe('createCmap', () => { + it('creates CMaps for embedded Ubuntu-R font files', () => { const font = fontkit.create(ubuntuFont); const glyphs = allGlyphsInFontSortedById(font); @@ -35,7 +35,7 @@ describe(`createCmap`, () => { expect(cmap).toEqual(String(ubuntuFontCmap)); }); - it(`creates CMaps for embedded SourceHanSerifJP-Regular font files`, () => { + it('creates CMaps for embedded SourceHanSerifJP-Regular font files', () => { const font = fontkit.create(sourceHansJpFont); const glyphs = allGlyphsInFontSortedById(font); diff --git a/tests/core/embedders/CustomFontEmbedder.spec.ts b/tests/core/embedders/CustomFontEmbedder.spec.ts index 7694c8a40..8b5427b28 100644 --- a/tests/core/embedders/CustomFontEmbedder.spec.ts +++ b/tests/core/embedders/CustomFontEmbedder.spec.ts @@ -7,17 +7,17 @@ import { PDFDict, PDFHexString, PDFRef, -} from 'src/index'; +} from '../../../src/index'; const ubuntuFont = fs.readFileSync('./assets/fonts/ubuntu/Ubuntu-R.ttf'); -describe(`CustomFontEmbedder`, () => { - it(`can be constructed with CustomFontEmbedder.for(...)`, async () => { +describe('CustomFontEmbedder', () => { + it('can be constructed with CustomFontEmbedder.for(...)', async () => { const embedder = await CustomFontEmbedder.for(fontkit, ubuntuFont); expect(embedder).toBeInstanceOf(CustomFontEmbedder); }); - it(`exposes the font's name`, async () => { + it("exposes the font's name", async () => { const embedder = await CustomFontEmbedder.for( fontkit, new Uint8Array(ubuntuFont), @@ -25,7 +25,7 @@ describe(`CustomFontEmbedder`, () => { expect(embedder.fontName).toBe('Ubuntu'); }); - it(`can set a custom font name`, async () => { + it('can set a custom font name', async () => { const customName = 'abc123'; const embedder = await CustomFontEmbedder.for( fontkit, @@ -35,7 +35,7 @@ describe(`CustomFontEmbedder`, () => { expect(embedder.customName).toBe(customName); }); - it(`can embed font dictionaries into PDFContexts without a predefined ref`, async () => { + it('can embed font dictionaries into PDFContexts without a predefined ref', async () => { const context = PDFContext.create(); const embedder = await CustomFontEmbedder.for( fontkit, @@ -48,7 +48,7 @@ describe(`CustomFontEmbedder`, () => { expect(context.lookup(ref)).toBeInstanceOf(PDFDict); }); - it(`can embed font dictionaries into PDFContexts with a predefined ref`, async () => { + it('can embed font dictionaries into PDFContexts with a predefined ref', async () => { const context = PDFContext.create(); const predefinedRef = PDFRef.of(9999); const embedder = await CustomFontEmbedder.for( @@ -63,7 +63,7 @@ describe(`CustomFontEmbedder`, () => { expect(ref).toBe(predefinedRef); }); - it(`can encode text strings into PDFHexString objects`, async () => { + it('can encode text strings into PDFHexString objects', async () => { const text = 'Stuff and thingz!'; const hexCodes = '00360057005801AA000300440051004700030057004B004C0051004A005D0004'; @@ -75,20 +75,20 @@ describe(`CustomFontEmbedder`, () => { ); }); - it(`can measure the width of text strings at the given font size`, async () => { + it('can measure the width of text strings at the given font size', async () => { const text = 'Stuff and thingz!'; const embedder = await CustomFontEmbedder.for(fontkit, ubuntuFont); expect(embedder.widthOfTextAtSize(text, 12)).toBe(90.672); expect(embedder.widthOfTextAtSize(text, 24)).toBe(181.344); }); - it(`can measure the height of the font at the given size`, async () => { + it('can measure the height of the font at the given size', async () => { const embedder = await CustomFontEmbedder.for(fontkit, ubuntuFont); expect(embedder.heightOfFontAtSize(12)).toBeCloseTo(13.452); expect(embedder.heightOfFontAtSize(24)).toBeCloseTo(26.904); }); - it(`can measure the size of the font at a given height`, async () => { + it('can measure the size of the font at a given height', async () => { const embedder = await CustomFontEmbedder.for(fontkit, ubuntuFont); expect(embedder.sizeOfFontAtHeight(12)).toBeCloseTo(10.705); expect(embedder.sizeOfFontAtHeight(24)).toBeCloseTo(21.409); diff --git a/tests/core/embedders/CustomFontSubsetEmbedder.spec.ts b/tests/core/embedders/CustomFontSubsetEmbedder.spec.ts index 1e5f3049c..43012ef0d 100644 --- a/tests/core/embedders/CustomFontSubsetEmbedder.spec.ts +++ b/tests/core/embedders/CustomFontSubsetEmbedder.spec.ts @@ -6,17 +6,17 @@ import { PDFContext, PDFDict, PDFHexString, -} from 'src/index'; +} from '../../../src/index'; const ubuntuFont = fs.readFileSync('./assets/fonts/ubuntu/Ubuntu-R.ttf'); -describe(`CustomFontSubsetEmbedder`, () => { - it(`can be constructed with CustomFontSubsetEmbedder.for(...)`, async () => { +describe('CustomFontSubsetEmbedder', () => { + it('can be constructed with CustomFontSubsetEmbedder.for(...)', async () => { const embedder = await CustomFontSubsetEmbedder.for(fontkit, ubuntuFont); expect(embedder).toBeInstanceOf(CustomFontSubsetEmbedder); }); - it(`can embed standard font dictionaries into PDFContexts`, async () => { + it('can embed standard font dictionaries into PDFContexts', async () => { const context = PDFContext.create(); const embedder = await CustomFontSubsetEmbedder.for( fontkit, @@ -29,7 +29,7 @@ describe(`CustomFontSubsetEmbedder`, () => { expect(context.lookup(ref)).toBeInstanceOf(PDFDict); }); - it(`can encode text strings into PDFHexString objects`, async () => { + it('can encode text strings into PDFHexString objects', async () => { const text = 'Stuff and thingz!'; const hexCodes = '00010002000300040005000600070008000500020009000A0007000B000C000D'; @@ -41,20 +41,20 @@ describe(`CustomFontSubsetEmbedder`, () => { ); }); - it(`can measure the width of text strings at the given font size`, async () => { + it('can measure the width of text strings at the given font size', async () => { const text = 'Stuff and thingz!'; const embedder = await CustomFontSubsetEmbedder.for(fontkit, ubuntuFont); expect(embedder.widthOfTextAtSize(text, 12)).toBe(90.672); expect(embedder.widthOfTextAtSize(text, 24)).toBe(181.344); }); - it(`can measure the height of the font at the given size`, async () => { + it('can measure the height of the font at the given size', async () => { const embedder = await CustomFontSubsetEmbedder.for(fontkit, ubuntuFont); expect(embedder.heightOfFontAtSize(12)).toBeCloseTo(13.452); expect(embedder.heightOfFontAtSize(24)).toBeCloseTo(26.904); }); - it(`can measure the size of the font at a given height`, async () => { + it('can measure the size of the font at a given height', async () => { const embedder = await CustomFontSubsetEmbedder.for(fontkit, ubuntuFont); expect(embedder.sizeOfFontAtHeight(12)).toBeCloseTo(10.705); expect(embedder.sizeOfFontAtHeight(24)).toBeCloseTo(21.409); diff --git a/tests/core/embedders/FileEmbedder.spec.ts b/tests/core/embedders/FileEmbedder.spec.ts index 603f47965..31c6f9144 100644 --- a/tests/core/embedders/FileEmbedder.spec.ts +++ b/tests/core/embedders/FileEmbedder.spec.ts @@ -1,18 +1,18 @@ import fs from 'fs'; -import { PDFContext, PDFDict, PDFRef, FileEmbedder } from 'src/index'; +import { PDFContext, PDFDict, PDFRef, FileEmbedder } from '../../../src/index'; const catRidingUnicornJpg = fs.readFileSync( 'assets/images/cat_riding_unicorn.jpg', ); const usConstitutionPdf = fs.readFileSync('assets/pdfs/us_constitution.pdf'); -describe(`FileEmbedder`, () => { - it(`can be constructed with FileEmbedder.for(...)`, () => { +describe('FileEmbedder', () => { + it('can be constructed with FileEmbedder.for(...)', () => { const embedder = FileEmbedder.for(catRidingUnicornJpg, 'cat.jpg'); expect(embedder).toBeInstanceOf(FileEmbedder); }); - it(`can embed files into PDFContexts without a predefined ref`, async () => { + it('can embed files into PDFContexts without a predefined ref', async () => { const context = PDFContext.create(); const embedder = FileEmbedder.for( catRidingUnicornJpg, @@ -31,7 +31,7 @@ describe(`FileEmbedder`, () => { expect(context.lookup(ref)).toBeInstanceOf(PDFDict); }); - it(`can embed files into PDFContexts with a predefined ref`, async () => { + it('can embed files into PDFContexts with a predefined ref', async () => { const context = PDFContext.create(); const predefinedRef = PDFRef.of(9999); const embedder = FileEmbedder.for( diff --git a/tests/core/embedders/JpegEmbedder.spec.ts b/tests/core/embedders/JpegEmbedder.spec.ts index 18a2f164a..56279c4e4 100644 --- a/tests/core/embedders/JpegEmbedder.spec.ts +++ b/tests/core/embedders/JpegEmbedder.spec.ts @@ -1,17 +1,22 @@ import fs from 'fs'; -import { JpegEmbedder, PDFContext, PDFRawStream, PDFRef } from 'src/core'; +import { + JpegEmbedder, + PDFContext, + PDFRawStream, + PDFRef, +} from '../../../src/core'; const catUnicornJpg = fs.readFileSync('./assets/images/cat_riding_unicorn.jpg'); const minionsLaughing = fs.readFileSync('./assets/images/minions_laughing.jpg'); const cmykJpg = fs.readFileSync('./assets/images/cmyk_colorspace.jpg'); -describe(`JpegEmbedder`, () => { - it(`can be constructed with JpegEmbedder.for(...)`, async () => { +describe('JpegEmbedder', () => { + it('can be constructed with JpegEmbedder.for(...)', async () => { const embedder = await JpegEmbedder.for(catUnicornJpg); expect(embedder).toBeInstanceOf(JpegEmbedder); }); - it(`can embed JPEG images into PDFContexts without a predefined ref`, async () => { + it('can embed JPEG images into PDFContexts without a predefined ref', async () => { const context = PDFContext.create(); const embedder = await JpegEmbedder.for(catUnicornJpg); @@ -21,7 +26,7 @@ describe(`JpegEmbedder`, () => { expect(context.lookup(ref)).toBeInstanceOf(PDFRawStream); }); - it(`can embed JPEG images into PDFContexts with a predefined ref`, async () => { + it('can embed JPEG images into PDFContexts with a predefined ref', async () => { const context = PDFContext.create(); const predefinedRef = PDFRef.of(9999); const embedder = await JpegEmbedder.for(catUnicornJpg); @@ -33,7 +38,7 @@ describe(`JpegEmbedder`, () => { expect(ref).toBe(predefinedRef); }); - it(`can extract properties of JPEG images (1)`, async () => { + it('can extract properties of JPEG images (1)', async () => { const embedder = await JpegEmbedder.for(catUnicornJpg); expect(embedder.bitsPerComponent).toBe(8); @@ -42,7 +47,7 @@ describe(`JpegEmbedder`, () => { expect(embedder.colorSpace).toBe('DeviceRGB'); }); - it(`can extract properties of JPEG images (2)`, async () => { + it('can extract properties of JPEG images (2)', async () => { const embedder = await JpegEmbedder.for(minionsLaughing); expect(embedder.bitsPerComponent).toBe(8); @@ -51,7 +56,7 @@ describe(`JpegEmbedder`, () => { expect(embedder.colorSpace).toBe('DeviceRGB'); }); - it(`can extract properties of JPEG images (3)`, async () => { + it('can extract properties of JPEG images (3)', async () => { const embedder = await JpegEmbedder.for(cmykJpg); expect(embedder.bitsPerComponent).toBe(8); diff --git a/tests/core/embedders/PDFPageEmbedder.spec.ts b/tests/core/embedders/PDFPageEmbedder.spec.ts index c57b1fa66..80ad99ca5 100644 --- a/tests/core/embedders/PDFPageEmbedder.spec.ts +++ b/tests/core/embedders/PDFPageEmbedder.spec.ts @@ -1,6 +1,12 @@ import fs from 'fs'; -import { PDFDocument } from 'src/api'; -import { PDFContext, PDFPageEmbedder, PDFRawStream, PDFRef } from 'src/core'; +import { PDFDocument } from '../../../src/api'; +import { + PDFContext, + PDFName, + PDFPageEmbedder, + PDFRawStream, + PDFRef, +} from '../../../src/core'; const examplePdf = fs.readFileSync('./assets/pdfs/normal.pdf'); @@ -9,14 +15,14 @@ const examplePage = async () => { return doc.getPages()[0]; }; -describe(`PDFPageEmbedder`, () => { - it(`can be constructed with PDFPageEmbedder.for(...)`, async () => { +describe('PDFPageEmbedder', () => { + it('can be constructed with PDFPageEmbedder.for(...)', async () => { const page = await examplePage(); const embedder = await PDFPageEmbedder.for(page.node); expect(embedder).toBeInstanceOf(PDFPageEmbedder); }); - it(`can embed PDF pages into PDFContexts with a predefined ref`, async () => { + it('can embed PDF pages into PDFContexts with a predefined ref', async () => { const context = PDFContext.create(); const predefinedRef = PDFRef.of(9999); const page = await examplePage(); @@ -29,7 +35,7 @@ describe(`PDFPageEmbedder`, () => { expect(ref).toBe(predefinedRef); }); - it(`can extract properties of the PDF page`, async () => { + it('can extract properties of the PDF page', async () => { const page = await examplePage(); const embedder = await PDFPageEmbedder.for(page.node); @@ -44,7 +50,7 @@ describe(`PDFPageEmbedder`, () => { expect(embedder.height).toEqual(page.getHeight()); }); - it(`calculates dimensions depending on the bounding box when given one`, async () => { + it('calculates dimensions depending on the bounding box when given one', async () => { const page = await examplePage(); const boundingBox = { left: 100, @@ -57,4 +63,46 @@ describe(`PDFPageEmbedder`, () => { expect(embedder.width).toEqual(122); expect(embedder.height).toEqual(233); }); + + it('handles MediaBox coordinates in any order', async () => { + const doc = await PDFDocument.create(); + const page = doc.addPage(); + + // Set MediaBox with reversed coordinates + const mediaBox = doc.context.obj([200, 300, -100, -100]); + page.node.set(PDFName.MediaBox, mediaBox); + const embedder = await PDFPageEmbedder.for(page.node); + + // Should normalize the MediaBox coordinates + expect(embedder.boundingBox).toEqual({ + left: -100, // Min of x coordinates + bottom: -100, // Min of y coordinates + right: 200, // Max of x coordinates + top: 300, // Max of y coordinates + }); + + // Width and height should be positive + expect(embedder.width).toBe(300); // right - left + expect(embedder.height).toBe(400); // top - bottom + }); + + it('respects the provided bounding box for clipping', async () => { + const page = await examplePage(); + + // Define a clipping region + const clipBox = { + left: 100, + bottom: 200, + right: 200, + top: 300, + }; + const embedder = await PDFPageEmbedder.for(page.node, clipBox); + + // Should use the clipping box as-is + expect(embedder.boundingBox).toEqual(clipBox); + + // Width and height should match the clipping dimensions + expect(embedder.width).toBe(100); // right - left + expect(embedder.height).toBe(100); // top - bottom + }); }); diff --git a/tests/core/embedders/PngEmbedder.spec.ts b/tests/core/embedders/PngEmbedder.spec.ts index 72ebd4bcd..80cd82361 100644 --- a/tests/core/embedders/PngEmbedder.spec.ts +++ b/tests/core/embedders/PngEmbedder.spec.ts @@ -1,17 +1,22 @@ import fs from 'fs'; -import { PDFContext, PDFRawStream, PDFRef, PngEmbedder } from 'src/core'; +import { + PDFContext, + PDFRawStream, + PDFRef, + PngEmbedder, +} from '../../../src/core'; const greyscalePng = fs.readFileSync('./assets/images/greyscale_bird.png'); const rgbaPng = fs.readFileSync('./assets/images/minions_banana_alpha.png'); const rgbPng = fs.readFileSync('./assets/images/minions_banana_no_alpha.png'); -describe(`PngEmbedder`, () => { - it(`can be constructed with PngEmbedder.for(...)`, async () => { +describe('PngEmbedder', () => { + it('can be constructed with PngEmbedder.for(...)', async () => { const embedder = await PngEmbedder.for(greyscalePng); expect(embedder).toBeInstanceOf(PngEmbedder); }); - it(`can embed PNG images into PDFContexts with a predefined ref`, async () => { + it('can embed PNG images into PDFContexts with a predefined ref', async () => { const context = PDFContext.create(); const predefinedRef = PDFRef.of(9999); const embedder = await PngEmbedder.for(greyscalePng); @@ -23,7 +28,7 @@ describe(`PngEmbedder`, () => { expect(ref).toBe(predefinedRef); }); - it(`can embed greyscale PNG images into PDFContexts`, async () => { + it('can embed greyscale PNG images into PDFContexts', async () => { const context = PDFContext.create(); const embedder = await PngEmbedder.for(greyscalePng); @@ -33,7 +38,7 @@ describe(`PngEmbedder`, () => { expect(context.lookup(ref)).toBeInstanceOf(PDFRawStream); }); - it(`can embed RGBA PNG images into PDFContexts`, async () => { + it('can embed RGBA PNG images into PDFContexts', async () => { const context = PDFContext.create(); const embedder = await PngEmbedder.for(rgbaPng); @@ -43,7 +48,7 @@ describe(`PngEmbedder`, () => { expect(context.lookup(ref)).toBeInstanceOf(PDFRawStream); }); - it(`can embed RGB PNG images into PDFContexts`, async () => { + it('can embed RGB PNG images into PDFContexts', async () => { const context = PDFContext.create(); const embedder = await PngEmbedder.for(rgbPng); @@ -53,7 +58,7 @@ describe(`PngEmbedder`, () => { expect(context.lookup(ref)).toBeInstanceOf(PDFRawStream); }); - it(`can extract properties of greyscale PNG images`, async () => { + it('can extract properties of greyscale PNG images', async () => { const embedder = await PngEmbedder.for(greyscalePng); expect(embedder.bitsPerComponent).toBe(8); @@ -62,7 +67,7 @@ describe(`PngEmbedder`, () => { expect(embedder.colorSpace).toBe('DeviceRGB'); }); - it(`can extract properties of RGBA PNG images`, async () => { + it('can extract properties of RGBA PNG images', async () => { const embedder = await PngEmbedder.for(rgbaPng); expect(embedder.bitsPerComponent).toBe(8); @@ -71,7 +76,7 @@ describe(`PngEmbedder`, () => { expect(embedder.colorSpace).toBe('DeviceRGB'); }); - it(`can extract properties of RGB PNG images`, async () => { + it('can extract properties of RGB PNG images', async () => { const embedder = await PngEmbedder.for(rgbPng); expect(embedder.bitsPerComponent).toBe(8); diff --git a/tests/core/embedders/StandardFontEmbedder.spec.ts b/tests/core/embedders/StandardFontEmbedder.spec.ts index a6235b1cb..ac80fafd9 100644 --- a/tests/core/embedders/StandardFontEmbedder.spec.ts +++ b/tests/core/embedders/StandardFontEmbedder.spec.ts @@ -5,20 +5,20 @@ import { PDFHexString, PDFRef, StandardFontEmbedder, -} from 'src/index'; +} from '../../../src/index'; -describe(`StandardFontEmbedder`, () => { - it(`can be constructed with StandardFontEmbedder.for(...)`, () => { +describe('StandardFontEmbedder', () => { + it('can be constructed with StandardFontEmbedder.for(...)', () => { const embedder = StandardFontEmbedder.for(FontNames.Helvetica); expect(embedder).toBeInstanceOf(StandardFontEmbedder); }); - it(`exposes the font's name`, () => { + it("exposes the font's name", () => { const embedder = StandardFontEmbedder.for(FontNames.HelveticaOblique); expect(embedder.fontName).toBe('Helvetica-Oblique'); }); - it(`can use a custom font name`, () => { + it('can use a custom font name', () => { const customName = 'Roboto 2'; const embedder = StandardFontEmbedder.for( FontNames.HelveticaOblique, @@ -27,7 +27,7 @@ describe(`StandardFontEmbedder`, () => { expect(embedder.customName).toBe(customName); }); - it(`can embed standard font dictionaries into PDFContexts without a predefined ref`, () => { + it('can embed standard font dictionaries into PDFContexts without a predefined ref', () => { const context = PDFContext.create(); const embedder = StandardFontEmbedder.for(FontNames.Courier); @@ -37,7 +37,7 @@ describe(`StandardFontEmbedder`, () => { expect(context.lookup(ref)).toBeInstanceOf(PDFDict); }); - it(`can embed standard font dictionaries into PDFContexts with a predefined ref`, () => { + it('can embed standard font dictionaries into PDFContexts with a predefined ref', () => { const context = PDFContext.create(); const predefinedRef = PDFRef.of(9999); const embedder = StandardFontEmbedder.for(FontNames.Courier); @@ -49,7 +49,7 @@ describe(`StandardFontEmbedder`, () => { expect(ref).toBe(predefinedRef); }); - it(`can encode text strings into PDFHexString objects`, () => { + it('can encode text strings into PDFHexString objects', () => { const text = 'Stuff and thingz!'; const embedder = StandardFontEmbedder.for(FontNames.TimesRoman); expect(embedder.encodeText(text)).toBeInstanceOf(PDFHexString); @@ -58,20 +58,20 @@ describe(`StandardFontEmbedder`, () => { ); }); - it(`can measure the width of text strings at the given font size`, () => { + it('can measure the width of text strings at the given font size', () => { const text = 'Stuff and thingz!'; const embedder = StandardFontEmbedder.for(FontNames.HelveticaBold); expect(embedder.widthOfTextAtSize(text, 12)).toBe(94.656); expect(embedder.widthOfTextAtSize(text, 24)).toBe(189.312); }); - it(`can measure the height of the font at the given size`, () => { + it('can measure the height of the font at the given size', () => { const embedder = StandardFontEmbedder.for(FontNames.HelveticaBold); expect(embedder.heightOfFontAtSize(12)).toBeCloseTo(11.1); expect(embedder.heightOfFontAtSize(24)).toBeCloseTo(22.2); }); - it(`can measure the size of the font at a given height`, () => { + it('can measure the size of the font at a given height', () => { const embedder = StandardFontEmbedder.for(FontNames.HelveticaBold); expect(embedder.sizeOfFontAtHeight(12)).toBeCloseTo(12.972); expect(embedder.sizeOfFontAtHeight(24)).toBeCloseTo(25.945); diff --git a/tests/core/objects/PDFArray.spec.ts b/tests/core/objects/PDFArray.spec.ts index 59e8f7587..8ca04c946 100644 --- a/tests/core/objects/PDFArray.spec.ts +++ b/tests/core/objects/PDFArray.spec.ts @@ -9,13 +9,13 @@ import { PDFNumber, PDFRef, PDFString, -} from 'src/core'; -import { toCharCode, typedArrayFor } from 'src/utils'; +} from '../../../src/core'; +import { toCharCode, typedArrayFor } from '../../../src/utils'; -describe(`PDFArray`, () => { +describe('PDFArray', () => { const context = PDFContext.create(); - it(`can be constructed with PDFArray.withContext(...)`, () => { + it('can be constructed with PDFArray.withContext(...)', () => { expect(PDFArray.withContext(context)).toBeInstanceOf(PDFArray); }); @@ -46,7 +46,7 @@ describe(`PDFArray`, () => { pdfArray.push(pdfSubArray); pdfArray.push(pdfRef); - it(`retains pushed objects`, () => { + it('retains pushed objects', () => { expect(pdfArray.size()).toBe(8); expect(pdfArray.get(0)).toBe(pdfBool); @@ -59,7 +59,7 @@ describe(`PDFArray`, () => { expect(pdfArray.get(7)).toBe(pdfRef); }); - it(`allows objects to be assigned to specific indices`, () => { + it('allows objects to be assigned to specific indices', () => { const array = PDFArray.withContext(PDFContext.create()); array.push(PDFName.of('a')); array.push(PDFName.of('b')); @@ -69,7 +69,7 @@ describe(`PDFArray`, () => { expect(array.size()).toBe(3); }); - it(`allows objects to be inserted at specific indices`, () => { + it('allows objects to be inserted at specific indices', () => { const array = PDFArray.withContext(PDFContext.create()); array.push(PDFName.of('a')); array.push(PDFName.of('b')); @@ -81,7 +81,7 @@ describe(`PDFArray`, () => { expect(array.size()).toBe(4); }); - it(`allows objects to be removed from specific indices`, () => { + it('allows objects to be removed from specific indices', () => { const array = PDFArray.withContext(PDFContext.create()); array.push(PDFName.of('a')); array.push(PDFName.of('b')); @@ -92,7 +92,7 @@ describe(`PDFArray`, () => { expect(array.size()).toBe(2); }); - it(`can be converted to an Array`, () => { + it('can be converted to an Array', () => { expect(pdfArray.asArray()).toEqual([ pdfBool, pdfHexString, @@ -105,24 +105,24 @@ describe(`PDFArray`, () => { ]); }); - it(`can be cloned`, () => { + it('can be cloned', () => { const original = pdfArray; const clone = original.clone(); expect(clone).not.toBe(original); expect(clone.toString()).toBe(original.toString()); }); - it(`can be converted to a string`, () => { + it('can be converted to a string', () => { expect(String(pdfArray)).toBe( '[ true /Foo#23Bar! null -24.179 (foobar) [ true <<\n/Foo /Bar\n>> ] 21 92 R ]', ); }); - it(`can provide its size in bytes`, () => { + it('can provide its size in bytes', () => { expect(pdfArray.sizeInBytes()).toBe(84); }); - it(`can be serialized`, () => { + it('can be serialized', () => { const buffer = new Uint8Array(88).fill(toCharCode(' ')); expect(pdfArray.copyBytesInto(buffer, 3)).toBe(84); expect(buffer).toEqual( diff --git a/tests/core/objects/PDFBool.spec.ts b/tests/core/objects/PDFBool.spec.ts index 7bab13e77..1c2a52bf3 100644 --- a/tests/core/objects/PDFBool.spec.ts +++ b/tests/core/objects/PDFBool.spec.ts @@ -1,40 +1,40 @@ -import { PDFBool, PrivateConstructorError } from 'src/core'; -import { toCharCode, typedArrayFor } from 'src/utils'; +import { PDFBool, PrivateConstructorError } from '../../../src/core'; +import { toCharCode, typedArrayFor } from '../../../src/utils'; -describe(`PDFBool`, () => { - it(`cannot be publicly constructed`, () => { +describe('PDFBool', () => { + it('cannot be publicly constructed', () => { expect(() => new (PDFBool as any)({}, true)).toThrow( new PrivateConstructorError(PDFBool.name), ); }); - it(`can be converted to a boolean`, () => { + it('can be converted to a boolean', () => { expect(PDFBool.True.asBoolean()).toBe(true); expect(PDFBool.False.asBoolean()).toBe(false); }); - it(`can be cloned`, () => { + it('can be cloned', () => { expect(PDFBool.True.clone()).toBe(PDFBool.True); expect(PDFBool.False.clone()).toBe(PDFBool.False); }); - it(`can be converted to a string`, () => { + it('can be converted to a string', () => { expect(String(PDFBool.True)).toBe('true'); expect(String(PDFBool.False)).toBe('false'); }); - it(`can provide its size in bytes`, () => { + it('can provide its size in bytes', () => { expect(PDFBool.True.sizeInBytes()).toBe(4); expect(PDFBool.False.sizeInBytes()).toBe(5); }); - it(`can be serialized when true`, () => { + it('can be serialized when true', () => { const buffer = new Uint8Array(8).fill(toCharCode(' ')); expect(PDFBool.True.copyBytesInto(buffer, 3)).toBe(4); expect(buffer).toEqual(typedArrayFor(' true ')); }); - it(`can be serialized when false`, () => { + it('can be serialized when false', () => { const buffer = new Uint8Array(9).fill(toCharCode(' ')); expect(PDFBool.False.copyBytesInto(buffer, 1)).toBe(5); expect(buffer).toEqual(typedArrayFor(' false ')); diff --git a/tests/core/objects/PDFDict.spec.ts b/tests/core/objects/PDFDict.spec.ts index 0eb880a34..f136c2ff7 100644 --- a/tests/core/objects/PDFDict.spec.ts +++ b/tests/core/objects/PDFDict.spec.ts @@ -10,13 +10,13 @@ import { PDFRef, PDFString, PDFObject, -} from 'src/core'; -import { toCharCode, typedArrayFor } from 'src/utils'; +} from '../../../src/core'; +import { toCharCode, typedArrayFor } from '../../../src/utils'; -describe(`PDFDict`, () => { +describe('PDFDict', () => { const context = PDFContext.create(); - it(`can be constructed from PDFDict.withContext(...)`, () => { + it('can be constructed from PDFDict.withContext(...)', () => { expect(PDFDict.withContext(context)).toBeInstanceOf(PDFDict); }); @@ -47,7 +47,7 @@ describe(`PDFDict`, () => { pdfDict.set(PDFName.of('Dictionary'), pdfSubDict); - it(`can detect if a value is present`, () => { + it('can detect if a value is present', () => { expect(pdfDict.has(PDFName.of('Boolean'))).toBe(true); expect(pdfDict.has(PDFName.of('HexString'))).toBe(true); expect(pdfDict.has(PDFName.of('Name'))).toBe(true); @@ -60,7 +60,7 @@ describe(`PDFDict`, () => { expect(pdfDict.has(PDFName.of('foo'))).toBe(false); }); - it(`retains entered objects`, () => { + it('retains entered objects', () => { expect(pdfDict.entries().length).toBe(8); expect(pdfDict.get(PDFName.of('Boolean'))).toBe(pdfBool); @@ -74,7 +74,7 @@ describe(`PDFDict`, () => { expect(pdfSubDict.get(PDFName.of('Array'))).toBe(pdfArray); }); - it(`can be converted to a Map`, () => { + it('can be converted to a Map', () => { expect(pdfDict.asMap()).toEqual( new Map([ [PDFName.of('Boolean'), pdfBool], @@ -89,14 +89,14 @@ describe(`PDFDict`, () => { ); }); - it(`can be cloned`, () => { + it('can be cloned', () => { const original = pdfDict; const clone = original.clone(); expect(clone).not.toBe(original); expect(clone.toString()).toBe(original.toString()); }); - it(`can be converted to a string`, () => { + it('can be converted to a string', () => { expect(String(pdfDict)).toBe( `<< /Boolean true @@ -113,11 +113,11 @@ describe(`PDFDict`, () => { ); }); - it(`can provide its size in bytes`, () => { + it('can provide its size in bytes', () => { expect(pdfDict.sizeInBytes()).toBe(153); }); - it(`can be serialized`, () => { + it('can be serialized', () => { const buffer = new Uint8Array(157).fill(toCharCode(' ')); expect(pdfDict.copyBytesInto(buffer, 3)).toBe(153); expect(buffer).toEqual( @@ -138,7 +138,7 @@ describe(`PDFDict`, () => { ); }); - it(`returns "undefined" if the underlying value is "PDFNull"`, () => { + it('returns "undefined" if the underlying value is "PDFNull"', () => { const dict = context.obj({ foo: null }); dict.set(PDFName.of('Bar'), PDFNull); context.assign(PDFRef.of(21), PDFNull); @@ -166,7 +166,7 @@ describe(`PDFDict`, () => { }); // https://github.com/Hopding/pdf-lib/issues/1075 - it(`can generate new keys that don't conflict with existing ones`, () => { + it("can generate new keys that don't conflict with existing ones", () => { const anotherContext = PDFContext.create(); const anotherDict = anotherContext.obj({}); const anotherKey = anotherDict.uniqueKey(); diff --git a/tests/core/objects/PDFHexString.spec.ts b/tests/core/objects/PDFHexString.spec.ts index e29eebaa8..85f5c2c9f 100644 --- a/tests/core/objects/PDFHexString.spec.ts +++ b/tests/core/objects/PDFHexString.spec.ts @@ -1,14 +1,14 @@ -import { PDFHexString } from 'src/core'; -import { toCharCode, typedArrayFor } from 'src/utils'; +import { PDFHexString } from '../../../src/core'; +import { toCharCode, typedArrayFor } from '../../../src/utils'; -describe(`PDFHexString`, () => { - it(`can be constructed from PDFHexString.of(...)`, () => { +describe('PDFHexString', () => { + it('can be constructed from PDFHexString.of(...)', () => { expect(PDFHexString.of('4E6F762073686D6F7A2')).toBeInstanceOf(PDFHexString); expect(PDFHexString.of('901FA3')).toBeInstanceOf(PDFHexString); expect(PDFHexString.of('901FA')).toBeInstanceOf(PDFHexString); }); - it(`can be constructed from a string of text (using UTF-16BE encoding)`, () => { + it('can be constructed from a string of text (using UTF-16BE encoding)', () => { expect(String(PDFHexString.fromText(''))).toBe(''); expect(String(PDFHexString.fromText('ä☺𠜎️☁️💩'))).toBe( '', @@ -18,66 +18,66 @@ describe(`PDFHexString`, () => { ); }); - describe(`converting to bytes`, () => { - it(`can handle an even number of hex digits`, () => { + describe('converting to bytes', () => { + it('can handle an even number of hex digits', () => { const hex = 'FEFF0045006700670020D83CDF73'; // prettier-ignore expect(PDFHexString.of(hex).asBytes()).toEqual(Uint8Array.of( - 0xFE, 0xFF, - 0x00, 0x45, - 0x00, 0x67, - 0x00, 0x67, - 0x00, 0x20, - 0xD8, 0x3C, + 0xFE, 0xFF, + 0x00, 0x45, + 0x00, 0x67, + 0x00, 0x67, + 0x00, 0x20, + 0xD8, 0x3C, 0xDF, 0x73, )); }); - it(`can handle an odd number of hex digits`, () => { + it('can handle an odd number of hex digits', () => { const hex = '6145627300623'; // prettier-ignore expect(PDFHexString.of(hex).asBytes()).toEqual(Uint8Array.of( - 0x61, 0x45, - 0x62, 0x73, - 0x00, 0x62, + 0x61, 0x45, + 0x62, 0x73, + 0x00, 0x62, 0x30, )); }); }); - describe(`decoding to string`, () => { - it(`can interpret UTF-16BE strings`, () => { + describe('decoding to string', () => { + it('can interpret UTF-16BE strings', () => { const hex = 'FEFF0045006700670020D83CDF73'; expect(PDFHexString.of(hex).decodeText()).toBe('Egg 🍳'); }); - it(`can interpret UTF-16LE strings`, () => { + it('can interpret UTF-16LE strings', () => { const hex = 'FFFE45006700670020003CD873DF'; expect(PDFHexString.of(hex).decodeText()).toBe('Egg 🍳'); }); - it(`can interpret PDFDocEncoded strings`, () => { + it('can interpret PDFDocEncoded strings', () => { const hex = '61456273006236'; expect(PDFHexString.of(hex).decodeText()).toBe('aEbs\0b6'); }); }); - describe(`decoding to date`, () => { - it(`can interpret date strings of the form D:YYYYMMDDHHmmSSOHH'mm`, () => { + describe('decoding to date', () => { + it("can interpret date strings of the form D:YYYYMMDDHHmmSSOHH'mm", () => { expect( - PDFHexString.fromText(`D:20200321165011+01'01`).decodeDate(), + PDFHexString.fromText("D:20200321165011+01'01").decodeDate(), ).toStrictEqual(new Date('2020-03-21T15:49:11Z')); expect( - PDFHexString.fromText(`D:20200321165011-01'01`).decodeDate(), + PDFHexString.fromText("D:20200321165011-01'01").decodeDate(), ).toStrictEqual(new Date('2020-03-21T17:51:11Z')); expect( - PDFHexString.fromText(`D:20200321165011Z00'00`).decodeDate(), + PDFHexString.fromText("D:20200321165011Z00'00").decodeDate(), ).toStrictEqual(new Date('2020-03-21T16:50:11Z')); }); - it(`can interpret date strings of the form D:YYYYMMDDHHmmSSOHH`, () => { + it('can interpret date strings of the form D:YYYYMMDDHHmmSSOHH', () => { expect( PDFHexString.fromText('D:20200321165011+01').decodeDate(), ).toStrictEqual(new Date('2020-03-21T15:50:11Z')); @@ -89,64 +89,64 @@ describe(`PDFHexString`, () => { ).toStrictEqual(new Date('2020-03-21T16:50:11Z')); }); - it(`can interpret date strings of the form D:YYYYMMDDHHmmSSO`, () => { + it('can interpret date strings of the form D:YYYYMMDDHHmmSSO', () => { expect( PDFHexString.fromText('D:20200321165011Z').decodeDate(), ).toStrictEqual(new Date('2020-03-21T16:50:11Z')); }); - it(`can interpret date strings of the form D:YYYYMMDDHHmmSS`, () => { + it('can interpret date strings of the form D:YYYYMMDDHHmmSS', () => { expect( PDFHexString.fromText('D:20200321165011').decodeDate(), ).toStrictEqual(new Date('2020-03-21T16:50:11Z')); }); - it(`can interpret date strings of the form D:YYYYMMDDHHmm`, () => { + it('can interpret date strings of the form D:YYYYMMDDHHmm', () => { expect( PDFHexString.fromText('D:202003211650').decodeDate(), ).toStrictEqual(new Date('2020-03-21T16:50:00Z')); }); - it(`can interpret date strings of the form D:YYYYMMDDHH`, () => { + it('can interpret date strings of the form D:YYYYMMDDHH', () => { expect(PDFHexString.fromText('D:2020032116').decodeDate()).toStrictEqual( new Date('2020-03-21T16:00:00Z'), ); }); - it(`can interpret date strings of the form D:YYYYMMDD`, () => { + it('can interpret date strings of the form D:YYYYMMDD', () => { expect(PDFHexString.fromText('D:20200321').decodeDate()).toStrictEqual( new Date('2020-03-21T00:00:00Z'), ); }); - it(`can interpret date strings of the form D:YYYYMM`, () => { + it('can interpret date strings of the form D:YYYYMM', () => { expect(PDFHexString.fromText('D:202003').decodeDate()).toStrictEqual( new Date('2020-03-01T00:00:00Z'), ); }); - it(`can interpret date strings of the form D:YYYY`, () => { + it('can interpret date strings of the form D:YYYY', () => { expect(PDFHexString.fromText('D:2020').decodeDate()).toStrictEqual( new Date('2020-01-01T00:00:00Z'), ); }); }); - it(`can be converted to a string`, () => { + it('can be converted to a string', () => { expect(PDFHexString.of('901FA').asString()).toBe('901FA'); expect(PDFHexString.fromText('stuff 💩 and 🎂things').asString()).toBe( 'FEFF007300740075006600660020D83DDCA900200061006E00640020D83CDF82007400680069006E00670073', ); }); - it(`can be cloned`, () => { + it('can be cloned', () => { const original = PDFHexString.of('901FA'); const clone = original.clone(); expect(clone).not.toBe(original); expect(clone.toString()).toBe(original.toString()); }); - it(`can be converted to a string`, () => { + it('can be converted to a string', () => { expect(String(PDFHexString.of('4E6F762073686D6F7A2'))).toBe( '<4E6F762073686D6F7A2>', ); @@ -154,13 +154,13 @@ describe(`PDFHexString`, () => { expect(String(PDFHexString.of('901FA'))).toBe('<901FA>'); }); - it(`can provide its size in bytes`, () => { + it('can provide its size in bytes', () => { expect(PDFHexString.of('4E6F762073686D6F7A2').sizeInBytes()).toBe(21); expect(PDFHexString.of('901FA3').sizeInBytes()).toBe(8); expect(PDFHexString.of('901FA').sizeInBytes()).toBe(7); }); - it(`can be serialized`, () => { + it('can be serialized', () => { const buffer = new Uint8Array(11).fill(toCharCode(' ')); expect(PDFHexString.of('901FA').copyBytesInto(buffer, 3)).toBe(7); expect(buffer).toEqual(typedArrayFor(' <901FA> ')); diff --git a/tests/core/objects/PDFInvalidObject.spec.ts b/tests/core/objects/PDFInvalidObject.spec.ts index 135efcd41..22de440ac 100644 --- a/tests/core/objects/PDFInvalidObject.spec.ts +++ b/tests/core/objects/PDFInvalidObject.spec.ts @@ -1,28 +1,28 @@ -import { PDFInvalidObject } from 'src/core'; +import { PDFInvalidObject } from '../../../src/core'; -describe(`PDFInvalidObject`, () => { +describe('PDFInvalidObject', () => { const data = new Uint8Array([12, 39, 92, 38, 38, 28, 49]); - it(`can be constructed from PDFInvalidObject.of(...)`, () => { + it('can be constructed from PDFInvalidObject.of(...)', () => { expect(PDFInvalidObject.of(data)).toBeInstanceOf(PDFInvalidObject); }); - it(`can be cloned`, () => { + it('can be cloned', () => { const original = PDFInvalidObject.of(data); const clone = original.clone(); expect(clone).not.toBe(original); expect(clone.toString()).toEqual(original.toString()); }); - it(`can be converted to a string`, () => { + it('can be converted to a string', () => { expect(String(PDFInvalidObject.of(data))).toBe('PDFInvalidObject(7 bytes)'); }); - it(`can provide its size in bytes`, () => { + it('can provide its size in bytes', () => { expect(PDFInvalidObject.of(data).sizeInBytes()).toBe(7); }); - it(`can be serialized`, () => { + it('can be serialized', () => { const buffer = new Uint8Array(11).fill(0); expect(PDFInvalidObject.of(data).copyBytesInto(buffer, 3)).toBe(7); expect(buffer).toEqual( diff --git a/tests/core/objects/PDFName.spec.ts b/tests/core/objects/PDFName.spec.ts index 91d02553b..1482127c9 100644 --- a/tests/core/objects/PDFName.spec.ts +++ b/tests/core/objects/PDFName.spec.ts @@ -1,20 +1,20 @@ -import { PDFName, PrivateConstructorError } from 'src/core'; -import { toCharCode, typedArrayFor } from 'src/utils'; +import { PDFName, PrivateConstructorError } from '../../../src/core'; +import { toCharCode, typedArrayFor } from '../../../src/utils'; -describe(`PDFName`, () => { - it(`can be constructed from PDFName.of(...)`, () => { +describe('PDFName', () => { + it('can be constructed from PDFName.of(...)', () => { expect(PDFName.of('foobar')).toBeInstanceOf(PDFName); expect(PDFName.of('A;Name_With-***Characters?')).toBeInstanceOf(PDFName); expect(PDFName.of('paired#28#29parentheses')).toBeInstanceOf(PDFName); }); - it(`cannot be publicly constructed`, () => { + it('cannot be publicly constructed', () => { expect(() => new (PDFName as any)({}, 'stuff')).toThrow( new PrivateConstructorError(PDFName.name), ); }); - it(`returns the same instance when given the same value`, () => { + it('returns the same instance when given the same value', () => { expect(PDFName.of('foobar')).toBe(PDFName.of('foobar')); expect(PDFName.of('A;Name_With-***Characters?')).toBe( PDFName.of('A;Name_With-***Characters?'), @@ -24,7 +24,7 @@ describe(`PDFName`, () => { ); }); - it(`decodes hex codes in the values`, () => { + it('decodes hex codes in the values', () => { expect(PDFName.of('Lime#20Green')).toBe(PDFName.of('Lime Green')); expect(PDFName.of('paired#28#29parentheses')).toBe( PDFName.of('paired()parentheses'), @@ -53,7 +53,7 @@ describe(`PDFName`, () => { expect(PDFName.of('#4F')).toBe(PDFName.of('O')); }); - it(`encodes hashes, whitespace, and delimiters when serialized`, () => { + it('encodes hashes, whitespace, and delimiters when serialized', () => { expect(PDFName.of('Foo#').toString()).toBe('/Foo#23'); // Note that the \0 shouldn't ever be written into a name, @@ -77,12 +77,12 @@ describe(`PDFName`, () => { expect(PDFName.of('Foo%').toString()).toBe('/Foo#25'); }); - it(`can be cloned`, () => { + it('can be cloned', () => { expect(PDFName.of('foobar').clone()).toBe(PDFName.of('foobar')); expect(PDFName.of('Lime#20Green').clone()).toBe(PDFName.of('Lime Green')); }); - it(`can be converted to a string`, () => { + it('can be converted to a string', () => { expect(String(PDFName.of('foobar'))).toBe('/foobar'); expect(String(PDFName.of('Lime Green'))).toBe('/Lime#20Green'); expect(String(PDFName.of('\0\t\n\f\r '))).toBe('/#00#09#0A#0C#0D#20'); @@ -96,7 +96,7 @@ describe(`PDFName`, () => { expect(String(PDFName.of('A#42'))).toBe('/AB'); }); - it(`can provide its size in bytes`, () => { + it('can provide its size in bytes', () => { expect(PDFName.of('foobar').sizeInBytes()).toBe(7); expect(PDFName.of('Lime Green').sizeInBytes()).toBe(13); expect(PDFName.of('\0\t\n\f\r ').sizeInBytes()).toBe(19); @@ -106,7 +106,7 @@ describe(`PDFName`, () => { expect(PDFName.of('A#42').sizeInBytes()).toBe(3); }); - it(`can be serialized`, () => { + it('can be serialized', () => { const buffer1 = new Uint8Array(23).fill(toCharCode(' ')); expect(PDFName.of('\0\t\n\f\r ').copyBytesInto(buffer1, 3)).toBe(19); expect(buffer1).toEqual(typedArrayFor(' /#00#09#0A#0C#0D#20 ')); diff --git a/tests/core/objects/PDFNull.spec.ts b/tests/core/objects/PDFNull.spec.ts index 1ebfc3f64..113a7a2cd 100644 --- a/tests/core/objects/PDFNull.spec.ts +++ b/tests/core/objects/PDFNull.spec.ts @@ -1,28 +1,28 @@ -import { PDFNull } from 'src/core'; -import { toCharCode, typedArrayFor } from 'src/utils'; +import { PDFNull } from '../../../src/core'; +import { toCharCode, typedArrayFor } from '../../../src/utils'; -describe(`PDFNull`, () => { - it(`cannot be publicly constructed`, () => { +describe('PDFNull', () => { + it('cannot be publicly constructed', () => { expect(() => new (PDFNull as any)()).toThrow(); }); - it(`can be converted to null`, () => { + it('can be converted to null', () => { expect(PDFNull.asNull()).toBe(null); }); - it(`can be cloned`, () => { + it('can be cloned', () => { expect(PDFNull.clone()).toBe(PDFNull); }); - it(`can be converted to a string`, () => { + it('can be converted to a string', () => { expect(String(PDFNull)).toBe('null'); }); - it(`can provide its size in bytes`, () => { + it('can provide its size in bytes', () => { expect(PDFNull.sizeInBytes()).toBe(4); }); - it(`can be serialized`, () => { + it('can be serialized', () => { const buffer = new Uint8Array(8).fill(toCharCode(' ')); expect(PDFNull.copyBytesInto(buffer, 3)).toBe(4); expect(buffer).toEqual(typedArrayFor(' null ')); diff --git a/tests/core/objects/PDFNumber.spec.ts b/tests/core/objects/PDFNumber.spec.ts index 55070724e..64d203950 100644 --- a/tests/core/objects/PDFNumber.spec.ts +++ b/tests/core/objects/PDFNumber.spec.ts @@ -1,21 +1,21 @@ -import { PDFNumber } from 'src/core'; -import { toCharCode, typedArrayFor } from 'src/utils'; +import { PDFNumber } from '../../../src/core'; +import { toCharCode, typedArrayFor } from '../../../src/utils'; -describe(`PDFNumber`, () => { - it(`can be constructed from PDFNumber.of(...)`, () => { +describe('PDFNumber', () => { + it('can be constructed from PDFNumber.of(...)', () => { expect(PDFNumber.of(21)).toBeInstanceOf(PDFNumber); expect(PDFNumber.of(-43)).toBeInstanceOf(PDFNumber); expect(PDFNumber.of(-0.1e7)).toBeInstanceOf(PDFNumber); }); - it(`can be cloned`, () => { + it('can be cloned', () => { const original = PDFNumber.of(-21.42); const clone = original.clone(); expect(clone).not.toBe(original); expect(clone.toString()).toBe(original.toString()); }); - it(`can be converted to a string`, () => { + it('can be converted to a string', () => { expect(String(PDFNumber.of(21))).toEqual('21'); expect(String(PDFNumber.of(-43))).toEqual('-43'); expect(String(PDFNumber.of(3.403e38))).toEqual( @@ -29,14 +29,14 @@ describe(`PDFNumber`, () => { ); }); - it(`can provide its size in bytes`, () => { + it('can provide its size in bytes', () => { expect(PDFNumber.of(21).sizeInBytes()).toBe(2); expect(PDFNumber.of(-43).sizeInBytes()).toBe(3); expect(PDFNumber.of(3.403e38).sizeInBytes()).toBe(39); expect(PDFNumber.of(-3.403e38).sizeInBytes()).toBe(40); }); - it(`can be serialized`, () => { + it('can be serialized', () => { const buffer1 = new Uint8Array(8).fill(toCharCode(' ')); expect(PDFNumber.of(21).copyBytesInto(buffer1, 3)).toBe(2); expect(buffer1).toEqual(typedArrayFor(' 21 ')); diff --git a/tests/core/objects/PDFObject.spec.ts b/tests/core/objects/PDFObject.spec.ts index 2919e21d6..2f75229fe 100644 --- a/tests/core/objects/PDFObject.spec.ts +++ b/tests/core/objects/PDFObject.spec.ts @@ -1,27 +1,27 @@ -import { MethodNotImplementedError, PDFObject } from 'src/core'; +import { MethodNotImplementedError, PDFObject } from '../../../src/core'; -describe(`PDFObject`, () => { +describe('PDFObject', () => { const pdfObject = new PDFObject(); - it(`does not implement clone()`, () => { + it('does not implement clone()', () => { expect(() => pdfObject.clone()).toThrow( new MethodNotImplementedError(PDFObject.name, 'clone'), ); }); - it(`does not implement toString()`, () => { + it('does not implement toString()', () => { expect(() => pdfObject.toString()).toThrow( new MethodNotImplementedError(PDFObject.name, 'toString'), ); }); - it(`does not implement sizeInBytes()`, () => { + it('does not implement sizeInBytes()', () => { expect(() => pdfObject.sizeInBytes()).toThrow( new MethodNotImplementedError(PDFObject.name, 'sizeInBytes'), ); }); - it(`does not implement copyBytesInto()`, () => { + it('does not implement copyBytesInto()', () => { expect(() => pdfObject.copyBytesInto(new Uint8Array(), 0)).toThrow( new MethodNotImplementedError(PDFObject.name, 'copyBytesInto'), ); diff --git a/tests/core/objects/PDFRawStream.spec.ts b/tests/core/objects/PDFRawStream.spec.ts index dd078fceb..ee29a7417 100644 --- a/tests/core/objects/PDFRawStream.spec.ts +++ b/tests/core/objects/PDFRawStream.spec.ts @@ -1,37 +1,37 @@ -import { PDFContext, PDFDict, PDFRawStream } from 'src/core'; -import { mergeIntoTypedArray, toCharCode } from 'src/utils'; +import { PDFContext, PDFDict, PDFRawStream } from '../../../src/core'; +import { mergeIntoTypedArray, toCharCode } from '../../../src/utils'; -describe(`PDFRawStream`, () => { +describe('PDFRawStream', () => { const context = PDFContext.create(); const dict = PDFDict.withContext(context); const data = new Uint8Array([12, 39, 92, 38, 38, 28, 49]); - it(`can be constructed from PDFRawStream.of(...)`, () => { + it('can be constructed from PDFRawStream.of(...)', () => { expect(PDFRawStream.of(dict, data)).toBeInstanceOf(PDFRawStream); }); - it(`can be converted to a Uint8Array`, () => { + it('can be converted to a Uint8Array', () => { expect(PDFRawStream.of(dict, data).asUint8Array()).toEqual(data); }); - it(`can be cloned`, () => { + it('can be cloned', () => { const original = PDFRawStream.of(dict, data); const clone = original.clone(); expect(clone).not.toBe(original); expect(clone.toString()).toEqual(original.toString()); }); - it(`can be converted to a string`, () => { + it('can be converted to a string', () => { expect(String(PDFRawStream.of(dict, data))).toEqual( - `<<\n/Length 7\n>>\nstream\n\f'\\&&\u001c1\nendstream`, + "<<\n/Length 7\n>>\nstream\n\f'\\&&\u001c1\nendstream", ); }); - it(`can provide its size in bytes`, () => { + it('can provide its size in bytes', () => { expect(PDFRawStream.of(dict, data).sizeInBytes()).toBe(40); }); - it(`can be serialized`, () => { + it('can be serialized', () => { const buffer = new Uint8Array(44).fill(toCharCode(' ')); expect(PDFRawStream.of(dict, data).copyBytesInto(buffer, 3)); expect(buffer).toEqual( diff --git a/tests/core/objects/PDFRef.spec.ts b/tests/core/objects/PDFRef.spec.ts index 7f7069d35..7e0cd163e 100644 --- a/tests/core/objects/PDFRef.spec.ts +++ b/tests/core/objects/PDFRef.spec.ts @@ -1,46 +1,46 @@ -import { PDFRef, PrivateConstructorError } from 'src/core'; -import { toCharCode, typedArrayFor } from 'src/utils'; +import { PDFRef, PrivateConstructorError } from '../../../src/core'; +import { toCharCode, typedArrayFor } from '../../../src/utils'; -describe(`PDFRef`, () => { - it(`can be constructed from PDFRef.of(...)`, () => { +describe('PDFRef', () => { + it('can be constructed from PDFRef.of(...)', () => { expect(PDFRef.of(0)).toBeInstanceOf(PDFRef); expect(PDFRef.of(0, 21)).toBeInstanceOf(PDFRef); expect(PDFRef.of(94, 0)).toBeInstanceOf(PDFRef); expect(PDFRef.of(4678, 9120)).toBeInstanceOf(PDFRef); }); - it(`cannot be publicly constructed`, () => { + it('cannot be publicly constructed', () => { expect(() => new (PDFRef as any)({}, 'stuff')).toThrow( new PrivateConstructorError(PDFRef.name), ); }); - it(`returns the same instance when given the same object and generation numbers`, () => { + it('returns the same instance when given the same object and generation numbers', () => { expect(PDFRef.of(0)).toBe(PDFRef.of(0)); expect(PDFRef.of(0, 21)).toBe(PDFRef.of(0, 21)); expect(PDFRef.of(94, 0)).toBe(PDFRef.of(94, 0)); expect(PDFRef.of(4678, 9120)).toBe(PDFRef.of(4678, 9120)); }); - it(`can be cloned`, () => { + it('can be cloned', () => { expect(PDFRef.of(4678, 9120).clone()).toBe(PDFRef.of(4678, 9120)); }); - it(`can be converted to a string`, () => { - expect(String(PDFRef.of(0))).toBe(`0 0 R`); - expect(String(PDFRef.of(0, 21))).toBe(`0 21 R`); - expect(String(PDFRef.of(94, 0))).toBe(`94 0 R`); - expect(String(PDFRef.of(4678, 9120))).toBe(`4678 9120 R`); + it('can be converted to a string', () => { + expect(String(PDFRef.of(0))).toBe('0 0 R'); + expect(String(PDFRef.of(0, 21))).toBe('0 21 R'); + expect(String(PDFRef.of(94, 0))).toBe('94 0 R'); + expect(String(PDFRef.of(4678, 9120))).toBe('4678 9120 R'); }); - it(`can provide its size in bytes`, () => { + it('can provide its size in bytes', () => { expect(PDFRef.of(0).sizeInBytes()).toBe(5); expect(PDFRef.of(0, 21).sizeInBytes()).toBe(6); expect(PDFRef.of(94, 0).sizeInBytes()).toBe(6); expect(PDFRef.of(4678, 9120).sizeInBytes()).toBe(11); }); - it(`can be serialized`, () => { + it('can be serialized', () => { const buffer1 = new Uint8Array(9).fill(toCharCode(' ')); expect(PDFRef.of(0).copyBytesInto(buffer1, 3)).toBe(5); expect(buffer1).toEqual(typedArrayFor(' 0 0 R ')); diff --git a/tests/core/objects/PDFString.spec.ts b/tests/core/objects/PDFString.spec.ts index 94a3e6fb3..4a5ca0e24 100644 --- a/tests/core/objects/PDFString.spec.ts +++ b/tests/core/objects/PDFString.spec.ts @@ -1,14 +1,14 @@ -import { PDFString } from 'src/core'; -import { toCharCode, typedArrayFor } from 'src/utils'; +import { PDFString } from '../../../src/core'; +import { toCharCode, typedArrayFor } from '../../../src/utils'; -describe(`PDFString`, () => { - it(`can be constructed from PDFString.of(...)`, () => { +describe('PDFString', () => { + it('can be constructed from PDFString.of(...)', () => { expect(PDFString.of('foobar')).toBeInstanceOf(PDFString); expect(PDFString.of(' (foo(bar))')).toBeInstanceOf(PDFString); expect(PDFString.of(')b\\a/z(')).toBeInstanceOf(PDFString); }); - it(`can be constructed from a Date object`, () => { + it('can be constructed from a Date object', () => { const date1 = new Date('2018-06-24T01:58:37.228Z'); expect(String(PDFString.fromDate(date1))).toBe('(D:20180624015837Z)'); @@ -16,36 +16,36 @@ describe(`PDFString`, () => { expect(String(PDFString.fromDate(date2))).toBe('(D:20191221070011Z)'); }); - it(`can be converted to a string`, () => { + it('can be converted to a string', () => { expect(PDFString.of('foobar').asString()).toBe('foobar'); const date = new Date('2018-06-24T01:58:37.228Z'); expect(PDFString.fromDate(date).asString()).toBe('D:20180624015837Z'); }); - it(`can be cloned`, () => { + it('can be cloned', () => { const original = PDFString.of(')b\\a/z('); const clone = original.clone(); expect(clone).not.toBe(original); expect(clone.toString()).toBe(original.toString()); }); - describe(`conversion to string`, () => { - it(`can be converted to a string`, () => { + describe('conversion to string', () => { + it('can be converted to a string', () => { expect(String(PDFString.of('foobar'))).toBe('(foobar)'); }); - it(`does not escape backslashes`, () => { + it('does not escape backslashes', () => { expect(String(PDFString.of('Foo\\Bar\\Qux'))).toBe('(Foo\\Bar\\Qux)'); }); - it(`does not escape nested parenthesis`, () => { + it('does not escape nested parenthesis', () => { expect(String(PDFString.of('(Foo((Bar))Qux)'))).toBe('((Foo((Bar))Qux))'); }); }); - describe(`converting to bytes`, () => { - it(`can interpret escaped octal codes`, () => { + describe('converting to bytes', () => { + it('can interpret escaped octal codes', () => { const literal = '\\376\\377\\000\\105\\000\\147\\000\\147\\000\\040\\330\\074\\337\\163'; @@ -61,7 +61,7 @@ describe(`PDFString`, () => { )); }); - it(`can interpret ASCII symbols`, () => { + it('can interpret ASCII symbols', () => { const literal = '\\376\\377\0E\0g\0g\0 \\330<\\337s'; // prettier-ignore @@ -71,12 +71,12 @@ describe(`PDFString`, () => { toCharCode('\0'), toCharCode('g'), toCharCode('\0'), toCharCode('g'), toCharCode('\0'), toCharCode(' '), - 0o330, toCharCode('<'), + 0o330, toCharCode('<'), 0o337, toCharCode('s'), )); }); - it(`can ignore line breaks`, () => { + it('can ignore line breaks', () => { const literal = '\\376\\377\0E\\\n\\0g\0g\0 \\330<\\337s'; // prettier-ignore @@ -86,24 +86,24 @@ describe(`PDFString`, () => { toCharCode('\0'), toCharCode('g'), toCharCode('\0'), toCharCode('g'), toCharCode('\0'), toCharCode(' '), - 0o330, toCharCode('<'), + 0o330, toCharCode('<'), 0o337, toCharCode('s'), )); }); - it(`can interpret EOLs and line breaks`, () => { + it('can interpret EOLs and line breaks', () => { const literal = 'a\nb\rc\\\nd\\\re'; // prettier-ignore expect(PDFString.of(literal).asBytes()).toEqual(Uint8Array.of( toCharCode('a'), toCharCode('\n'), toCharCode('b'), toCharCode('\r'), - toCharCode('c'), toCharCode('d'), + toCharCode('c'), toCharCode('d'), toCharCode('e'), )); }); - it(`can interpret invalid escapes`, () => { + it('can interpret invalid escapes', () => { const literal = 'a\nb\rc\\xd\\;'; // prettier-ignore @@ -114,61 +114,70 @@ describe(`PDFString`, () => { toCharCode('d'), toCharCode(';'), )); }); + + it('can interpret escaped backslashes', () => { + const literal = '\\\\\\\\'; + + // prettier-ignore + expect(PDFString.of(literal).asBytes()).toEqual(Uint8Array.of( + toCharCode('\\'), toCharCode('\\'), + )); + }); }); - describe(`decoding to string`, () => { - it(`can interpret UTF-16BE strings with escaped octal codes`, () => { + describe('decoding to string', () => { + it('can interpret UTF-16BE strings with escaped octal codes', () => { const literal = '\\376\\377\\000\\105\\000\\147\\000\\147\\000\\040\\330\\074\\337\\163'; expect(PDFString.of(literal).decodeText()).toBe('Egg 🍳'); }); - it(`can interpret UTF-16BE strings with ASCII symbols`, () => { + it('can interpret UTF-16BE strings with ASCII symbols', () => { const literal = '\\376\\377\0E\0g\0g\0 \\330<\\337s'; expect(PDFString.of(literal).decodeText()).toBe('Egg 🍳'); }); - it(`can interpret UTF-16BE strings with line breaks`, () => { + it('can interpret UTF-16BE strings with line breaks', () => { const literal = '\\376\\377\0E\\\n\\0g\0g\0 \\330<\\337s'; expect(PDFString.of(literal).decodeText()).toBe('Egg 🍳'); }); - it(`can interpret UTF-16LE strings with escaped octal codes`, () => { + it('can interpret UTF-16LE strings with escaped octal codes', () => { const literal = '\\377\\376\\105\\000\\147\\000\\147\\000\\040\\000\\074\\330\\163\\337'; expect(PDFString.of(literal).decodeText()).toBe('Egg 🍳'); }); - it(`can interpret PDFDocEncoded strings`, () => { + it('can interpret PDFDocEncoded strings', () => { const literal = 'a\\105b\\163\\0b6'; expect(PDFString.of(literal).decodeText()).toBe('aEbs\0b6'); }); - it(`can interpret PDFDocEncoded strings with EOLs and line breaks`, () => { + it('can interpret PDFDocEncoded strings with EOLs and line breaks', () => { const literal = 'a\nb\rc\\\nd\\\re'; expect(PDFString.of(literal).decodeText()).toBe('a\nb\rcde'); }); - it(`can interpret PDFDocEncoded strings with ignored escapes`, () => { + it('can interpret PDFDocEncoded strings with ignored escapes', () => { const literal = 'a\nb\rc\\xd\\;'; expect(PDFString.of(literal).decodeText()).toBe('a\nb\rcxd;'); }); }); - describe(`decoding to date`, () => { - it(`can interpret date strings of the form D:YYYYMMDDHHmmSSOHH'mm`, () => { - expect(PDFString.of(`D:20200321165011+01'01`).decodeDate()).toStrictEqual( + describe('decoding to date', () => { + it("can interpret date strings of the form D:YYYYMMDDHHmmSSOHH'mm", () => { + expect(PDFString.of("D:20200321165011+01'01").decodeDate()).toStrictEqual( new Date('2020-03-21T15:49:11Z'), ); - expect(PDFString.of(`D:20200321165011-01'01`).decodeDate()).toStrictEqual( + expect(PDFString.of("D:20200321165011-01'01").decodeDate()).toStrictEqual( new Date('2020-03-21T17:51:11Z'), ); - expect(PDFString.of(`D:20200321165011Z00'00`).decodeDate()).toStrictEqual( + expect(PDFString.of("D:20200321165011Z00'00").decodeDate()).toStrictEqual( new Date('2020-03-21T16:50:11Z'), ); }); - it(`can interpret date strings of the form D:YYYYMMDDHHmmSSOHH`, () => { + it('can interpret date strings of the form D:YYYYMMDDHHmmSSOHH', () => { expect(PDFString.of('D:20200321165011+01').decodeDate()).toStrictEqual( new Date('2020-03-21T15:50:11Z'), ); @@ -180,56 +189,56 @@ describe(`PDFString`, () => { ); }); - it(`can interpret date strings of the form D:YYYYMMDDHHmmSSO`, () => { + it('can interpret date strings of the form D:YYYYMMDDHHmmSSO', () => { expect(PDFString.of('D:20200321165011Z').decodeDate()).toStrictEqual( new Date('2020-03-21T16:50:11Z'), ); }); - it(`can interpret date strings of the form D:YYYYMMDDHHmmSS`, () => { + it('can interpret date strings of the form D:YYYYMMDDHHmmSS', () => { expect(PDFString.of('D:20200321165011').decodeDate()).toStrictEqual( new Date('2020-03-21T16:50:11Z'), ); }); - it(`can interpret date strings of the form D:YYYYMMDDHHmm`, () => { + it('can interpret date strings of the form D:YYYYMMDDHHmm', () => { expect(PDFString.of('D:202003211650').decodeDate()).toStrictEqual( new Date('2020-03-21T16:50:00Z'), ); }); - it(`can interpret date strings of the form D:YYYYMMDDHH`, () => { + it('can interpret date strings of the form D:YYYYMMDDHH', () => { expect(PDFString.of('D:2020032116').decodeDate()).toStrictEqual( new Date('2020-03-21T16:00:00Z'), ); }); - it(`can interpret date strings of the form D:YYYYMMDD`, () => { + it('can interpret date strings of the form D:YYYYMMDD', () => { expect(PDFString.of('D:20200321').decodeDate()).toStrictEqual( new Date('2020-03-21T00:00:00Z'), ); }); - it(`can interpret date strings of the form D:YYYYMM`, () => { + it('can interpret date strings of the form D:YYYYMM', () => { expect(PDFString.of('D:202003').decodeDate()).toStrictEqual( new Date('2020-03-01T00:00:00Z'), ); }); - it(`can interpret date strings of the form D:YYYY`, () => { + it('can interpret date strings of the form D:YYYY', () => { expect(PDFString.of('D:2020').decodeDate()).toStrictEqual( new Date('2020-01-01T00:00:00Z'), ); }); }); - it(`can provide its size in bytes`, () => { + it('can provide its size in bytes', () => { expect(PDFString.of('foobar').sizeInBytes()).toBe(8); expect(PDFString.of(' (foo(bar))').sizeInBytes()).toBe(13); expect(PDFString.of(')b\\a/z(').sizeInBytes()).toBe(9); }); - it(`can be serialized`, () => { + it('can be serialized', () => { const buffer = new Uint8Array(20).fill(toCharCode(' ')); expect(PDFString.of(')(b\\a/))z(').copyBytesInto(buffer, 3)).toBe(12); expect(buffer).toEqual(typedArrayFor(' ()(b\\a/))z() ')); diff --git a/tests/core/operators/PDFOperator.spec.ts b/tests/core/operators/PDFOperator.spec.ts index 8eda7bf69..66232165e 100644 --- a/tests/core/operators/PDFOperator.spec.ts +++ b/tests/core/operators/PDFOperator.spec.ts @@ -5,26 +5,26 @@ import { PDFString, toCharCode, typedArrayFor, -} from 'src/index'; +} from '../../../src/index'; -describe(`PDFOperator`, () => { - it(`can be constructed with args`, () => { +describe('PDFOperator', () => { + it('can be constructed with args', () => { const str = PDFString.of('FooBar'); expect(PDFOperator.of(Ops.ShowText, [str])).toBeInstanceOf(PDFOperator); }); - it(`can be constructed without args`, () => { + it('can be constructed without args', () => { expect(PDFOperator.of(Ops.BeginText)).toBeInstanceOf(PDFOperator); }); - it(`can be cloned without args`, () => { + it('can be cloned without args', () => { const original = PDFOperator.of(Ops.ClipNonZero); const clone = original.clone(); expect(clone).not.toBe(original); expect(String(clone)).toBe(String(original)); }); - it(`can be cloned with args`, () => { + it('can be cloned with args', () => { const original = PDFOperator.of(Ops.MoveText, [ PDFNumber.of(25), PDFNumber.of(50), @@ -34,11 +34,11 @@ describe(`PDFOperator`, () => { expect(String(clone)).toBe(String(original)); }); - it(`can be converted to a string without args`, () => { + it('can be converted to a string without args', () => { expect(String(PDFOperator.of(Ops.ClosePath))).toBe('h'); }); - it(`can be converted to a string with args`, () => { + it('can be converted to a string with args', () => { const op = PDFOperator.of(Ops.MoveText, [ PDFNumber.of(25.43), PDFNumber.of(-50), @@ -46,11 +46,11 @@ describe(`PDFOperator`, () => { expect(String(op)).toBe('25.43 -50 Td'); }); - it(`can provide its size in bytes without args`, () => { + it('can provide its size in bytes without args', () => { expect(PDFOperator.of(Ops.ClosePath).sizeInBytes()).toBe(1); }); - it(`can provide its size in bytes with args`, () => { + it('can provide its size in bytes with args', () => { const op = PDFOperator.of(Ops.MoveText, [ PDFNumber.of(25.43), PDFNumber.of(-50), @@ -58,14 +58,14 @@ describe(`PDFOperator`, () => { expect(op.sizeInBytes()).toBe(12); }); - it(`can be serialized without args`, () => { + it('can be serialized without args', () => { const op = PDFOperator.of(Ops.ClosePath); const buffer = new Uint8Array(op.sizeInBytes() + 3).fill(toCharCode(' ')); expect(op.copyBytesInto(buffer, 2)).toBe(1); expect(buffer).toEqual(typedArrayFor(' h ')); }); - it(`can be serialized with args`, () => { + it('can be serialized with args', () => { const op = PDFOperator.of(Ops.MoveText, [ PDFNumber.of(25.43), PDFNumber.of(-50), diff --git a/tests/core/parser/PDFObjectParser.spec.ts b/tests/core/parser/PDFObjectParser.spec.ts index 576dfe14a..4e49fa236 100644 --- a/tests/core/parser/PDFObjectParser.spec.ts +++ b/tests/core/parser/PDFObjectParser.spec.ts @@ -1,4 +1,4 @@ -import PDFPageLeaf from 'src/core/structures/PDFPageLeaf'; +import PDFPageLeaf from '../../../src/core/structures/PDFPageLeaf'; import { mergeIntoTypedArray, PDFArray, @@ -17,7 +17,7 @@ import { PDFString, typedArrayFor, numberToString, -} from 'src/index'; +} from '../../../src/index'; type ParseOptions = { capNumbers?: boolean }; @@ -37,7 +37,7 @@ const expectParse = (value: string | Uint8Array, options?: ParseOptions) => const expectParseStr = (value: string | Uint8Array, options?: ParseOptions) => expect(String(parse(value, options))); -describe(`PDFObjectParser`, () => { +describe('PDFObjectParser', () => { const origConsoleWarn = console.warn; beforeAll(() => { @@ -58,43 +58,43 @@ describe(`PDFObjectParser`, () => { console.warn = origConsoleWarn; }); - it(`throws an error when given empty input`, () => { + it('throws an error when given empty input', () => { expect(() => parse('')).toThrow(); }); - it(`throws an error for invalid input`, () => { + it('throws an error for invalid input', () => { expect(() => parse('I_AM_INVAL')).toThrow(); }); - describe(`when parsing true booleans`, () => { - it(`handles just the 'true' keyword`, () => { + describe('when parsing true booleans', () => { + it("handles just the 'true' keyword", () => { expectParse('true').toBe(PDFBool.True); }); - it(`handles whitespace before and after the 'true' keyword`, () => { + it("handles whitespace before and after the 'true' keyword", () => { expectParse('\0\t\n\f\r true\0\t\n\f\r ').toBe(PDFBool.True); }); - it(`handles comments before and after the 'true' keyword`, () => { + it("handles comments before and after the 'true' keyword", () => { expectParse('% Lulz wut?\ntrue% Lulz wut?\n').toBe(PDFBool.True); }); }); - describe(`when parsing false booleans`, () => { - it(`handles just the 'false' keyword`, () => { + describe('when parsing false booleans', () => { + it("handles just the 'false' keyword", () => { expectParse('false').toBe(PDFBool.False); }); - it(`handles whitespace before and after the 'false' keyword`, () => { + it("handles whitespace before and after the 'false' keyword", () => { expectParse('\0\t\n\f\r false\0\t\n\f\r ').toBe(PDFBool.False); }); - it(`handles comments before and after the 'false' keyword`, () => { + it("handles comments before and after the 'false' keyword", () => { expectParse('% Lulz wut?\nfalse% Lulz wut?\n').toBe(PDFBool.False); }); }); - describe(`when parsing numbers`, () => { + describe('when parsing numbers', () => { [ ['123', '123'], ['43445', '43445'], @@ -114,17 +114,17 @@ describe(`PDFObjectParser`, () => { }); }); - it(`handles whitespace before and after the number`, () => { + it('handles whitespace before and after the number', () => { expectParse('\0\t\n\f\r -.5\0\t\n\f\r ').toBeInstanceOf(PDFNumber); expectParseStr('\0\t\n\f\r -.5\0\t\n\f\r ').toBe('-0.5'); }); - it(`handles comments before and after the number`, () => { + it('handles comments before and after the number', () => { expectParse('% Lulz wut?\n-.5% Lulz wut?\n').toBeInstanceOf(PDFNumber); expectParseStr('% Lulz wut?\n-.5% Lulz wut?\n').toBe('-0.5'); }); - it(`stops parsing the number when whitespace is encountered`, () => { + it('stops parsing the number when whitespace is encountered', () => { expectParseStr('12\0' + '3').toBe('12'); expectParseStr('12\t3').toBe('12'); expectParseStr('12\n3').toBe('12'); @@ -133,7 +133,7 @@ describe(`PDFObjectParser`, () => { expectParseStr('12 3').toBe('12'); }); - it(`stops parsing the number when a delimiter is encountered`, () => { + it('stops parsing the number when a delimiter is encountered', () => { expectParseStr('12(3').toBe('12'); expectParseStr('12)3').toBe('12'); expectParseStr('12<3').toBe('12'); @@ -146,7 +146,7 @@ describe(`PDFObjectParser`, () => { expectParseStr('12%3').toBe('12'); }); - it(`can parse several numbers mashed together`, () => { + it('can parse several numbers mashed together', () => { const input = typedArrayFor('0.01.123+2.1-3..1-2.-.1'); const context = PDFContext.create(); const parser = PDFObjectParser.forBytes(input, context); @@ -159,7 +159,7 @@ describe(`PDFObjectParser`, () => { expect(parser.parseObject().toString()).toBe('-0.1'); }); - it(`caps numbers at Number.MAX_SAFE_INTEGER when capNumbers=true`, () => { + it('caps numbers at Number.MAX_SAFE_INTEGER when capNumbers=true', () => { expectParseStr(numberToString(Number.MAX_SAFE_INTEGER - 1), { capNumbers: true, }).toBe('9007199254740990'); @@ -177,7 +177,7 @@ describe(`PDFObjectParser`, () => { }).toBe('9007199254740991'); }); - it(`does not cap numbers at Number.MAX_SAFE_INTEGER when capNumbers=false`, () => { + it('does not cap numbers at Number.MAX_SAFE_INTEGER when capNumbers=false', () => { expectParseStr(numberToString(Number.MAX_SAFE_INTEGER - 1)).toBe( '9007199254740990', ); @@ -196,7 +196,7 @@ describe(`PDFObjectParser`, () => { }); }); - describe(`when parsing literal strings`, () => { + describe('when parsing literal strings', () => { [ ['(This is a string)'], ['(Strings may contain newlines\nand such.)'], @@ -213,19 +213,19 @@ describe(`PDFObjectParser`, () => { }); }); - it(`handles whitespace before and after the string`, () => { + it('handles whitespace before and after the string', () => { expectParse('\0\t\n\f\r (testing)\0\t\n\f\r ').toBeInstanceOf(PDFString); expectParseStr('\0\t\n\f\r (testing)\0\t\n\f\r ').toBe('(testing)'); }); - it(`handles comments before and after the string`, () => { + it('handles comments before and after the string', () => { expectParse('% Lulz wut?\n(testing)% Lulz wut?\n').toBeInstanceOf( PDFString, ); expectParseStr('% Lulz wut?\n(testing)% Lulz wut?\n').toBe('(testing)'); }); - it(`does not stop parsing the string when whitespace is encountered`, () => { + it('does not stop parsing the string when whitespace is encountered', () => { expectParseStr('(foo\0bar)').toBe('(foo\0bar)'); expectParseStr('(foo\tbar)').toBe('(foo\tbar)'); expectParseStr('(foo\nbar)').toBe('(foo\nbar)'); @@ -234,7 +234,7 @@ describe(`PDFObjectParser`, () => { expectParseStr('(foo bar)').toBe('(foo bar)'); }); - it(`does not stop parsing the string when a delimiter is encountered`, () => { + it('does not stop parsing the string when a delimiter is encountered', () => { expectParseStr('(foobar)').toBe('(foo>bar)'); expectParseStr('(foo[bar)').toBe('(foo[bar)'); @@ -245,27 +245,27 @@ describe(`PDFObjectParser`, () => { expectParseStr('(foo%bar)').toBe('(foo%bar)'); }); - it(`handles comments embedded within the string`, () => { + it('handles comments embedded within the string', () => { expectParse('(stuff% and things\n)').toBeInstanceOf(PDFString); expectParseStr('(stuff% and things\n)').toBe('(stuff% and things\n)'); }); - it(`handles nested parenthesis`, () => { + it('handles nested parenthesis', () => { expectParse('(FOO(BAR(QUX)(BAZ)))').toBeInstanceOf(PDFString); expectParseStr('(FOO(BAR(QUX)(BAZ)))').toBe('(FOO(BAR(QUX)(BAZ)))'); }); - it(`respects escaped parenthesis`, () => { + it('respects escaped parenthesis', () => { expectParse('(FOO\\(BAR)').toBeInstanceOf(PDFString); expectParseStr('(FOO\\(BAR)').toBe('(FOO\\(BAR)'); }); - it(`respects escaped backslashes`, () => { + it('respects escaped backslashes', () => { expect(() => parse('(FOO\\\\(BAR)')).toThrow(); }); }); - describe(`when parsing hex strings`, () => { + describe('when parsing hex strings', () => { [ ['<4E6F762073686D6F7A206B6120706F702E>'], ['<901FA3>'], @@ -278,21 +278,21 @@ describe(`PDFObjectParser`, () => { }); }); - it(`handles whitespace before and after the hex string`, () => { + it('handles whitespace before and after the hex string', () => { expectParse('\0\t\n\f\r \0\t\n\f\r ').toBeInstanceOf( PDFHexString, ); expectParseStr('\0\t\n\f\r \0\t\n\f\r ').toBe(''); }); - it(`handles comments before and after the hex string`, () => { + it('handles comments before and after the hex string', () => { expectParse('% Lulz wut?\n% Lulz wut?\n').toBeInstanceOf( PDFHexString, ); expectParseStr('% Lulz wut?\n% Lulz wut?\n').toBe(''); }); - it(`does not stop parsing the hex string when whitespace is encountered`, () => { + it('does not stop parsing the hex string when whitespace is encountered', () => { expectParseStr('').toBe(''); expectParseStr('').toBe(''); expectParseStr('').toBe(''); @@ -302,7 +302,7 @@ describe(`PDFObjectParser`, () => { }); }); - describe(`when parsing names`, () => { + describe('when parsing names', () => { [ ['/Name1', 'Name1'], ['/ASomewhatLongerName', 'ASomewhatLongerName'], @@ -324,19 +324,19 @@ describe(`PDFObjectParser`, () => { }); }); - it(`handles names consisting of a single '/'`, () => { + it("handles names consisting of a single '/'", () => { expectParse('/').toBe(PDFName.of('')); }); - it(`handles whitespace before and after the name`, () => { + it('handles whitespace before and after the name', () => { expectParse('\0\t\n\f\r /Foo\0\t\n\f\r ').toBe(PDFName.of('Foo')); }); - it(`handles comments before and after the name`, () => { + it('handles comments before and after the name', () => { expectParse('% Lulz wut?\n/Foo% Lulz wut?\n').toBe(PDFName.of('Foo')); }); - it(`stops parsing the name when whitespace is encountered`, () => { + it('stops parsing the name when whitespace is encountered', () => { expectParse('/Foo\0Bar').toBe(PDFName.of('Foo')); expectParse('/Foo\tBar').toBe(PDFName.of('Foo')); expectParse('/Foo\nBar').toBe(PDFName.of('Foo')); @@ -345,7 +345,7 @@ describe(`PDFObjectParser`, () => { expectParse('/Foo Bar').toBe(PDFName.of('Foo')); }); - it(`stops parsing the name when a delimiter is encountered`, () => { + it('stops parsing the name when a delimiter is encountered', () => { expectParse('/Foo(Bar').toBe(PDFName.of('Foo')); expectParse('/Foo)Bar').toBe(PDFName.of('Foo')); expectParse('/Foo { expectParse('/Foo%Bar').toBe(PDFName.of('Foo')); }); - it(`can parse several names mashed together`, () => { + it('can parse several names mashed together', () => { const input = typedArrayFor('/Foo/Bar/Qux//Baz/Bing/Bang'); const context = PDFContext.create(); const parser = PDFObjectParser.forBytes(input, context); @@ -371,23 +371,23 @@ describe(`PDFObjectParser`, () => { expect(parser.parseObject()).toBe(PDFName.of('Bang')); }); - it(`handles names containing non-ASCII characters`, () => { + it('handles names containing non-ASCII characters', () => { expectParse('/ABCDEE+»ªÎÄÖÐËÎ').toBe(PDFName.of('ABCDEE+»ªÎÄÖÐËÎ')); }); }); - describe(`when parsing arrays`, () => { - it(`handles empty arrays`, () => { + describe('when parsing arrays', () => { + it('handles empty arrays', () => { expectParse('[]').toBeInstanceOf(PDFArray); expectParseStr('[]').toBe('[ ]'); }); - it(`handles empty arrays with whitespace between braces`, () => { + it('handles empty arrays with whitespace between braces', () => { expectParse('[\0\t\n\f\r ]').toBeInstanceOf(PDFArray); expectParseStr('[\0\t\n\f\r ]').toBe('[ ]'); }); - it(`handles arrays of all value types seperated by whitespace and (multiple) comments`, () => { + it('handles arrays of all value types seperated by whitespace and (multiple) comments', () => { const input = `% Comment \0\t\n\f\r % Comment [ @@ -428,7 +428,7 @@ describe(`PDFObjectParser`, () => { expect(array.get(8)).toBe(PDFNull); }); - it(`handles arrays with no whitespace or comments`, () => { + it('handles arrays with no whitespace or comments', () => { expectParse('[true/FooBar[]<>21.null]').toBeInstanceOf( PDFArray, ); @@ -437,31 +437,31 @@ describe(`PDFObjectParser`, () => { ); }); - it(`throws an error when closing delimiter is missing`, () => { + it('throws an error when closing delimiter is missing', () => { expect(() => parse('[/Foo')).toThrow(); }); - it(`throws an error for mismatches delimiters`, () => { + it('throws an error for mismatches delimiters', () => { expect(() => parse('[[]')).toThrow(); }); - it(`throws an error when an invalid element is detected`, () => { + it('throws an error when an invalid element is detected', () => { expect(() => parse('[/Foo I_AM_INVALID]')).toThrow(); }); }); - describe(`when parsing dictionaries`, () => { - it(`handles empty dictionaries`, () => { + describe('when parsing dictionaries', () => { + it('handles empty dictionaries', () => { expectParse('<<>>').toBeInstanceOf(PDFDict); expectParseStr('<<>>').toBe('<<\n>>'); }); - it(`handles empty dictionaries with whitespace between brackets`, () => { + it('handles empty dictionaries with whitespace between brackets', () => { expectParse('<<\0\t\n\f\r >>').toBeInstanceOf(PDFDict); expectParseStr('<<\0\t\n\f\r >>').toBe('<<\n>>'); }); - it(`handles dictionaries of all value types seperated by whitespace and (multiplecomments`, () => { + it('handles dictionaries of all value types seperated by whitespace and (multiplecomments', () => { const input = `% Comment \0\t\n\f\r % Comment << @@ -521,7 +521,7 @@ describe(`PDFObjectParser`, () => { expect(dict.get(PDFName.of('PDFNull'))).toBe(undefined); }); - it(`handles dictionaries with no whitespace or comments`, () => { + it('handles dictionaries with no whitespace or comments', () => { expectParse( '<>/Baz 21./Bing null>>', ).toBeInstanceOf(PDFDict); @@ -530,31 +530,31 @@ describe(`PDFObjectParser`, () => { ); }); - it(`returns the correct subclass based on the dictionary's 'Type'`, () => { + it("returns the correct subclass based on the dictionary's 'Type'", () => { expectParse('<< >>').toBeInstanceOf(PDFDict); expectParse('<< /Type /Catalog >>').toBeInstanceOf(PDFCatalog); expectParse('<< /Type /Pages >>').toBeInstanceOf(PDFPageTree); expectParse('<< /Type /Page >>').toBeInstanceOf(PDFPageLeaf); }); - it(`throws an error when closing delimiter is missing`, () => { + it('throws an error when closing delimiter is missing', () => { expect(() => parse('< { + it('throws an error for mismatched delimiters', () => { expect(() => parse('<<>')).toThrow(); }); - it(`throws an error when an invalid key is detected`, () => { + it('throws an error when an invalid key is detected', () => { expect(() => parse('<>')).toThrow(); }); - it(`throws an error when an invalid value is detected`, () => { + it('throws an error when an invalid value is detected', () => { expect(() => parse('<>')).toThrow(); }); }); - describe(`when parsing streams`, () => { + describe('when parsing streams', () => { [ [ '<< >>\nstream\nstream foobar endstream\nendstream', @@ -590,44 +590,44 @@ describe(`PDFObjectParser`, () => { // Note that the ' \r\n' sequence following the 'stream' keyword is // technically invalid (per the specification). But some PDFs have it, so // we will support it anyways. - it(`handles streams with a space, carriage return, and a newline following the 'stream' keyword`, () => { - expectParse(`<<>>\r\nstream \r\n Stuff and Things \nendstream`); - expectParseStr(`<<>>\r\nstream \r\n Stuff and Things \nendstream`).toBe( + it("handles streams with a space, carriage return, and a newline following the 'stream' keyword", () => { + expectParse('<<>>\r\nstream \r\n Stuff and Things \nendstream'); + expectParseStr('<<>>\r\nstream \r\n Stuff and Things \nendstream').toBe( '<<\n/Length 18\n>>\nstream\n Stuff and Things \nendstream', ); }); - it(`handles streams with a carriage return and a newline following the 'stream' keyword`, () => { - expectParse(`<<>>\r\nstream\r\n Stuff and Things \nendstream`); - expectParseStr(`<<>>\r\nstream\r\n Stuff and Things \nendstream`).toBe( + it("handles streams with a carriage return and a newline following the 'stream' keyword", () => { + expectParse('<<>>\r\nstream\r\n Stuff and Things \nendstream'); + expectParseStr('<<>>\r\nstream\r\n Stuff and Things \nendstream').toBe( '<<\n/Length 18\n>>\nstream\n Stuff and Things \nendstream', ); }); - it(`handles streams with only a carriage return following the 'stream' keyword`, () => { - expectParse(`<<>>\rstream\r Stuff and Things \nendstream`); - expectParseStr(`<<>>\nstream\n Stuff and Things \nendstream`).toBe( + it("handles streams with only a carriage return following the 'stream' keyword", () => { + expectParse('<<>>\rstream\r Stuff and Things \nendstream'); + expectParseStr('<<>>\nstream\n Stuff and Things \nendstream').toBe( '<<\n/Length 18\n>>\nstream\n Stuff and Things \nendstream', ); }); - it(`handles streams with a carriage return preceding the 'endstream' keyword`, () => { - expectParse(`<<>>\r\nstream\r\n Stuff and Things \rendstream`); - expectParseStr(`<<>>\r\nstream\r\n Stuff and Things \rendstream`).toBe( + it("handles streams with a carriage return preceding the 'endstream' keyword", () => { + expectParse('<<>>\r\nstream\r\n Stuff and Things \rendstream'); + expectParseStr('<<>>\r\nstream\r\n Stuff and Things \rendstream').toBe( '<<\n/Length 18\n>>\nstream\n Stuff and Things \nendstream', ); }); - it(`handles comments and whitespace preceding the 'stream' keyword`, () => { + it("handles comments and whitespace preceding the 'stream' keyword", () => { expectParse( - `<<>>\0\t\n\f\r % I am a comment\0\t\n\f\r stream\r\n Stuff and Things \nendstream`, + '<<>>\0\t\n\f\r % I am a comment\0\t\n\f\r stream\r\n Stuff and Things \nendstream', ); expectParseStr( - `<<>>\0\t\n\f\r % I am a comment\0\t\n\f\r stream\r\n Stuff and Things \nendstream`, + '<<>>\0\t\n\f\r % I am a comment\0\t\n\f\r stream\r\n Stuff and Things \nendstream', ).toBe('<<\n/Length 18\n>>\nstream\n Stuff and Things \nendstream'); }); - it(`handles binary stream content`, () => { + it('handles binary stream content', () => { const input = mergeIntoTypedArray( '<<>>stream', new Uint8Array([12, 492, 0, 129]), @@ -648,38 +648,38 @@ describe(`PDFObjectParser`, () => { }); }); - describe(`when parsing null`, () => { - it(`handles just the 'null' keyword`, () => { + describe('when parsing null', () => { + it("handles just the 'null' keyword", () => { expectParse('null').toBe(PDFNull); }); - it(`handles whitespace before and after the 'null' keyword`, () => { + it("handles whitespace before and after the 'null' keyword", () => { expectParse('\0\t\n\f\r null\0\t\n\f\r ').toBe(PDFNull); }); - it(`handles comments before and after the 'null' keyword`, () => { + it("handles comments before and after the 'null' keyword", () => { expectParse('% Lulz wut?\nnull% Lulz wut?\n').toBe(PDFNull); }); }); - describe(`when parsing indirect object references`, () => { - it(`handles whitespace before and after the ref`, () => { + describe('when parsing indirect object references', () => { + it('handles whitespace before and after the ref', () => { expectParse('\0\t\n\f\r 1 2 R\0\t\n\f\r ').toBe(PDFRef.of(1, 2)); }); - it(`handles whitespace within the ref`, () => { + it('handles whitespace within the ref', () => { expectParse('1\0\t\n\f\r2\0\t\n\f\rR').toBe(PDFRef.of(1, 2)); }); - it(`handles comments before and after the ref`, () => { + it('handles comments before and after the ref', () => { expectParse('% Lulz wut?\n1 2 R% Lulz wut?\n').toBe(PDFRef.of(1, 2)); }); - it(`handles comments within the ref`, () => { + it('handles comments within the ref', () => { expectParse('1% Lulz wut?\r2% Lulz wut?\rR').toBe(PDFRef.of(1, 2)); }); - it(`does not stop parsing the ref when whitespace is encountered`, () => { + it('does not stop parsing the ref when whitespace is encountered', () => { expectParse('1\0' + '2\0R').toBe(PDFRef.of(1, 2)); expectParse('1\t2\tR').toBe(PDFRef.of(1, 2)); expectParse('1\n2\nR').toBe(PDFRef.of(1, 2)); @@ -688,7 +688,7 @@ describe(`PDFObjectParser`, () => { expectParse('1 2 R').toBe(PDFRef.of(1, 2)); }); - it(`stops parsing the ref when a delimiter is encountered`, () => { + it('stops parsing the ref when a delimiter is encountered', () => { expectParseStr('1 2(R').toBe('1'); expectParseStr('1 2)R').toBe('1'); expectParseStr('1 2 { expectParseStr('1 2%R').toBe('1'); }); - it(`can parse several refs mashed together`, () => { + it('can parse several refs mashed together', () => { const input = typedArrayFor('0 0R1 1R 2 2R'); const context = PDFContext.create(); const parser = PDFObjectParser.forBytes(input, context); @@ -710,7 +710,7 @@ describe(`PDFObjectParser`, () => { expect(parser.parseObject()).toBe(PDFRef.of(2, 2)); }); - it(`can parse a number, then a ref, then a number`, () => { + it('can parse a number, then a ref, then a number', () => { const input = typedArrayFor('0 21 0 R 42'); const context = PDFContext.create(); const parser = PDFObjectParser.forBytes(input, context); diff --git a/tests/core/parser/PDFObjectStreamParser.spec.ts b/tests/core/parser/PDFObjectStreamParser.spec.ts index d517df59f..0b601147c 100644 --- a/tests/core/parser/PDFObjectStreamParser.spec.ts +++ b/tests/core/parser/PDFObjectStreamParser.spec.ts @@ -13,13 +13,13 @@ import { PDFRef, PDFString, ReparseError, -} from 'src/index'; +} from '../../../src/index'; const readData = (file: string) => new Uint8Array(fs.readFileSync(`./tests/core/parser/data/${file}`)); -describe(`PDFObjectStreamParser`, () => { - it(`parses simple object streams`, () => { +describe('PDFObjectStreamParser', () => { + it('parses simple object streams', () => { const context = PDFContext.create(); const dict = context.obj({ N: 3, @@ -66,7 +66,7 @@ describe(`PDFObjectStreamParser`, () => { expect(context.lookup(PDFRef.of(9))).toBe(PDFNull); }); - it(`handles object streams with newlines separating the integer pairs`, () => { + it('handles object streams with newlines separating the integer pairs', () => { const context = PDFContext.create(); const dict = context.obj({ N: 182, @@ -80,7 +80,7 @@ describe(`PDFObjectStreamParser`, () => { expect(context.enumerateIndirectObjects().length).toBe(182); }); - it(`handles encoded object streams with PDFName filters`, () => { + it('handles encoded object streams with PDFName filters', () => { const context = PDFContext.create(); const dict = context.obj({ Filter: 'FlateDecode', @@ -95,7 +95,7 @@ describe(`PDFObjectStreamParser`, () => { expect(context.enumerateIndirectObjects().length).toBe(115); }); - it(`handles encoded object streams with PDFArray filters`, () => { + it('handles encoded object streams with PDFArray filters', () => { const context = PDFContext.create(); const dict = context.obj({ Filter: ['FlateDecode'], @@ -110,7 +110,7 @@ describe(`PDFObjectStreamParser`, () => { expect(context.enumerateIndirectObjects().length).toBe(115); }); - it(`throws an error for invalid Filters`, () => { + it('throws an error for invalid Filters', () => { const context = PDFContext.create(); const dict = context.obj({ Filter: 42, @@ -125,7 +125,7 @@ describe(`PDFObjectStreamParser`, () => { ).toThrow(); }); - it(`throws an error for invalid object streams`, async () => { + it('throws an error for invalid object streams', async () => { const context = PDFContext.create(); const dict = context.obj({ N: 1, @@ -139,7 +139,7 @@ describe(`PDFObjectStreamParser`, () => { ).rejects.toThrow(); }); - it(`prevents reparsing`, async () => { + it('prevents reparsing', async () => { const context = PDFContext.create(); const dict = context.obj({ N: 3, diff --git a/tests/core/parser/PDFParser.spec.ts b/tests/core/parser/PDFParser.spec.ts index ae631c6b3..33817225e 100644 --- a/tests/core/parser/PDFParser.spec.ts +++ b/tests/core/parser/PDFParser.spec.ts @@ -12,9 +12,9 @@ import { PDFString, ReparseError, typedArrayFor, -} from 'src/index'; +} from '../../../src/index'; -describe(`PDFParser`, () => { +describe('PDFParser', () => { const origConsoleWarn = console.warn; beforeAll(() => { @@ -37,7 +37,7 @@ describe(`PDFParser`, () => { console.warn = origConsoleWarn; }); - it(`throws an error when the PDF is missing a header`, async () => { + it('throws an error when the PDF is missing a header', async () => { const input = ` I_AM_NOT_A_HEADER 1 0 obj @@ -48,7 +48,7 @@ describe(`PDFParser`, () => { await expect(parser.parseDocument()).rejects.toThrow(); }); - it(`does not throw an error when the 'endobj' keyword is missing`, async () => { + it("does not throw an error when the 'endobj' keyword is missing", async () => { const input = ` %PDF-1.7 1 0 obj @@ -60,7 +60,7 @@ describe(`PDFParser`, () => { expect(context.lookup(PDFRef.of(1))).toBeInstanceOf(PDFString); }); - it(`handles invalid binary comments after header`, async () => { + it('handles invalid binary comments after header', async () => { const input = mergeIntoTypedArray( '%PDF-1.7\n', new Uint8Array([128, 1, 2, 3, 4, 5, 129, 130, 131, CharCodes.Newline]), @@ -73,7 +73,7 @@ describe(`PDFParser`, () => { expect(context.enumerateIndirectObjects().length).toBe(1); }); - it(`handles invalid binary comments with missing newline after header`, async () => { + it('handles invalid binary comments with missing newline after header', async () => { const input = mergeIntoTypedArray( '%PDF-1.7\n', new Uint8Array([142, 1, 2, 3, 4, 5, 129, 130, 131]), @@ -86,7 +86,7 @@ describe(`PDFParser`, () => { expect(context.enumerateIndirectObjects().length).toBe(1); }); - it(`does not stall when stuff follows the last %%EOL`, async () => { + it('does not stall when stuff follows the last %%EOL', async () => { const input = ` %PDF-1.7 1 0 obj @@ -102,7 +102,7 @@ describe(`PDFParser`, () => { expect(context.enumerateIndirectObjects().length).toBe(1); }); - it(`handles invalid indirect objects`, async () => { + it('handles invalid indirect objects', async () => { const input = ` %PDF-1.7 22 0 obj <> endobj @@ -115,7 +115,7 @@ describe(`PDFParser`, () => { expect(object).toBeInstanceOf(PDFInvalidObject); }); - it(`throws an error with invalid indirect objects when throwOnInvalidObject=true`, async () => { + it('throws an error with invalid indirect objects when throwOnInvalidObject=true', async () => { const input = ` %PDF-1.7 22 0 obj <> endobj @@ -128,7 +128,7 @@ describe(`PDFParser`, () => { await expect(parser.parseDocument()).rejects.toBeInstanceOf(Error); }); - it(`handles xref sections with empty subsections`, async () => { + it('handles xref sections with empty subsections', async () => { const input = ` %PDF-1.7 22 0 obj @@ -150,7 +150,7 @@ describe(`PDFParser`, () => { expect(object).toBeInstanceOf(PDFString); }); - it(`can parse PDF files with comments and stuff preceding the header`, async () => { + it('can parse PDF files with comments and stuff preceding the header', async () => { const pdfBytes = fs.readFileSync( './assets/pdfs/pdf20examples/PDF 2.0 with offset start.pdf', ); @@ -163,7 +163,7 @@ describe(`PDFParser`, () => { expect(context.enumerateIndirectObjects().length).toBe(8); }); - it(`can parse PDF files with comments stuff following the header`, async () => { + it('can parse PDF files with comments stuff following the header', async () => { const pdfBytes = fs.readFileSync( './assets/pdfs/stuff_following_header.pdf', ); @@ -176,7 +176,7 @@ describe(`PDFParser`, () => { expect(context.enumerateIndirectObjects().length).toBe(12); }); - it(`can parse PDF files with missing xref table, trailer dict, and trailer`, async () => { + it('can parse PDF files with missing xref table, trailer dict, and trailer', async () => { const pdfBytes = fs.readFileSync( './assets/pdfs/missing_xref_trailer_dict.pdf', ); @@ -189,7 +189,7 @@ describe(`PDFParser`, () => { expect(context.enumerateIndirectObjects().length).toBe(8); }); - it(`can parse PDF files without object streams or update sections`, async () => { + it('can parse PDF files with invalid xref table', async () => { const pdfBytes = fs.readFileSync('./assets/pdfs/normal.pdf'); const parser = PDFParser.forBytesWithOptions(pdfBytes); @@ -200,7 +200,18 @@ describe(`PDFParser`, () => { expect(context.enumerateIndirectObjects().length).toBe(108); }); - it(`can parse PDF files with update sections`, async () => { + it('can parse PDF files without object streams or update sections', async () => { + const pdfBytes = fs.readFileSync('./assets/pdfs/normal.pdf'); + + const parser = PDFParser.forBytesWithOptions(pdfBytes); + const context = await parser.parseDocument(); + + expect(context.header).toBeInstanceOf(PDFHeader); + expect(context.header.toString()).toEqual('%PDF-1.3\n%'); + expect(context.enumerateIndirectObjects().length).toBe(108); + }); + + it('can parse PDF files with update sections', async () => { const pdfBytes = fs.readFileSync('./assets/pdfs/with_update_sections.pdf'); const parser = PDFParser.forBytesWithOptions(pdfBytes); @@ -208,10 +219,11 @@ describe(`PDFParser`, () => { expect(context.header).toBeInstanceOf(PDFHeader); expect(context.header.toString()).toEqual('%PDF-1.7\n%'); - expect(context.enumerateIndirectObjects().length).toBe(131); + // has lots of deleted objects... + expect(context.enumerateIndirectObjects().length).toBe(138); }); - it(`can parse PDF files with comments`, async () => { + it('can parse PDF files with comments', async () => { const pdfBytes = fs.readFileSync('./assets/pdfs/with_comments.pdf'); const parser = PDFParser.forBytesWithOptions(pdfBytes); @@ -219,10 +231,10 @@ describe(`PDFParser`, () => { expect(context.header).toBeInstanceOf(PDFHeader); expect(context.header.toString()).toEqual('%PDF-1.7\n%'); - expect(context.enumerateIndirectObjects().length).toBe(143); + expect(context.enumerateIndirectObjects().length).toBe(145); }); - it(`prevents double parsing`, async () => { + it('prevents double parsing', async () => { const pdfBytes = fs.readFileSync('./assets/pdfs/normal.pdf'); const parser = PDFParser.forBytesWithOptions(pdfBytes); @@ -233,7 +245,7 @@ describe(`PDFParser`, () => { ); }); - it(`can parse PDF files with binary jibberish between indirect objects`, async () => { + it('can parse PDF files with binary jibberish between indirect objects', async () => { const pdfBytes = fs.readFileSync('./assets/pdfs/giraffe.pdf'); const parser = PDFParser.forBytesWithOptions(pdfBytes); @@ -241,10 +253,10 @@ describe(`PDFParser`, () => { expect(context.header).toBeInstanceOf(PDFHeader); expect(context.header.toString()).toEqual('%PDF-1.6\n%'); - expect(context.enumerateIndirectObjects().length).toBe(17); + expect(context.enumerateIndirectObjects().length).toBe(22); }); - it(`can fix incorrect values for /Root`, async () => { + it('can fix incorrect values for /Root', async () => { const pdfBytes = fs.readFileSync('./assets/pdfs/invalid_root_ref.pdf'); const parser = PDFParser.forBytesWithOptions(pdfBytes); @@ -253,10 +265,11 @@ describe(`PDFParser`, () => { expect(context.header).toBeInstanceOf(PDFHeader); expect(context.header.toString()).toEqual('%PDF-1.5\n%'); expect(context.trailerInfo.Root).toBe(PDFRef.of(2, 0)); - expect(context.enumerateIndirectObjects().length).toBe(28); + // the pdf has many.. many errors, not sure if 29 is actually the right number.. + expect(context.enumerateIndirectObjects().length).toBe(29); }); - it(`can parse files containing indirect objects missing their 'endobj' keyword`, async () => { + it("can parse files containing indirect objects missing their 'endobj' keyword", async () => { const pdfBytes = fs.readFileSync( './assets/pdfs/missing_endobj_keyword.pdf', ); @@ -269,7 +282,7 @@ describe(`PDFParser`, () => { expect(context.enumerateIndirectObjects().length).toBe(7); }); - it(`can parse files with containing large arrays with most 'null' values`, async () => { + it("can parse files with containing large arrays with most 'null' values", async () => { const pdfBytes = fs.readFileSync('./assets/pdfs/bixby_guide.pdf'); const parser = PDFParser.forBytesWithOptions(pdfBytes); @@ -279,13 +292,14 @@ describe(`PDFParser`, () => { expect(context.header.toString()).toEqual('%PDF-1.4\n%'); const objects = context.enumerateIndirectObjects(); - expect(objects.length).toBe(26079); + // 1 less than Size + expect(objects.length).toBe(26237); expect( objects.filter(([_ref, obj]) => obj instanceof PDFPageLeaf).length, ).toBe(176); }); - it(`can parse files with invalid stream EOLs: "stream \r\n`, async () => { + it('can parse files with invalid stream EOLs: "stream \r\n', async () => { const pdfBytes = fs.readFileSync( './assets/pdfs/with_invalid_stream_EOL.pdf', ); @@ -303,7 +317,7 @@ describe(`PDFParser`, () => { ).toBe(2); }); - it(`handles updated PDFs missing newline after %%EOF marker`, async () => { + it('handles updated PDFs missing newline after %%EOF marker', async () => { const input = ` %PDF-1.7 22 0 obj @@ -336,7 +350,7 @@ describe(`PDFParser`, () => { expect(object28).toBeInstanceOf(PDFDict); }); - it(`handles updated PDFs with comments preceding %%EOF marker`, async () => { + it('handles updated PDFs with comments preceding %%EOF marker', async () => { const input = ` %PDF-1.7 22 0 obj @@ -370,7 +384,7 @@ describe(`PDFParser`, () => { expect(object28).toBeInstanceOf(PDFDict); }); - it(`removes indirect objects with objectNumber=0`, async () => { + it('removes indirect objects with objectNumber=0', async () => { const input = ` %PDF-1.7 1 0 obj @@ -395,4 +409,97 @@ describe(`PDFParser`, () => { const object2 = context.lookup(PDFRef.of(2)); expect(object2).toBeInstanceOf(PDFString); }); + + it('preserves pdfBytes when created for incremental update', async () => { + const pdfBytes = fs.readFileSync('./assets/pdfs/bixby_guide.pdf'); + + const parser = PDFParser.forBytesWithOptions( + pdfBytes, + undefined, + undefined, + undefined, + undefined, + undefined, + true, + ); + const context = await parser.parseDocument(); + + expect(context.pdfFileDetails.originalBytes).toBeDefined(); + expect(context.pdfFileDetails.originalBytes?.toString()).toEqual( + pdfBytes.toString(), + ); + }); + + describe('xref preservation and object versions', () => { + const pdfBytes = fs.readFileSync('./assets/pdfs/with_update_sections.pdf'); + + it('preserves the xref information of PDF files with update sections', async () => { + const parser = PDFParser.forBytesWithOptions(pdfBytes); + const context = await parser.parseDocument(); + + expect(context.header).toBeInstanceOf(PDFHeader); + expect(context.header.toString()).toEqual('%PDF-1.7\n%'); + expect(context.xrefs.length).toBe(5); + expect(context.listXrefEntries().length).toBe(5); + }); + + it('does not preserves objects versions by default', async () => { + const parser = PDFParser.forBytesWithOptions(pdfBytes); + const context = await parser.parseDocument(); + + expect(context.header).toBeInstanceOf(PDFHeader); + expect(context.header.toString()).toEqual('%PDF-1.7\n%'); + expect(context.xrefs.length).toBe(5); + expect(context.getObjectVersions(PDFRef.of(334)).length).toBe(0); + }); + + it('preserves objects versions if indicated on creation', async () => { + const parser = PDFParser.forBytesWithOptions( + pdfBytes, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + true, + ); + const context = await parser.parseDocument(); + + expect(context.header).toBeInstanceOf(PDFHeader); + expect(context.header.toString()).toEqual('%PDF-1.7\n%'); + expect(context.xrefs.length).toBe(5); + // there are 4 versions of object 308, but doesn't really changes + const v308obj = context.getObjectVersions(PDFRef.of(308)); + const last308 = context.lookup(PDFRef.of(308)); + expect(v308obj.length).toBe(3); + expect(v308obj[2].toString()).toEqual( + `<< +/Author (SE:W:CAR:MP) +/CreationDate (D:20140102050054-08'00') +/Creator (Adobe LiveCycle Designer ES 8.2) +/ModDate (D:20140102050152-08'00') +/Producer (Adobe Acrobat Pro 10.1.8) +/Subject (Payment Voucher) +>>`, + ); + expect(last308).toBeDefined(); + expect(last308?.toString()).toEqual( + `<< +/Author (SE:W:CAR:MP) +/CreationDate (D:20140102050054-08'00') +/Creator (Adobe LiveCycle Designer ES 8.2) +/ModDate (D:20140124112822-08'00') +/Producer (Adobe Acrobat Pro 10.1.8) +/Subject (Payment Voucher) +>>`, + ); + // three versions of object 291 (one in a stream) + const v291obj = context.getObjectVersions(PDFRef.of(291)); + const last291 = context.lookup(PDFRef.of(291)); + expect(v291obj.length).toBe(2); + expect(last291).toBeDefined(); + expect(last291?.toString()).not.toEqual(v291obj[0].toString()); + }); + }); }); diff --git a/tests/core/parser/PDFXRefStreamParser.spec.ts b/tests/core/parser/PDFXRefStreamParser.spec.ts index 9dd069f16..9ae86b124 100644 --- a/tests/core/parser/PDFXRefStreamParser.spec.ts +++ b/tests/core/parser/PDFXRefStreamParser.spec.ts @@ -4,13 +4,13 @@ import { PDFRawStream, PDFXRefStreamParser, ReparseError, -} from 'src/index'; +} from '../../../src/index'; const readData = (file: string) => new Uint8Array(fs.readFileSync(`./tests/core/parser/data/${file}`)); -describe(`PDFXRefStreamParser`, () => { - it(`can parse XRef streams (1)`, () => { +describe('PDFXRefStreamParser', () => { + it('can parse XRef streams (1)', () => { const context = PDFContext.create(); const dict = context.obj({ DecodeParms: { Columns: 4, Predictor: 12 }, @@ -35,7 +35,7 @@ describe(`PDFXRefStreamParser`, () => { expect(inObjectStream.length).toBe(67); }); - it(`can parse XRef streams (2)`, () => { + it('can parse XRef streams (2)', () => { const context = PDFContext.create(); const dict = context.obj({ DecodeParms: { Columns: 4, Predictor: 12 }, @@ -85,7 +85,7 @@ describe(`PDFXRefStreamParser`, () => { expect(inObjectStream.length).toBe(33); }); - it(`can parse XRef streams (3)`, () => { + it('can parse XRef streams (3)', () => { const context = PDFContext.create(); const dict = context.obj({ DecodeParms: { Columns: 3, Predictor: 12 }, @@ -111,7 +111,7 @@ describe(`PDFXRefStreamParser`, () => { expect(inObjectStream.length).toBe(2); }); - it(`can parse XRef streams (4)`, () => { + it('can parse XRef streams (4)', () => { const context = PDFContext.create(); const dict = context.obj({ Filter: 'FlateDecode', @@ -165,7 +165,7 @@ describe(`PDFXRefStreamParser`, () => { // expect(context.lookup(barRef)).not.toBeUndefined(); // }); - it(`prevents reparsing`, () => { + it('prevents reparsing', () => { const context = PDFContext.create(); const dict = context.obj({ Filter: 'FlateDecode', diff --git a/tests/core/streams/Ascii85Stream.spec.ts b/tests/core/streams/Ascii85Stream.spec.ts index c416853fe..ac55c3128 100644 --- a/tests/core/streams/Ascii85Stream.spec.ts +++ b/tests/core/streams/Ascii85Stream.spec.ts @@ -1,12 +1,12 @@ import fs from 'fs'; -import Ascii85Stream from 'src/core/streams/Ascii85Stream'; -import Stream from 'src/core/streams/Stream'; +import Ascii85Stream from '../../../src/core/streams/Ascii85Stream'; +import Stream from '../../../src/core/streams/Stream'; -const DIR = `tests/core/streams/data/ascii85`; +const DIR = 'tests/core/streams/data/ascii85'; const FILES = ['1']; -describe(`Ascii85Stream`, () => { +describe('Ascii85Stream', () => { FILES.forEach((file) => { it(`can decode ascii 85 encoded data (${file})`, () => { const encoded = new Uint8Array(fs.readFileSync(`${DIR}/${file}.encoded`)); diff --git a/tests/core/streams/AsciiHexStream.spec.ts b/tests/core/streams/AsciiHexStream.spec.ts index c1999adbf..482524487 100644 --- a/tests/core/streams/AsciiHexStream.spec.ts +++ b/tests/core/streams/AsciiHexStream.spec.ts @@ -1,12 +1,12 @@ import fs from 'fs'; -import AsciiHexStream from 'src/core/streams/AsciiHexStream'; -import Stream from 'src/core/streams/Stream'; +import AsciiHexStream from '../../../src/core/streams/AsciiHexStream'; +import Stream from '../../../src/core/streams/Stream'; -const DIR = `tests/core/streams/data/asciihex`; +const DIR = 'tests/core/streams/data/asciihex'; const FILES = ['1', '2']; -describe(`AsciiHexStream`, () => { +describe('AsciiHexStream', () => { FILES.forEach((file) => { it(`can decode ascii hex encoded data (${file})`, () => { const encoded = new Uint8Array(fs.readFileSync(`${DIR}/${file}.encoded`)); diff --git a/tests/core/streams/FlateStream.spec.ts b/tests/core/streams/FlateStream.spec.ts index 87e4aa3f9..1daf4421f 100644 --- a/tests/core/streams/FlateStream.spec.ts +++ b/tests/core/streams/FlateStream.spec.ts @@ -1,12 +1,12 @@ import fs from 'fs'; -import FlateStream from 'src/core/streams/FlateStream'; -import Stream from 'src/core/streams/Stream'; +import FlateStream from '../../../src/core/streams/FlateStream'; +import Stream from '../../../src/core/streams/Stream'; -const DIR = `tests/core/streams/data/flate`; +const DIR = 'tests/core/streams/data/flate'; const FILES = ['1', '2', '3', '4', '5', '6', '7']; -describe(`FlateStream`, () => { +describe('FlateStream', () => { FILES.forEach((file) => { it(`can decode flate encoded data (${file})`, () => { const encoded = new Uint8Array(fs.readFileSync(`${DIR}/${file}.encoded`)); diff --git a/tests/core/streams/LZWStream.spec.ts b/tests/core/streams/LZWStream.spec.ts index 268ca4f59..5ac2ea9a7 100644 --- a/tests/core/streams/LZWStream.spec.ts +++ b/tests/core/streams/LZWStream.spec.ts @@ -1,12 +1,12 @@ import fs from 'fs'; -import LZWStream from 'src/core/streams/LZWStream'; -import Stream from 'src/core/streams/Stream'; +import LZWStream from '../../../src/core/streams/LZWStream'; +import Stream from '../../../src/core/streams/Stream'; -const DIR = `tests/core/streams/data/lzw`; +const DIR = 'tests/core/streams/data/lzw'; const FILES = ['1', '2', '3', '4']; -describe(`LZWStream`, () => { +describe('LZWStream', () => { FILES.forEach((file) => { it(`can decode LZW encoded data (${file})`, () => { const encoded = new Uint8Array(fs.readFileSync(`${DIR}/${file}.encoded`)); diff --git a/tests/core/streams/RunLengthStream.spec.ts b/tests/core/streams/RunLengthStream.spec.ts index 92646f522..f9e120c6f 100644 --- a/tests/core/streams/RunLengthStream.spec.ts +++ b/tests/core/streams/RunLengthStream.spec.ts @@ -1,12 +1,12 @@ import fs from 'fs'; -import RunLengthStream from 'src/core/streams/RunLengthStream'; -import Stream from 'src/core/streams/Stream'; +import RunLengthStream from '../../../src/core/streams/RunLengthStream'; +import Stream from '../../../src/core/streams/Stream'; -const DIR = `tests/core/streams/data/runlength`; +const DIR = 'tests/core/streams/data/runlength'; const FILES = ['1', '2', '3', '4', '5']; -describe(`RunLengthStream`, () => { +describe('RunLengthStream', () => { FILES.forEach((file) => { it(`can decode run length encoded data (${file})`, () => { const encoded = new Uint8Array(fs.readFileSync(`${DIR}/${file}.encoded`)); diff --git a/tests/core/streams/Stream.spec.ts b/tests/core/streams/Stream.spec.ts index 677827c4c..bf317ef11 100644 --- a/tests/core/streams/Stream.spec.ts +++ b/tests/core/streams/Stream.spec.ts @@ -1,6 +1,6 @@ -import Stream from 'src/core/streams/Stream'; +import Stream from '../../../src/core/streams/Stream'; -describe(`Stream`, () => { +describe('Stream', () => { it('can get the stream length', () => { const bytes = Uint8Array.from([1, 1, 2]); const stream = new Stream(bytes, 0, bytes.length); diff --git a/tests/core/structures/PDFCatalog.spec.ts b/tests/core/structures/PDFCatalog.spec.ts index 7a966cec5..3aa55f3f4 100644 --- a/tests/core/structures/PDFCatalog.spec.ts +++ b/tests/core/structures/PDFCatalog.spec.ts @@ -6,10 +6,10 @@ import { PDFPageLeaf, PDFPageTree, PDFRef, -} from 'src/index'; +} from '../../../src/index'; -describe(`PDFCatalog`, () => { - it(`can be constructed directly from a Map and PDFContext`, () => { +describe('PDFCatalog', () => { + it('can be constructed directly from a Map and PDFContext', () => { const context = PDFContext.create(); const dict = new Map(); const catalog = PDFCatalog.fromMapWithContext(dict, context); @@ -19,7 +19,7 @@ describe(`PDFCatalog`, () => { expect(catalog.get(PDFName.of('Pages'))).toBeUndefined(); }); - it(`is constructed with the correct Type and entries`, () => { + it('is constructed with the correct Type and entries', () => { const context = PDFContext.create(); const pagesRef = PDFRef.of(21); const catalog = PDFCatalog.withContextAndPages(context, pagesRef); @@ -29,7 +29,7 @@ describe(`PDFCatalog`, () => { expect(catalog.get(PDFName.of('Pages'))).toBe(pagesRef); }); - it(`returns its Pages entry value when it's a reference`, () => { + it("returns its Pages entry value when it's a reference", () => { const context = PDFContext.create(); const pages = PDFDict.withContext(context); const pagesRef = context.register(pages); @@ -38,7 +38,7 @@ describe(`PDFCatalog`, () => { expect(catalog.Pages()).toBe(pages); }); - it(`returns its Pages entry value when it's a direct object`, () => { + it("returns its Pages entry value when it's a direct object", () => { const context = PDFContext.create(); const pages = PDFPageTree.withContext(context); const catalog = PDFCatalog.withContextAndPages(context, pages); @@ -46,7 +46,7 @@ describe(`PDFCatalog`, () => { expect(catalog.Pages()).toBe(pages); }); - it(`can insert leaf nodes`, () => { + it('can insert leaf nodes', () => { const context = PDFContext.create(); const pageTree1 = PDFPageTree.withContext(context); @@ -78,7 +78,7 @@ describe(`PDFCatalog`, () => { expect(pageTree1.Kids().get(2)).toBe(newLeafRef); }); - it(`can remove leaf nodes`, () => { + it('can remove leaf nodes', () => { const context = PDFContext.create(); const pageTree1 = PDFPageTree.withContext(context); diff --git a/tests/core/structures/PDFContentStream.spec.ts b/tests/core/structures/PDFContentStream.spec.ts index 368f7daa0..fa6956dca 100644 --- a/tests/core/structures/PDFContentStream.spec.ts +++ b/tests/core/structures/PDFContentStream.spec.ts @@ -15,9 +15,9 @@ import { pushGraphicsState, toCharCode, typedArrayFor, -} from 'src/index'; +} from '../../../src/index'; -describe(`PDFContentStream`, () => { +describe('PDFContentStream', () => { const context = PDFContext.create(); const dict = PDFDict.withContext(context); const operators = [ @@ -28,13 +28,13 @@ describe(`PDFContentStream`, () => { PDFOperator.of(Ops.EndText), ]; - it(`can be constructed from PDFContentStream.of(...)`, () => { + it('can be constructed from PDFContentStream.of(...)', () => { expect(PDFContentStream.of(dict, operators, false)).toBeInstanceOf( PDFContentStream, ); }); - it(`allows operators to be pushed to the end of the stream`, () => { + it('allows operators to be pushed to the end of the stream', () => { const stream = PDFContentStream.of(dict, [pushGraphicsState()], false); stream.push(moveText(21, 99), popGraphicsState()); expect(String(stream)).toEqual( @@ -47,14 +47,14 @@ describe(`PDFContentStream`, () => { ); }); - it(`can be cloned`, () => { + it('can be cloned', () => { const original = PDFContentStream.of(dict, operators, false); const clone = original.clone(); expect(clone).not.toBe(original); expect(String(clone)).toBe(String(original)); }); - it(`can be converted to a string`, () => { + it('can be converted to a string', () => { expect(String(PDFContentStream.of(dict, operators, false))).toEqual( '<<\n/Length 55\n>>\n' + 'stream\n' + @@ -67,11 +67,11 @@ describe(`PDFContentStream`, () => { ); }); - it(`can provide its size in bytes`, () => { + it('can provide its size in bytes', () => { expect(PDFContentStream.of(dict, operators, false).sizeInBytes()).toBe(89); }); - it(`can be serialized`, () => { + it('can be serialized', () => { const stream = PDFContentStream.of(dict, operators, false); const buffer = new Uint8Array(stream.sizeInBytes() + 3).fill( toCharCode(' '), @@ -91,7 +91,7 @@ describe(`PDFContentStream`, () => { ); }); - it(`can be serialized when encoded`, () => { + it('can be serialized when encoded', () => { const contents = 'BT\n' + '/F1 24 Tf\n' + diff --git a/tests/core/structures/PDFCrossRefStream.spec.ts b/tests/core/structures/PDFCrossRefStream.spec.ts index 2029f5bb5..e4cf49af6 100644 --- a/tests/core/structures/PDFCrossRefStream.spec.ts +++ b/tests/core/structures/PDFCrossRefStream.spec.ts @@ -6,13 +6,13 @@ import { PDFCrossRefStream, PDFRef, toCharCode, -} from 'src/index'; +} from '../../../src/index'; -describe(`PDFCrossRefStream`, () => { +describe('PDFCrossRefStream', () => { const context = PDFContext.create(); const dict = context.obj({}); - it(`can be constructed from PDFCrossRefStream.create(...)`, () => { + it('can be constructed from PDFCrossRefStream.create(...)', () => { expect(PDFCrossRefStream.create(dict, false)).toBeInstanceOf( PDFCrossRefStream, ); @@ -29,14 +29,14 @@ describe(`PDFCrossRefStream`, () => { stream2.addUncompressedEntry(PDFRef.of(9000), 600); stream2.addCompressedEntry(PDFRef.of(9001), PDFRef.of(10), 1); - it(`can be cloned`, () => { + it('can be cloned', () => { const original = stream1; const clone = original.clone(); expect(clone).not.toBe(original); expect(String(clone)).toBe(String(original)); }); - it(`can be converted to a string`, () => { + it('can be converted to a string', () => { expect(String(stream1)).toEqual( '<<\n/Type /XRef\n/Length 16\n/W [ 1 1 2 ]\n/Index [ 0 3 21 1 ]\n>>\n' + 'stream\n' + @@ -45,7 +45,7 @@ describe(`PDFCrossRefStream`, () => { ); }); - it(`can be converted to a string without object number 1`, () => { + it('can be converted to a string without object number 1', () => { expect(String(stream2)).toEqual( '<<\n/Type /XRef\n/Length 25\n/W [ 1 2 2 ]\n/Index [ 0 1 2 2 9000 2 ]\n>>\n' + 'stream\n' + @@ -54,15 +54,15 @@ describe(`PDFCrossRefStream`, () => { ); }); - it(`can provide its size in bytes`, () => { + it('can provide its size in bytes', () => { expect(stream1.sizeInBytes()).toBe(95); }); - it(`can provide its size in bytes without object number 1`, () => { + it('can provide its size in bytes without object number 1', () => { expect(stream2.sizeInBytes()).toBe(110); }); - it(`can be serialized`, () => { + it('can be serialized', () => { const buffer = new Uint8Array(stream1.sizeInBytes() + 3).fill( toCharCode(' '), ); @@ -86,7 +86,7 @@ describe(`PDFCrossRefStream`, () => { ); }); - it(`can be serialized without object number 1`, () => { + it('can be serialized without object number 1', () => { const buffer = new Uint8Array(stream2.sizeInBytes() + 3).fill( toCharCode(' '), ); @@ -111,7 +111,7 @@ describe(`PDFCrossRefStream`, () => { ); }); - it(`can be serialized when encoded`, () => { + it('can be serialized when encoded', () => { const stream = PDFCrossRefStream.create(dict, true); stream.addUncompressedEntry(PDFRef.of(2), 300); stream.addCompressedEntry(PDFRef.of(3), PDFRef.of(10), 0); diff --git a/tests/core/structures/PDFObjectStream.spec.ts b/tests/core/structures/PDFObjectStream.spec.ts index ea55800af..49efecc35 100644 --- a/tests/core/structures/PDFObjectStream.spec.ts +++ b/tests/core/structures/PDFObjectStream.spec.ts @@ -10,9 +10,9 @@ import { PDFString, toCharCode, typedArrayFor, -} from 'src/index'; +} from '../../../src/index'; -describe(`PDFObjectStream`, () => { +describe('PDFObjectStream', () => { const context = PDFContext.create(); const objects: [PDFRef, PDFObject][] = [ @@ -27,13 +27,13 @@ describe(`PDFObjectStream`, () => { [context.nextRef(), PDFString.of('Stuff and thingz')], ]; - it(`can be constructed from PDFObjectStream.of(...)`, () => { + it('can be constructed from PDFObjectStream.of(...)', () => { expect( PDFObjectStream.withContextAndObjects(context, objects, false), ).toBeInstanceOf(PDFObjectStream); }); - it(`can be cloned`, () => { + it('can be cloned', () => { const original = PDFObjectStream.withContextAndObjects( context, objects, @@ -44,7 +44,7 @@ describe(`PDFObjectStream`, () => { expect(String(clone)).toBe(String(original)); }); - it(`can be converted to a string`, () => { + it('can be converted to a string', () => { expect( String(PDFObjectStream.withContextAndObjects(context, objects, false)), ).toEqual( @@ -64,7 +64,7 @@ describe(`PDFObjectStream`, () => { ); }); - it(`can provide its size in bytes`, () => { + it('can provide its size in bytes', () => { expect( PDFObjectStream.withContextAndObjects( context, @@ -74,7 +74,7 @@ describe(`PDFObjectStream`, () => { ).toBe(172); }); - it(`can be serialized`, () => { + it('can be serialized', () => { const stream = PDFObjectStream.withContextAndObjects( context, objects, @@ -103,7 +103,7 @@ describe(`PDFObjectStream`, () => { ); }); - it(`can be serialized when encoded`, () => { + it('can be serialized when encoded', () => { const contents = '1 0 2 4 3 9 4 15 5 24 6 31 7 39 8 44 9 47 ' + '[ ]\n' + diff --git a/tests/core/structures/PDFPageLeaf.spec.ts b/tests/core/structures/PDFPageLeaf.spec.ts index 6c1305149..c74d20184 100644 --- a/tests/core/structures/PDFPageLeaf.spec.ts +++ b/tests/core/structures/PDFPageLeaf.spec.ts @@ -6,10 +6,10 @@ import { PDFPageLeaf, PDFPageTree, PDFRef, -} from 'src/index'; +} from '../../../src/index'; -describe(`PDFPageLeaf`, () => { - it(`can be constructed directly from a Map and PDFContext`, () => { +describe('PDFPageLeaf', () => { + it('can be constructed directly from a Map and PDFContext', () => { const context = PDFContext.create(); const dict = new Map(); const pageTree = PDFPageLeaf.fromMapWithContext(dict, context); @@ -21,7 +21,7 @@ describe(`PDFPageLeaf`, () => { expect(pageTree.get(PDFName.of('Parent'))).toBeUndefined(); }); - it(`is constructed with the correct Type and entries`, () => { + it('is constructed with the correct Type and entries', () => { const context = PDFContext.create(); const parentRef = PDFRef.of(1); const pageTree = PDFPageLeaf.withContextAndParent(context, parentRef); @@ -33,7 +33,7 @@ describe(`PDFPageLeaf`, () => { expect(pageTree.get(PDFName.of('MediaBox'))).toBeInstanceOf(PDFArray); }); - it(`returns its Parent, Contents, Annots, BleedBox, TrimBox, Resources, MediaBox, CropBox, and Rotate entry values when they are references`, () => { + it('returns its Parent, Contents, Annots, BleedBox, TrimBox, Resources, MediaBox, CropBox, and Rotate entry values when they are references', () => { const context = PDFContext.create(); const parent = PDFPageTree.withContext(context); @@ -88,7 +88,7 @@ describe(`PDFPageLeaf`, () => { expect(pageLeaf.Rotate()).toBe(rotate); }); - it(`returns its Parent, Contents, Annots, BleedBox, TrimBox, Resources, MediaBox, CropBox, and Rotate entry values when they are direct objects`, () => { + it('returns its Parent, Contents, Annots, BleedBox, TrimBox, Resources, MediaBox, CropBox, and Rotate entry values when they are direct objects', () => { const context = PDFContext.create(); const parent = PDFPageTree.withContext(context); @@ -135,7 +135,7 @@ describe(`PDFPageLeaf`, () => { expect(pageLeaf.Rotate()).toBe(rotate); }); - it(`returns its Resources, MediaBox, CropBox, and Rotate entry values when they are inherited`, () => { + it('returns its Resources, MediaBox, CropBox, and Rotate entry values when they are inherited', () => { const context = PDFContext.create(); const resources = context.obj({}); @@ -173,7 +173,7 @@ describe(`PDFPageLeaf`, () => { expect(pageLeaf.Rotate()).toBe(rotate); }); - it(`returns its Resources, MediaBox, CropBox, and Rotate entry values after being normalized, when they are inherited`, () => { + it('returns its Resources, MediaBox, CropBox, and Rotate entry values after being normalized, when they are inherited', () => { const context = PDFContext.create(); const resources = context.obj({ @@ -220,7 +220,7 @@ describe(`PDFPageLeaf`, () => { expect(XObject).toBe(resources.get(PDFName.XObject)); }); - it(`can set its Parent`, () => { + it('can set its Parent', () => { const context = PDFContext.create(); const parentRef = PDFRef.of(1); const pageTree = PDFPageLeaf.withContextAndParent(context, parentRef); @@ -228,7 +228,7 @@ describe(`PDFPageLeaf`, () => { expect(pageTree.get(PDFName.of('Parent'))).toBe(PDFRef.of(21)); }); - it(`can add content stream refs`, () => { + it('can add content stream refs', () => { const context = PDFContext.create(); const parentRef = PDFRef.of(1); const pageTree = PDFPageLeaf.withContextAndParent(context, parentRef); @@ -239,7 +239,7 @@ describe(`PDFPageLeaf`, () => { expect(pageTree.Contents()!.toString()).toBe('[ 21 0 R 99 0 R ]'); }); - it(`can set font dictionary refs`, () => { + it('can set font dictionary refs', () => { const context = PDFContext.create(); const parentRef = PDFRef.of(1); const pageTree = PDFPageLeaf.withContextAndParent(context, parentRef); @@ -255,7 +255,7 @@ describe(`PDFPageLeaf`, () => { ); }); - it(`can set XObject refs`, () => { + it('can set XObject refs', () => { const context = PDFContext.create(); const parentRef = PDFRef.of(1); const pageTree = PDFPageLeaf.withContextAndParent(context, parentRef); @@ -271,7 +271,7 @@ describe(`PDFPageLeaf`, () => { ); }); - it(`can set ExtGState refs and dicts`, () => { + it('can set ExtGState refs and dicts', () => { const context = PDFContext.create(); const parentRef = PDFRef.of(1); const pageTree = PDFPageLeaf.withContextAndParent(context, parentRef); @@ -287,7 +287,7 @@ describe(`PDFPageLeaf`, () => { ); }); - it(`can be ascended`, () => { + it('can be ascended', () => { const context = PDFContext.create(); const pageTree1 = PDFPageTree.withContext(context); @@ -309,7 +309,7 @@ describe(`PDFPageLeaf`, () => { expect(visitations).toEqual([pageLeaf, pageTree2, pageTree1]); }); - it(`can be normalized with autoNormalizeCTM=false`, () => { + it('can be normalized with autoNormalizeCTM=false', () => { const context = PDFContext.create(); const parentRef = PDFRef.of(1); const pageTree = PDFPageLeaf.withContextAndParent(context, parentRef); @@ -329,7 +329,7 @@ describe(`PDFPageLeaf`, () => { ); }); - it(`can be normalized with autoNormalizeCTM=true`, () => { + it('can be normalized with autoNormalizeCTM=true', () => { const context = PDFContext.create(); const map = new Map(); const pageTree = PDFPageLeaf.fromMapWithContext(map, context); diff --git a/tests/core/structures/PDFPageTree.spec.ts b/tests/core/structures/PDFPageTree.spec.ts index 57df5a619..2ff379f6e 100644 --- a/tests/core/structures/PDFPageTree.spec.ts +++ b/tests/core/structures/PDFPageTree.spec.ts @@ -1,5 +1,5 @@ import fs from 'fs'; -import { TreeNode } from 'src/core/structures/PDFPageTree'; +import { TreeNode } from '../../../src/core/structures/PDFPageTree'; import { PDFArray, PDFContext, @@ -9,7 +9,7 @@ import { PDFPageTree, PDFRef, PDFDocument, -} from 'src/index'; +} from '../../../src/index'; const withNullEntryPdfBytes = fs.readFileSync( 'assets/pdfs/with_null_parent_entry.pdf', @@ -41,8 +41,8 @@ const pushLeafNodes = (tree: PDFPageTree, ...nodes: PDFRef[]) => { nodes.forEach((n) => tree.pushLeafNode(n)); }; -describe(`PDFPageTree`, () => { - it(`can be constructed directly from a Map and PDFContext`, () => { +describe('PDFPageTree', () => { + it('can be constructed directly from a Map and PDFContext', () => { const context = PDFContext.create(); const dict = new Map(); const pageTree = PDFPageTree.fromMapWithContext(dict, context); @@ -54,7 +54,7 @@ describe(`PDFPageTree`, () => { expect(pageTree.get(PDFName.of('Parent'))).toBeUndefined(); }); - it(`is constructed with the correct Type and entries`, () => { + it('is constructed with the correct Type and entries', () => { const context = PDFContext.create(); const pageTree = PDFPageTree.withContext(context); @@ -67,7 +67,7 @@ describe(`PDFPageTree`, () => { expect(pageTree.get(PDFName.of('Parent'))).toBeUndefined(); }); - it(`returns its Parent, Kids, and Count entry values when they are references`, () => { + it('returns its Parent, Kids, and Count entry values when they are references', () => { const context = PDFContext.create(); const parent = context.obj({}); @@ -88,7 +88,7 @@ describe(`PDFPageTree`, () => { expect(pageTree.Count()).toBe(count); }); - it(`returns its Parent, Kids, and Count entry values when they are direct objects`, () => { + it('returns its Parent, Kids, and Count entry values when they are direct objects', () => { const context = PDFContext.create(); const kids = context.obj([]); @@ -104,7 +104,7 @@ describe(`PDFPageTree`, () => { expect(pageTree.Count()).toBe(count); }); - it(`can be ascended`, () => { + it('can be ascended', () => { const { pageTree } = pageUtils(); const [lvl1Tree1Ref, lvl1Tree1] = pageTree(); @@ -119,7 +119,7 @@ describe(`PDFPageTree`, () => { expect(visitations).toEqual([lvl3Tree1, lvl2Tree1, lvl1Tree1]); }); - it(`can perform a Post-Order traversal`, () => { + it('can perform a Post-Order traversal', () => { const { pageTree, pageLeaf } = pageUtils(); const [rootPageTreeRef, rootPageTree] = pageTree(); @@ -156,8 +156,8 @@ describe(`PDFPageTree`, () => { ]); }); - describe(`leaf node insertion`, () => { - it(`can insert leaf nodes into the middle of the second layer of a page tree`, () => { + describe('leaf node insertion', () => { + it('can insert leaf nodes into the middle of the second layer of a page tree', () => { const { context, pageTree, pageLeaf } = pageUtils(); const [lvl1Tree1Ref, lvl1Tree1] = pageTree(); @@ -201,7 +201,7 @@ describe(`PDFPageTree`, () => { expect(lvl2Tree1.Kids().get(2)).toBe(lvl3Tree1Ref); }); - it(`can insert leaf nodes towards the end of the second layer of a page tree`, () => { + it('can insert leaf nodes towards the end of the second layer of a page tree', () => { const { context, pageTree, pageLeaf } = pageUtils(); const [lvl1Tree1Ref, lvl1Tree1] = pageTree(); @@ -243,7 +243,7 @@ describe(`PDFPageTree`, () => { expect(lvl2Tree1.Kids().get(3)).toBe(leafRef5); }); - it(`can insert leaf nodes at the end of a page tree`, () => { + it('can insert leaf nodes at the end of a page tree', () => { const { context, pageTree, pageLeaf } = pageUtils(); const [lvl1Tree1Ref, lvl1Tree1] = pageTree(); @@ -269,7 +269,7 @@ describe(`PDFPageTree`, () => { expect(lvl1Tree1.Kids().get(3)).toBe(newLeafRef); }); - it(`returns the correct ref when inserting more than two levels deep`, () => { + it('returns the correct ref when inserting more than two levels deep', () => { const { context, pageTree, pageLeaf } = pageUtils(); const [lvl1Tree1Ref, lvl1Tree1] = pageTree(); @@ -299,7 +299,7 @@ describe(`PDFPageTree`, () => { expect(lvl3Tree1.Kids().get(2)).toBe(leafRef2); }); - it(`throws an error when inserting past the end of a tree`, () => { + it('throws an error when inserting past the end of a tree', () => { const { context, pageTree, pageLeaf } = pageUtils(); const [lvl1Tree1Ref, lvl1Tree1] = pageTree(); @@ -316,8 +316,8 @@ describe(`PDFPageTree`, () => { }); }); - describe(`leaf node removal`, () => { - it(`can remove leaf nodes from the end of the second layer of a page tree`, () => { + describe('leaf node removal', () => { + it('can remove leaf nodes from the end of the second layer of a page tree', () => { const { pageTree, pageLeaf } = pageUtils(); const [lvl1Tree1Ref, lvl1Tree1] = pageTree(); @@ -357,7 +357,7 @@ describe(`PDFPageTree`, () => { expect(lvl2Tree1.Kids().get(2)).toBe(undefined); }); - it(`can remove leaf nodes from a parent node that is the last child of another node`, () => { + it('can remove leaf nodes from a parent node that is the last child of another node', () => { const { pageTree, pageLeaf } = pageUtils(); const [lvl1Tree1Ref, lvl1Tree1] = pageTree(); @@ -366,7 +366,7 @@ describe(`PDFPageTree`, () => { const [lvl4Tree1Ref, lvl4Tree1] = pageTree(lvl3Tree1Ref); const [leafRef1] = pageLeaf(lvl1Tree1Ref); - const [] = pageLeaf(lvl2Tree1Ref); + pageLeaf(lvl2Tree1Ref); const [leafRef3] = pageLeaf(lvl4Tree1Ref); const [leafRef4] = pageLeaf(lvl1Tree1Ref); @@ -399,7 +399,7 @@ describe(`PDFPageTree`, () => { expect(lvl4Tree1.Kids().get(0)).toBe(undefined); }); - it(`can remove leaf nodes from the end of a page tree`, () => { + it('can remove leaf nodes from the end of a page tree', () => { const { pageTree, pageLeaf } = pageUtils(); const [lvl1Tree1Ref, lvl1Tree1] = pageTree(); @@ -420,7 +420,7 @@ describe(`PDFPageTree`, () => { expect(lvl1Tree1.Kids().get(2)).toBe(undefined); }); - it(`throws an error when removing past the end of a tree`, () => { + it('throws an error when removing past the end of a tree', () => { const buildTree = () => { const { pageTree, pageLeaf } = pageUtils(); @@ -446,7 +446,7 @@ describe(`PDFPageTree`, () => { ); }); - it(`does not throw an error when at the end of a hierarchical tree`, () => { + it('does not throw an error when at the end of a hierarchical tree', () => { const buildTree = () => { const { pageTree, pageLeaf } = pageUtils(); @@ -496,7 +496,7 @@ describe(`PDFPageTree`, () => { ); }); - it(`throws an error when the page tree has no kids`, () => { + it('throws an error when the page tree has no kids', () => { const buildTree = () => { const { pageTree } = pageUtils(); const [, lvl1Tree1] = pageTree(); @@ -511,7 +511,7 @@ describe(`PDFPageTree`, () => { ); }); - it(`throws an error when the page tree is invalid`, () => { + it('throws an error when the page tree is invalid', () => { const buildTree = () => { const { pageTree } = pageUtils(); const [, lvl1Tree1] = pageTree(); @@ -522,14 +522,14 @@ describe(`PDFPageTree`, () => { tree.set(PDFName.of('Count'), PDFNumber.of(21)); expect(() => tree.removeLeafNode(0)).toThrow( - `Failed to removeLeafNode at targetIndex=0 due to corrupt page tree: It is likely that one or more 'Count' entries are invalid`, + "Failed to removeLeafNode at targetIndex=0 due to corrupt page tree: It is likely that one or more 'Count' entries are invalid", ); expect(() => tree.removeLeafNode(1)).toThrow( - `Failed to removeLeafNode at targetIndex=1 due to corrupt page tree: It is likely that one or more 'Count' entries are invalid`, + "Failed to removeLeafNode at targetIndex=1 due to corrupt page tree: It is likely that one or more 'Count' entries are invalid", ); }); - it(`removes tree nodes that have 0 children after a leaf node is removed`, () => { + it('removes tree nodes that have 0 children after a leaf node is removed', () => { const { pageTree, pageLeaf } = pageUtils(); const [tree1Ref, tree1] = pageTree(); @@ -576,7 +576,7 @@ describe(`PDFPageTree`, () => { }); }); - it(`can be ascended when a "/Parent null" entry exists on a node`, async () => { + it('can be ascended when a "/Parent null" entry exists on a node', async () => { const pdfDoc = await PDFDocument.load(withNullEntryPdfBytes); const pages = pdfDoc.getPages(); const parent = pages[0].node.Parent(); diff --git a/tests/core/writers/PDFStreamWriter.spec.ts b/tests/core/writers/PDFStreamWriter.spec.ts index 6f23e5ff8..10f4a479f 100644 --- a/tests/core/writers/PDFStreamWriter.spec.ts +++ b/tests/core/writers/PDFStreamWriter.spec.ts @@ -1,6 +1,11 @@ import fs from 'fs'; -import { PDFContext, PDFName, PDFRef, PDFStreamWriter } from 'src/index'; +import { + PDFContext, + PDFName, + PDFRef, + PDFStreamWriter, +} from '../../../src/index'; const expectedPdfBytes = new Uint8Array( fs.readFileSync('./tests/core/writers/data/stream-writer-1.pdf'), @@ -14,8 +19,8 @@ const contentStreamText = ` ET `; -describe(`PDFStreamWriter`, () => { - it(`serializes PDFContext objects using Indirect Objects, Object Streams, and XRef Streams`, async () => { +describe('PDFStreamWriter', () => { + it('serializes PDFContext objects using Indirect Objects, Object Streams, and XRef Streams', async () => { const context = PDFContext.create(); const contentStream = context.flateStream(contentStreamText); diff --git a/tests/core/writers/PDFWriter.spec.ts b/tests/core/writers/PDFWriter.spec.ts index c38d8689a..5c29038f6 100644 --- a/tests/core/writers/PDFWriter.spec.ts +++ b/tests/core/writers/PDFWriter.spec.ts @@ -6,7 +6,7 @@ import { PDFRef, PDFWriter, typedArrayFor, -} from 'src/index'; +} from '../../../src/index'; const contentStreamText = ` BT @@ -94,8 +94,8 @@ startxref %%EOF`, ); -describe(`PDFWriter`, () => { - it(`serializes PDFContext objects using Indirect Objects and a Cross Reference table`, async () => { +describe('PDFWriter', () => { + it('serializes PDFContext objects using Indirect Objects and a Cross Reference table', async () => { const context = PDFContext.create(); const contentStream = context.flateStream(contentStreamText); diff --git a/tests/tsconfig.json b/tests/tsconfig.json index eea765bc4..34177019e 100644 --- a/tests/tsconfig.json +++ b/tests/tsconfig.json @@ -1,6 +1,9 @@ { "extends": "../tsconfig.json", "include": ["./**/*"], - "rootDir": null, - "rootDirs": ["../src", "../tests"] + "exclude": [], + "compilerOptions": { + "rootDir": null, + "rootDirs": ["../src", "../tests"] + } } diff --git a/tests/utils/base64.spec.ts b/tests/utils/base64.spec.ts index a33e78aa1..2062df390 100644 --- a/tests/utils/base64.spec.ts +++ b/tests/utils/base64.spec.ts @@ -1,5 +1,5 @@ import fs from 'fs'; -import { decodeFromBase64DataUri } from 'src/utils'; +import { decodeFromBase64DataUri } from '../../src/utils'; const pdfBytes = fs.readFileSync('tests/utils/data/simple.pdf'); const pdfBase64Bytes = fs.readFileSync('tests/utils/data/simple.pdf.base64'); @@ -13,48 +13,48 @@ const arraysAreEqual = (a: Uint8Array, b: Uint8Array) => { return true; }; -describe(`decodeFromBase64DataUri`, () => { - it(`can decode plain base64 strings`, () => { +describe('decodeFromBase64DataUri', () => { + it('can decode plain base64 strings', () => { const uri = String(pdfBase64Bytes); expect(arraysAreEqual(decodeFromBase64DataUri(uri), pdfBytes)).toBe(true); }); - it(`can decode complete data URIs`, () => { + it('can decode complete data URIs', () => { const uri = `data:application/pdf;base64,${pdfBase64Bytes}`; expect(arraysAreEqual(decodeFromBase64DataUri(uri), pdfBytes)).toBe(true); }); - it(`can decode partial data URIs (1)`, () => { + it('can decode partial data URIs (1)', () => { const uri = `data:application/pdf;,${pdfBase64Bytes}`; expect(arraysAreEqual(decodeFromBase64DataUri(uri), pdfBytes)).toBe(true); }); - it(`can decode partial data URIs (2)`, () => { + it('can decode partial data URIs (2)', () => { const uri = `data:;,${pdfBase64Bytes}`; expect(arraysAreEqual(decodeFromBase64DataUri(uri), pdfBytes)).toBe(true); }); - it(`can decode partial data URIs (3)`, () => { + it('can decode partial data URIs (3)', () => { const uri = `data:application/pdf;,${pdfBase64Bytes}`; expect(arraysAreEqual(decodeFromBase64DataUri(uri), pdfBytes)).toBe(true); }); - it(`can decode partial data URIs (4)`, () => { + it('can decode partial data URIs (4)', () => { const uri = `:;,${pdfBase64Bytes}`; expect(arraysAreEqual(decodeFromBase64DataUri(uri), pdfBytes)).toBe(true); }); - it(`can decode partial data URIs (5)`, () => { + it('can decode partial data URIs (5)', () => { const uri = `;,${pdfBase64Bytes}`; expect(arraysAreEqual(decodeFromBase64DataUri(uri), pdfBytes)).toBe(true); }); - it(`can decode partial data URIs (6)`, () => { + it('can decode partial data URIs (6)', () => { const uri = `,${pdfBase64Bytes}`; expect(arraysAreEqual(decodeFromBase64DataUri(uri), pdfBytes)).toBe(true); }); - it(`can throws an error when it fails to parse the URI`, () => { + it('can throws an error when it fails to parse the URI', () => { const uri = {} as any; expect(() => decodeFromBase64DataUri(uri)).toThrow(); }); diff --git a/tests/utils/pdfDocEncoding.spec.ts b/tests/utils/pdfDocEncoding.spec.ts index 96f609e6d..6c454c8f9 100644 --- a/tests/utils/pdfDocEncoding.spec.ts +++ b/tests/utils/pdfDocEncoding.spec.ts @@ -1,4 +1,4 @@ -import { range, pdfDocEncodingDecode } from 'src/utils'; +import { range, pdfDocEncodingDecode } from '../../src/utils'; type Mapping = [number, string]; @@ -60,8 +60,8 @@ const mappings: Mapping[] = [ ...range(0xae, 0xff + 1).map(identityMapping), ]; -describe(`pdfDocEncodingDecode`, () => { - it(`maps all PDFDocEncoding codes from 0-255 to the correct Unicode code points`, () => { +describe('pdfDocEncodingDecode', () => { + it('maps all PDFDocEncoding codes from 0-255 to the correct Unicode code points', () => { // Make sure we have defined mappings for all codes from 0-255 expect(mappings.map(([code]) => code).sort((a, b) => a - b)).toEqual( range(0, 256), diff --git a/tests/utils/png.spec.ts b/tests/utils/png.spec.ts index fdf9c1e2a..e3bcc6913 100644 --- a/tests/utils/png.spec.ts +++ b/tests/utils/png.spec.ts @@ -1,7 +1,7 @@ -import { PNG } from 'src/utils/png'; +import { PNG } from '../../src/utils/png'; -describe(`PNG`, () => { - it(`can load images with alpha values greater than 1`, () => { +describe('PNG', () => { + it('can load images with alpha values greater than 1', () => { // This Uint8Array contains a PNG image composed of a single pixel. It was // generated with the following code in a browser: // ``` diff --git a/tests/utils/rng.spec.ts b/tests/utils/rng.spec.ts index d5310e105..7b491fe03 100644 --- a/tests/utils/rng.spec.ts +++ b/tests/utils/rng.spec.ts @@ -1,12 +1,12 @@ -import { SimpleRNG } from 'src/utils/rng'; +import { SimpleRNG } from '../../src/utils/rng'; -describe(`psuedo random numbers`, () => { - it(`generates distinct numbers`, () => { +describe('psuedo random numbers', () => { + it('generates distinct numbers', () => { const rng = SimpleRNG.withSeed(1); expect(rng.nextInt()).not.toEqual(rng.nextInt()); }); - it(`generates the same number across different SimpleRNG`, () => { + it('generates the same number across different SimpleRNG', () => { const rng = SimpleRNG.withSeed(1); expect(rng.nextInt()).toEqual(0.7098480789645691); expect(rng.nextInt()).toEqual(0.9742682568175951); diff --git a/tests/utils/strings.spec.ts b/tests/utils/strings.spec.ts index ac3f13a2d..ac41e28d4 100644 --- a/tests/utils/strings.spec.ts +++ b/tests/utils/strings.spec.ts @@ -2,8 +2,8 @@ import fontkit from '@pdf-lib/fontkit'; import { FontNames } from '@pdf-lib/standard-fonts'; import fs from 'fs'; -import { CustomFontEmbedder, StandardFontEmbedder } from 'src/core'; -import { breakTextIntoLines } from 'src/utils'; +import { CustomFontEmbedder, StandardFontEmbedder } from '../../src/core'; +import { breakTextIntoLines } from '../../src/utils'; const font = StandardFontEmbedder.for(FontNames.Helvetica); @@ -12,36 +12,36 @@ const textSize = 24; const computeTextWidth = (text: string) => font.widthOfTextAtSize(text, textSize); -describe(`breakTextIntoLines`, () => { - it(`handles empty wordBreaks arrays`, () => { +describe('breakTextIntoLines', () => { + it('handles empty wordBreaks arrays', () => { const input = 'foobar-quxbaz'; const expected = ['foobar-quxbaz']; const actual = breakTextIntoLines(input, [], 21, computeTextWidth); expect(actual).toEqual(expected); }); - it(`handles trailing newlines`, () => { + it('handles trailing newlines', () => { const input = 'foo\n'; const expected = ['foo']; const actual = breakTextIntoLines(input, [], 21, computeTextWidth); expect(actual).toEqual(expected); }); - it(`handles trailing carriage returns`, () => { + it('handles trailing carriage returns', () => { const input = 'foo\r'; const expected = ['foo']; const actual = breakTextIntoLines(input, [], 21, computeTextWidth); expect(actual).toEqual(expected); }); - it(`always breaks lines when EOLs are encountered`, () => { + it('always breaks lines when EOLs are encountered', () => { const input = 'foo\nbar-qux\rbaz\n'; const expected = ['foo', 'bar-qux', 'baz']; const actual = breakTextIntoLines(input, [], 90000, computeTextWidth); expect(actual).toEqual(expected); }); - it(`breaks at the last possible 'wordBreak' before exceeding 'maxWidth' (1)`, () => { + it("breaks at the last possible 'wordBreak' before exceeding 'maxWidth' (1)", () => { const input = 'Lorem Test ipsum dolor sit amet, consectetur adipiscing\nelit'; const expected = [ @@ -63,14 +63,14 @@ describe(`breakTextIntoLines`, () => { expect(actual).toEqual(expected); }); - it(`breaks at the last possible 'wordBreak' before exceeding 'maxWidth' (2)`, () => { + it("breaks at the last possible 'wordBreak' before exceeding 'maxWidth' (2)", () => { const input = 'Foo%bar%baz'; const expected = ['Foo%', 'bar%baz']; const actual = breakTextIntoLines(input, ['%'], 100, computeTextWidth); expect(actual).toEqual(expected); }); - it(`handles non-ascii code points and empty breaks`, async () => { + it('handles non-ascii code points and empty breaks', async () => { const sourceHansBytes = fs.readFileSync( 'assets/fonts/source_hans_jp/SourceHanSerifJP-Regular.otf', ); diff --git a/tests/utils/unicode.spec.ts b/tests/utils/unicode.spec.ts index 8cbd45285..70a9c69be 100644 --- a/tests/utils/unicode.spec.ts +++ b/tests/utils/unicode.spec.ts @@ -3,7 +3,7 @@ import { utf16Encode, utf8Encode, utf16Decode, -} from 'src/utils'; +} from '../../src/utils'; const utf8BOM = new Uint8Array([0xef, 0xbb, 0xbf]); const utf16BOM = new Uint16Array([0xfeff]); @@ -14,14 +14,14 @@ const withUtf8Bom = (encoding: Uint8Array) => const withUtf16Bom = (encoding: Uint16Array) => new Uint16Array([...Array.from(utf16BOM), ...Array.from(encoding)]); -describe(`utf8Encode`, () => { - it(`encodes to UTF-8`, () => { +describe('utf8Encode', () => { + it('encodes to UTF-8', () => { const input = '\u{004D}\u{0430}\u{4E8C}\u{10302}'; // prettier-ignore const expected = new Uint8Array([ - /* U+004D */ 0x4d, - /* U+0430 */ 0xd0, 0xb0, + /* U+004D */ 0x4d, + /* U+0430 */ 0xd0, 0xb0, /* U+4E8C */ 0xe4, 0xba, 0x8c, /* U+10302 */ 0xf0, 0x90, 0x8c, 0x82, ]); @@ -31,13 +31,13 @@ describe(`utf8Encode`, () => { expect(actual).toEqual(withUtf8Bom(expected)); }); - it(`encodes to UTF-8`, () => { + it('encodes to UTF-8', () => { const input = '\u{004D}\u{0061}\u{10000}'; // prettier-ignore const expected = new Uint8Array([ - /* U+004D */ 0x4d, - /* U+0061 */ 0x61, + /* U+004D */ 0x4d, + /* U+0061 */ 0x61, /* U+10000 */ 0xf0, 0x90, 0x80, 0x80, ]); @@ -46,13 +46,13 @@ describe(`utf8Encode`, () => { expect(actual).toEqual(withUtf8Bom(expected)); }); - it(`encodes to UTF-8 (without a BOM)`, () => { + it('encodes to UTF-8 (without a BOM)', () => { const input = '💩🎂'; // prettier-ignore const expected = new Uint8Array([ - /* U+1F4A9 */ 0xf0, 0x9f, 0x92, 0xa9, - /* U+1F382 */ 0xf0, 0x9f, 0x8e, 0x82, + /* U+1F4A9 */ 0xf0, 0x9f, 0x92, 0xa9, + /* U+1F382 */ 0xf0, 0x9f, 0x8e, 0x82, ]); const actual = utf8Encode(input, false); @@ -60,7 +60,7 @@ describe(`utf8Encode`, () => { expect(actual).toEqual(expected); }); - it(`encodes "Дмитрий Козлюк (Dmitry Kozlyuk)" to UTF-8`, () => { + it('encodes "Дмитрий Козлюк (Dmitry Kozlyuk)" to UTF-8', () => { const input = 'Дмитрий Козлюк (Dmitry Kozlyuk)'; // prettier-ignore @@ -76,7 +76,7 @@ describe(`utf8Encode`, () => { expect(actual).toEqual(withUtf8Bom(expected)); }); - it(`encodes "ä☺𠜎️☁️" to UTF-8 (without a BOM)`, () => { + it('encodes "ä☺𠜎️☁️" to UTF-8 (without a BOM)', () => { const input = 'ä☺𠜎️☁️'; // prettier-ignore @@ -91,16 +91,16 @@ describe(`utf8Encode`, () => { }); }); -describe(`utf16Encode`, () => { - it(`encodes to UTF-16`, () => { +describe('utf16Encode', () => { + it('encodes to UTF-16', () => { const input = '\u{004D}\u{0430}\u{4E8C}\u{10302}'; // prettier-ignore const expected = new Uint16Array(new Uint8Array([ - /* U+004D */ 0x4d, 0x00, + /* U+004D */ 0x4d, 0x00, /* U+0430 */ 0x30, 0x04, /* U+4E8C */ 0x8c, 0x4e, - /* U+10302 */ 0x00, 0xd8, 0x02, 0xdf, + /* U+10302 */ 0x00, 0xd8, 0x02, 0xdf, ]).buffer); const actual = utf16Encode(input); @@ -108,12 +108,12 @@ describe(`utf16Encode`, () => { expect(actual).toEqual(withUtf16Bom(expected)); }); - it(`encodes to UTF-16`, () => { + it('encodes to UTF-16', () => { const input = '\u{004D}\u{0061}\u{10000}'; // prettier-ignore const expected = new Uint16Array(new Uint8Array([ - /* U+004D */ 0x4d, 0x00, + /* U+004D */ 0x4d, 0x00, /* U+0061 */ 0x61, 0x00, /* U+10000 */ 0x00, 0xd8, 0x00, 0xdc, ]).buffer); @@ -123,7 +123,7 @@ describe(`utf16Encode`, () => { expect(actual).toEqual(withUtf16Bom(expected)); }); - it(`encodes to UTF-16 (without a BOM)`, () => { + it('encodes to UTF-16 (without a BOM)', () => { const input = '💩🎂'; // prettier-ignore @@ -137,13 +137,13 @@ describe(`utf16Encode`, () => { expect(actual).toEqual(expected); }); - it(`encodes "Дмитрий Козлюк (Dmitry Kozlyuk)" to UTF-16`, () => { + it('encodes "Дмитрий Козлюк (Dmitry Kozlyuk)" to UTF-16', () => { const input = 'Дмитрий Козлюк (Dmitry Kozlyuk)'; // prettier-ignore const expected = new Uint16Array([ - 0x414, 0x43c, 0x438, 0x442, 0x440, 0x438, 0x439, 0x20, 0x41a, 0x43e, - 0x437, 0x43b, 0x44e, 0x43a, 0x20, 0x28, 0x44, 0x6d, 0x69, 0x74, 0x72, + 0x414, 0x43c, 0x438, 0x442, 0x440, 0x438, 0x439, 0x20, 0x41a, 0x43e, + 0x437, 0x43b, 0x44e, 0x43a, 0x20, 0x28, 0x44, 0x6d, 0x69, 0x74, 0x72, 0x79, 0x20, 0x4b, 0x6f, 0x7a, 0x6c, 0x79, 0x75, 0x6b, 0x29, ]); @@ -152,7 +152,7 @@ describe(`utf16Encode`, () => { expect(actual).toEqual(withUtf16Bom(expected)); }); - it(`encodes "ä☺𠜎️☁️" to UTF-16 (without a BOM)`, () => { + it('encodes "ä☺𠜎️☁️" to UTF-16 (without a BOM)', () => { const input = 'ä☺𠜎️☁️'; // prettier-ignore @@ -166,8 +166,8 @@ describe(`utf16Encode`, () => { }); }); -describe(`utf16Decode`, () => { - it(`decodes from UTF-16`, () => { +describe('utf16Decode', () => { + it('decodes from UTF-16', () => { // prettier-ignore const input = new Uint8Array([ /* U+004D */ 0x00, 0x4d, @@ -183,11 +183,11 @@ describe(`utf16Decode`, () => { expect(actual).toEqual(expected); }); - it(`decodes from UTF-16`, () => { + it('decodes from UTF-16', () => { // prettier-ignore const input = new Uint8Array([ - /* U+004D */ 0x00, 0x4d, - /* U+0061 */ 0x00, 0x61, + /* U+004D */ 0x00, 0x4d, + /* U+0061 */ 0x00, 0x61, /* U+10000 */ 0xd8, 0x00, 0xdc, 0x00, ]); @@ -198,11 +198,11 @@ describe(`utf16Decode`, () => { expect(actual).toEqual(expected); }); - it(`decodes from UTF-16`, () => { + it('decodes from UTF-16', () => { // prettier-ignore const input = new Uint8Array([ /* U+1F4A9 */ 0xd8, 0x3d, 0xdc, 0xa9, - /* U+1F382 */ 0xd8, 0x3c, 0xdf, 0x82, + /* U+1F382 */ 0xd8, 0x3c, 0xdf, 0x82, ]); const expected = '💩🎂'; @@ -212,7 +212,7 @@ describe(`utf16Decode`, () => { expect(actual).toEqual(expected); }); - it(`decodes 'abcd' from UTF-16`, () => { + it("decodes 'abcd' from UTF-16", () => { // prettier-ignore const input = new Uint8Array([ /* a */ 0, 97, @@ -228,15 +228,15 @@ describe(`utf16Decode`, () => { expect(actual).toEqual(expected); }); - it(`decodes "Дмитрий Козлюк (Dmitry Kozlyuk)" from UTF-16`, () => { + it('decodes "Дмитрий Козлюк (Dmitry Kozlyuk)" from UTF-16', () => { const littleEndianBOM = (0xfe << 8) | 0xff; // prettier-ignore const input = new Uint8Array(new Uint16Array([ littleEndianBOM, 0x414, 0x43c, 0x438, 0x442, 0x440, 0x438, 0x439, 0x020, 0x41a, 0x43e, - 0x437, 0x43b, 0x44e, 0x43a, 0x020, 0x028, 0x044, 0x06d, 0x069, 0x074, - 0x072, 0x079, 0x020, 0x04b, 0x06f, 0x07a, 0x06c, 0x079, 0x075, 0x06b, + 0x437, 0x43b, 0x44e, 0x43a, 0x020, 0x028, 0x044, 0x06d, 0x069, 0x074, + 0x072, 0x079, 0x020, 0x04b, 0x06f, 0x07a, 0x06c, 0x079, 0x075, 0x06b, 0x29, ]).buffer); @@ -247,7 +247,7 @@ describe(`utf16Decode`, () => { expect(actual).toEqual(expected); }); - it(`decodes "ä☺𠜎️☁️" from UTF-16 (without a BOM)`, () => { + it('decodes "ä☺𠜎️☁️" from UTF-16 (without a BOM)', () => { const littleEndianBOM = (0xfe << 8) | 0xff; // prettier-ignore @@ -263,11 +263,11 @@ describe(`utf16Decode`, () => { expect(actual).toEqual(expected); }); - it(`injects a replacement character when the input ends prematurely`, () => { + it('injects a replacement character when the input ends prematurely', () => { // prettier-ignore const input = new Uint8Array([ /* U+1F4A9 */ 0xd8, 0x3d, 0xdc, 0xa9, - /* U+1F382 */ 0xd8, + /* U+1F382 */ 0xd8, ]); const expected = '💩�'; @@ -277,7 +277,7 @@ describe(`utf16Decode`, () => { expect(actual).toEqual(expected); }); - it(`injects a replacement character when the input ends with a high surrogate`, () => { + it('injects a replacement character when the input ends with a high surrogate', () => { // prettier-ignore const input = new Uint8Array([ /* U+1F4A9 */ 0xd8, 0x3d, 0xdc, 0xa9, @@ -291,7 +291,7 @@ describe(`utf16Decode`, () => { expect(actual).toEqual(expected); }); - it(`injects a replacement character when the input ends with a low surrogate`, () => { + it('injects a replacement character when the input ends with a low surrogate', () => { // prettier-ignore const input = new Uint8Array([ /* U+1F4A9 */ 0xd8, 0x3d, 0xdc, 0xa9, @@ -305,11 +305,11 @@ describe(`utf16Decode`, () => { expect(actual).toEqual(expected); }); - it(`injects a replacement character when low surrogates precede high surrogates`, () => { + it('injects a replacement character when low surrogates precede high surrogates', () => { // prettier-ignore const input = new Uint8Array([ /* U+1F4A9 */ 0xd8, 0x3d, 0xdc, 0xa9, - /* U+1F382 */ 0xdf, 0x82, 0xd8, 0x3c, + /* U+1F382 */ 0xdf, 0x82, 0xd8, 0x3c, /* valid a */ 0, 97, ]); @@ -320,7 +320,7 @@ describe(`utf16Decode`, () => { expect(actual).toEqual(expected); }); - it(`injects a replacement character when high surrogates are not followed by low surrogates`, () => { + it('injects a replacement character when high surrogates are not followed by low surrogates', () => { // prettier-ignore const input = new Uint8Array([ /* valid U+1F4A9 */ 0xd8, 0x3d, 0xdc, 0xa9, diff --git a/tsconfig.json b/tsconfig.json index 21f2d02cf..3a4dedde7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,12 +1,13 @@ { "compilerOptions": { /* Basic Options */ - "target": "es5", + "target": "es2015", "module": "commonjs", "allowJs": false, "checkJs": false, "declaration": true, "declarationMap": true, + "skipLibCheck": true, "sourceMap": true, "outDir": "./build", "rootDir": "./src", @@ -18,28 +19,35 @@ "downlevelIteration": false, "isolatedModules": false, "newLine": "LF", - /* Strict Type-Checking Options */ "strict": true, - /* Additional Checks */ "noUnusedLocals": true, "noUnusedParameters": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, - /* Module Resolution Options */ "baseUrl": "./src", "paths": { - "src/*": ["./*"] + "src/*": ["./*"], }, "allowSyntheticDefaultImports": true, "esModuleInterop": true, "preserveSymlinks": true, "moduleResolution": "node", - - /* Plugins */ - "plugins": [{ "transform": "@zerollup/ts-transform-paths" }] + "jsx": "react", }, - "include": ["src/**/*"] + "include": ["src/**/*", "tests/**/*"], + "exclude": [ + ".circleci", + ".github", + ".vscode", + "apps", + "assets", + "cjs", + "docs", + "node_modules", + "scratchpad", + "tests", + ], } diff --git a/yarn.lock b/yarn.lock index 520d474b0..f0738ea1f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,1036 +2,1394 @@ # yarn lockfile v1 -"@babel/code-frame@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" - integrity sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA== - dependencies: - "@babel/highlight" "^7.0.0" - -"@babel/code-frame@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.3.tgz#324bcfd8d35cd3d47dae18cde63d752086435e9a" - integrity sha512-fDx9eNW0qz0WkUeqL6tXEXzVlPh6Y5aCDEZesl0xBGA8ndRukX91Uk44ZqnkECp01NAZUdCAl+aiQNGi0k88Eg== - dependencies: - "@babel/highlight" "^7.10.3" - -"@babel/code-frame@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" - integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== +"@adnsistemas/upng@^1.0.3": + version "1.0.3" + resolved "https://registry.npmjs.org/@adnsistemas/upng/-/upng-1.0.3.tgz" + integrity sha512-NFvcGsilB79BxXtGKT+oRjzG4Ksr4Dg4t00x//PQgiE4PtRmyA9vWCRdCNhMVmWXHkuimcC5mkyqvsbHiUJufA== dependencies: - "@babel/highlight" "^7.8.3" + pako "^1.0.10" -"@babel/core@^7.1.0": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.4.4.tgz#84055750b05fcd50f9915a826b44fa347a825250" - integrity sha512-lQgGX3FPRgbz2SKmhMtYgJvVzGZrmjaF4apZ2bLwofAKiSjxU0drPh4S/VasyYXwaTs+A1gvQ45BN8SQJzHsQQ== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.4.4" - "@babel/helpers" "^7.4.4" - "@babel/parser" "^7.4.4" - "@babel/template" "^7.4.4" - "@babel/traverse" "^7.4.4" - "@babel/types" "^7.4.4" - convert-source-map "^1.1.0" - debug "^4.1.0" - json5 "^2.1.0" - lodash "^4.17.11" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/core@^7.7.5": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.9.0.tgz#ac977b538b77e132ff706f3b8a4dbad09c03c56e" - integrity sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.9.0" - "@babel/helper-module-transforms" "^7.9.0" - "@babel/helpers" "^7.9.0" - "@babel/parser" "^7.9.0" - "@babel/template" "^7.8.6" - "@babel/traverse" "^7.9.0" - "@babel/types" "^7.9.0" - convert-source-map "^1.7.0" +"@ampproject/remapping@^2.2.0": + version "2.2.1" + resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz" + integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.23.5": + version "7.23.5" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz" + integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== + dependencies: + "@babel/highlight" "^7.23.4" + chalk "^2.4.2" + +"@babel/compat-data@^7.23.5": + version "7.23.5" + resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz" + integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw== + +"@babel/core@^7.11.6", "@babel/core@^7.12.3": + version "7.23.9" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz" + integrity sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.23.5" + "@babel/generator" "^7.23.6" + "@babel/helper-compilation-targets" "^7.23.6" + "@babel/helper-module-transforms" "^7.23.3" + "@babel/helpers" "^7.23.9" + "@babel/parser" "^7.23.9" + "@babel/template" "^7.23.9" + "@babel/traverse" "^7.23.9" + "@babel/types" "^7.23.9" + convert-source-map "^2.0.0" debug "^4.1.0" - gensync "^1.0.0-beta.1" - json5 "^2.1.2" - lodash "^4.17.13" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/generator@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.4.4.tgz#174a215eb843fc392c7edcaabeaa873de6e8f041" - integrity sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ== - dependencies: - "@babel/types" "^7.4.4" - jsesc "^2.5.1" - lodash "^4.17.11" - source-map "^0.5.0" - trim-right "^1.0.1" - -"@babel/generator@^7.9.0", "@babel/generator@^7.9.5": - version "7.9.5" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.9.5.tgz#27f0917741acc41e6eaaced6d68f96c3fa9afaf9" - integrity sha512-GbNIxVB3ZJe3tLeDm1HSn2AhuD/mVcyLDpgtLXa5tplmWrJdF/elxB56XNqCuD6szyNkDi6wuoKXln3QeBmCHQ== - dependencies: - "@babel/types" "^7.9.5" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.23.6", "@babel/generator@^7.7.2": + version "7.23.6" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz" + integrity sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw== + dependencies: + "@babel/types" "^7.23.6" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" jsesc "^2.5.1" - lodash "^4.17.13" - source-map "^0.5.0" - -"@babel/helper-function-name@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53" - integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw== - dependencies: - "@babel/helper-get-function-arity" "^7.0.0" - "@babel/template" "^7.1.0" - "@babel/types" "^7.0.0" - -"@babel/helper-function-name@^7.9.5": - version "7.9.5" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz#2b53820d35275120e1874a82e5aabe1376920a5c" - integrity sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw== - dependencies: - "@babel/helper-get-function-arity" "^7.8.3" - "@babel/template" "^7.8.3" - "@babel/types" "^7.9.5" - -"@babel/helper-get-function-arity@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" - integrity sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ== - dependencies: - "@babel/types" "^7.0.0" - -"@babel/helper-get-function-arity@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" - integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-member-expression-to-functions@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c" - integrity sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-module-imports@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498" - integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-module-transforms@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz#43b34dfe15961918707d247327431388e9fe96e5" - integrity sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA== - dependencies: - "@babel/helper-module-imports" "^7.8.3" - "@babel/helper-replace-supers" "^7.8.6" - "@babel/helper-simple-access" "^7.8.3" - "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/template" "^7.8.6" - "@babel/types" "^7.9.0" - lodash "^4.17.13" - -"@babel/helper-optimise-call-expression@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9" - integrity sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-plugin-utils@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" - integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA== - -"@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670" - integrity sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ== - -"@babel/helper-replace-supers@^7.8.6": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz#5ada744fd5ad73203bf1d67459a27dcba67effc8" - integrity sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.8.3" - "@babel/helper-optimise-call-expression" "^7.8.3" - "@babel/traverse" "^7.8.6" - "@babel/types" "^7.8.6" -"@babel/helper-simple-access@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae" - integrity sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw== - dependencies: - "@babel/template" "^7.8.3" - "@babel/types" "^7.8.3" - -"@babel/helper-split-export-declaration@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz#ff94894a340be78f53f06af038b205c49d993677" - integrity sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q== - dependencies: - "@babel/types" "^7.4.4" - -"@babel/helper-split-export-declaration@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" - integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-validator-identifier@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.3.tgz#60d9847f98c4cea1b279e005fdb7c28be5412d15" - integrity sha512-bU8JvtlYpJSBPuj1VUmKpFGaDZuLxASky3LhaKj3bmpSTY6VWooSM8msk+Z0CZoErFye2tlABF6yDkT3FOPAXw== - -"@babel/helper-validator-identifier@^7.9.0", "@babel/helper-validator-identifier@^7.9.5": - version "7.9.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz#90977a8e6fbf6b431a7dc31752eee233bf052d80" - integrity sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g== - -"@babel/helpers@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.4.4.tgz#868b0ef59c1dd4e78744562d5ce1b59c89f2f2a5" - integrity sha512-igczbR/0SeuPR8RFfC7tGrbdTbFL3QTvH6D+Z6zNxnTe//GyqmtHmDkzrqDmyZ3eSwPqB/LhyKoU5DXsp+Vp2A== - dependencies: - "@babel/template" "^7.4.4" - "@babel/traverse" "^7.4.4" - "@babel/types" "^7.4.4" - -"@babel/helpers@^7.9.0": - version "7.9.2" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.9.2.tgz#b42a81a811f1e7313b88cba8adc66b3d9ae6c09f" - integrity sha512-JwLvzlXVPjO8eU9c/wF9/zOIN7X6h8DYf7mG4CiFRZRvZNKEF5dQ3H3V+ASkHoIB3mWhatgl5ONhyqHRI6MppA== - dependencies: - "@babel/template" "^7.8.3" - "@babel/traverse" "^7.9.0" - "@babel/types" "^7.9.0" - -"@babel/highlight@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4" - integrity sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw== - dependencies: - chalk "^2.0.0" - esutils "^2.0.2" - js-tokens "^4.0.0" - -"@babel/highlight@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.3.tgz#c633bb34adf07c5c13156692f5922c81ec53f28d" - integrity sha512-Ih9B/u7AtgEnySE2L2F0Xm0GaM729XqqLfHkalTsbjXGyqmf/6M0Cu0WpvqueUlW+xk88BHw9Nkpj49naU+vWw== - dependencies: - "@babel/helper-validator-identifier" "^7.10.3" - chalk "^2.0.0" +"@babel/helper-compilation-targets@^7.23.6": + version "7.23.6" + resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz" + integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ== + dependencies: + "@babel/compat-data" "^7.23.5" + "@babel/helper-validator-option" "^7.23.5" + browserslist "^4.22.2" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-environment-visitor@^7.22.20": + version "7.22.20" + resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz" + integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== + +"@babel/helper-function-name@^7.23.0": + version "7.23.0" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz" + integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== + dependencies: + "@babel/template" "^7.22.15" + "@babel/types" "^7.23.0" + +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-module-imports@^7.22.15": + version "7.22.15" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz" + integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== + dependencies: + "@babel/types" "^7.22.15" + +"@babel/helper-module-transforms@^7.23.3": + version "7.23.3" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz" + integrity sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ== + dependencies: + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-module-imports" "^7.22.15" + "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/helper-validator-identifier" "^7.22.20" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.8.0": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz" + integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== + +"@babel/helper-simple-access@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz" + integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-string-parser@^7.23.4": + version "7.23.4" + resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz" + integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== + +"@babel/helper-validator-identifier@^7.22.20": + version "7.22.20" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz" + integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== + +"@babel/helper-validator-option@^7.23.5": + version "7.23.5" + resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz" + integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== + +"@babel/helpers@^7.23.9": + version "7.23.9" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.9.tgz" + integrity sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ== + dependencies: + "@babel/template" "^7.23.9" + "@babel/traverse" "^7.23.9" + "@babel/types" "^7.23.9" + +"@babel/highlight@^7.23.4": + version "7.23.4" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz" + integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== + dependencies: + "@babel/helper-validator-identifier" "^7.22.20" + chalk "^2.4.2" js-tokens "^4.0.0" -"@babel/highlight@^7.8.3": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.9.0.tgz#4e9b45ccb82b79607271b2979ad82c7b68163079" - integrity sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ== - dependencies: - "@babel/helper-validator-identifier" "^7.9.0" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/parser@^7.1.0", "@babel/parser@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.4.4.tgz#5977129431b8fe33471730d255ce8654ae1250b6" - integrity sha512-5pCS4mOsL+ANsFZGdvNLybx4wtqAZJ0MJjMHxvzI3bvIsz6sQvzW8XX92EYIkiPtIvcfG3Aj+Ir5VNyjnZhP7w== - -"@babel/parser@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.3.tgz#7e71d892b0d6e7d04a1af4c3c79d72c1f10f5315" - integrity sha512-oJtNJCMFdIMwXGmx+KxuaD7i3b8uS7TTFYW/FNG2BT8m+fmGHoiPYoH0Pe3gya07WuFmM5FCDIr1x0irkD/hyA== - -"@babel/parser@^7.7.5", "@babel/parser@^7.8.6", "@babel/parser@^7.9.0": - version "7.9.4" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.9.4.tgz#68a35e6b0319bbc014465be43828300113f2f2e8" - integrity sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA== +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9": + version "7.23.9" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz" + integrity sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA== "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz" integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-bigint@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz" integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-class-properties@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.8.3.tgz#6cb933a8872c8d359bfde69bbeaae5162fd1e8f7" - integrity sha512-UcAyQWg2bAN647Q+O811tG9MrJ38Z10jjhQdKNAL8fsyPzE3cCN/uT+f55cFVY4aGO4jqJAvmqsuY3GQDwAoXg== + version "7.12.13" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== dependencies: - "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-json-strings@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz" integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" +"@babel/plugin-syntax-jsx@^7.7.2": + version "7.23.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz" + integrity sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.8.3.tgz#3995d7d7ffff432f6ddc742b47e730c054599897" - integrity sha512-Zpg2Sgc++37kuFl6ppq2Q7Awc6E6AIW671x5PY8E/f7MCIyPPGK/EoeZXvvY3P42exZ3Q4/t3YOzP/HiN79jDg== + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== dependencies: - "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz" integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-numeric-separator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.8.3.tgz#0e3fb63e09bea1b11e96467271c8308007e7c41f" - integrity sha512-H7dCMAdN83PcCmqmkHB5dtp+Xa9a6LKSvA2hiFBC/5alSHxM5VgWZXFqDi0YFe8XNGT6iCa+z4V4zSt/PdZ7Dw== + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== dependencies: - "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-object-rest-spread@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz" integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-optional-catch-binding@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz" integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-optional-chaining@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz" integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/template@^7.1.0", "@babel/template@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237" - integrity sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.4.4" - "@babel/types" "^7.4.4" - -"@babel/template@^7.3.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.3.tgz#4d13bc8e30bf95b0ce9d175d30306f42a2c9a7b8" - integrity sha512-5BjI4gdtD+9fHZUsaxPHPNpwa+xRkDO7c7JbhYn2afvrkDu5SfAAbi9AIMXw2xEhO/BR35TqiW97IqNvCo/GqA== - dependencies: - "@babel/code-frame" "^7.10.3" - "@babel/parser" "^7.10.3" - "@babel/types" "^7.10.3" - -"@babel/template@^7.7.4", "@babel/template@^7.8.3", "@babel/template@^7.8.6": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b" - integrity sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/parser" "^7.8.6" - "@babel/types" "^7.8.6" - -"@babel/traverse@^7.1.0", "@babel/traverse@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.4.4.tgz#0776f038f6d78361860b6823887d4f3937133fe8" - integrity sha512-Gw6qqkw/e6AGzlyj9KnkabJX7VcubqPtkUQVAwkc0wUMldr3A/hezNB3Rc5eIvId95iSGkGIOe5hh1kMKf951A== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.4.4" - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.4.4" - "@babel/parser" "^7.4.4" - "@babel/types" "^7.4.4" - debug "^4.1.0" +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.7.2": + version "7.23.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz" + integrity sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/template@^7.22.15", "@babel/template@^7.23.9", "@babel/template@^7.3.3": + version "7.23.9" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz" + integrity sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA== + dependencies: + "@babel/code-frame" "^7.23.5" + "@babel/parser" "^7.23.9" + "@babel/types" "^7.23.9" + +"@babel/traverse@^7.23.9": + version "7.23.9" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz" + integrity sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg== + dependencies: + "@babel/code-frame" "^7.23.5" + "@babel/generator" "^7.23.6" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.23.9" + "@babel/types" "^7.23.9" + debug "^4.3.1" globals "^11.1.0" - lodash "^4.17.11" - -"@babel/traverse@^7.7.4", "@babel/traverse@^7.8.6", "@babel/traverse@^7.9.0": - version "7.9.5" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.9.5.tgz#6e7c56b44e2ac7011a948c21e283ddd9d9db97a2" - integrity sha512-c4gH3jsvSuGUezlP6rzSJ6jf8fYjLj3hsMZRx/nX0h+fmHN0w+ekubRrHPqnMec0meycA2nwCsJ7dC8IPem2FQ== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.9.5" - "@babel/helper-function-name" "^7.9.5" - "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/parser" "^7.9.0" - "@babel/types" "^7.9.5" - debug "^4.1.0" - globals "^11.1.0" - lodash "^4.17.13" - -"@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.4.4.tgz#8db9e9a629bb7c29370009b4b779ed93fe57d5f0" - integrity sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ== - dependencies: - esutils "^2.0.2" - lodash "^4.17.11" - to-fast-properties "^2.0.0" - -"@babel/types@^7.10.3", "@babel/types@^7.3.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.3.tgz#6535e3b79fea86a6b09e012ea8528f935099de8e" - integrity sha512-nZxaJhBXBQ8HVoIcGsf9qWep3Oh3jCENK54V4mRF7qaJabVsAYdbTtmSD8WmAp1R6ytPiu5apMwSXyxB1WlaBA== - dependencies: - "@babel/helper-validator-identifier" "^7.10.3" - lodash "^4.17.13" - to-fast-properties "^2.0.0" -"@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.0", "@babel/types@^7.9.5": - version "7.9.5" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.5.tgz#89231f82915a8a566a703b3b20133f73da6b9444" - integrity sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg== +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.6", "@babel/types@^7.23.9", "@babel/types@^7.3.3": + version "7.23.9" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz" + integrity sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q== dependencies: - "@babel/helper-validator-identifier" "^7.9.5" - lodash "^4.17.13" + "@babel/helper-string-parser" "^7.23.4" + "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" "@bcoe/v8-coverage@^0.2.3": version "0.2.3" - resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@cnakazawa/watch@^1.0.3": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.3.tgz#099139eaec7ebf07a27c1786a3ff64f39464d2ef" - integrity sha512-r5160ogAvGyHsal38Kux7YYtodEKOj89RGb28ht1jh3SJb08VwRwAKKJL0bGb04Zd/3r9FL3BFIc3bBidYffCA== +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.7.0" + resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz" + integrity sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw== dependencies: - exec-sh "^0.3.2" - minimist "^1.2.0" + eslint-visitor-keys "^3.4.3" + +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.6.1": + version "4.12.1" + resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz" + integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== + +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.6.0" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@8.57.1", "@eslint/js@^8.56.0": + version "8.57.1" + resolved "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz" + integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== + +"@humanwhocodes/config-array@^0.13.0": + version "0.13.0" + resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz" + integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw== + dependencies: + "@humanwhocodes/object-schema" "^2.0.3" + debug "^4.3.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^2.0.3": + version "2.0.3" + resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== + +"@iarna/toml@2.2.5": + version "2.2.5" + resolved "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz" + integrity sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg== + +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" "@istanbuljs/load-nyc-config@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz#10602de5570baea82f8afbfa2630b24e7a8cfe5b" - integrity sha512-ZR0rq/f/E4f4XcgnDvtMWXCUJpi8eO0rssVhmztsZqLIEFA9UUP9zmpE0VxlM+kv/E1ul2I876Fwil2ayptDVg== + version "1.1.0" + resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== dependencies: camelcase "^5.3.1" find-up "^4.1.0" + get-package-type "^0.1.0" js-yaml "^3.13.1" resolve-from "^5.0.0" "@istanbuljs/schema@^0.1.2": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" - integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== + version "0.1.3" + resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== -"@jest/console@^26.0.1": - version "26.0.1" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-26.0.1.tgz#62b3b2fa8990f3cbffbef695c42ae9ddbc8f4b39" - integrity sha512-9t1KUe/93coV1rBSxMmBAOIK3/HVpwxArCA1CxskKyRiv6o8J70V8C/V3OJminVCTa2M0hQI9AWRd5wxu2dAHw== +"@jest/console@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz" + integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^29.6.3" + "@types/node" "*" chalk "^4.0.0" - jest-message-util "^26.0.1" - jest-util "^26.0.1" + jest-message-util "^29.7.0" + jest-util "^29.7.0" slash "^3.0.0" -"@jest/core@^26.0.1": - version "26.0.1" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.0.1.tgz#aa538d52497dfab56735efb00e506be83d841fae" - integrity sha512-Xq3eqYnxsG9SjDC+WLeIgf7/8KU6rddBxH+SCt18gEpOhAGYC/Mq+YbtlNcIdwjnnT+wDseXSbU0e5X84Y4jTQ== +"@jest/core@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz" + integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== dependencies: - "@jest/console" "^26.0.1" - "@jest/reporters" "^26.0.1" - "@jest/test-result" "^26.0.1" - "@jest/transform" "^26.0.1" - "@jest/types" "^26.0.1" + "@jest/console" "^29.7.0" + "@jest/reporters" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" + ci-info "^3.2.0" exit "^0.1.2" - graceful-fs "^4.2.4" - jest-changed-files "^26.0.1" - jest-config "^26.0.1" - jest-haste-map "^26.0.1" - jest-message-util "^26.0.1" - jest-regex-util "^26.0.0" - jest-resolve "^26.0.1" - jest-resolve-dependencies "^26.0.1" - jest-runner "^26.0.1" - jest-runtime "^26.0.1" - jest-snapshot "^26.0.1" - jest-util "^26.0.1" - jest-validate "^26.0.1" - jest-watcher "^26.0.1" - micromatch "^4.0.2" - p-each-series "^2.1.0" - rimraf "^3.0.0" + graceful-fs "^4.2.9" + jest-changed-files "^29.7.0" + jest-config "^29.7.0" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-resolve-dependencies "^29.7.0" + jest-runner "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + jest-watcher "^29.7.0" + micromatch "^4.0.4" + pretty-format "^29.7.0" slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/environment@^26.0.1": - version "26.0.1" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-26.0.1.tgz#82f519bba71959be9b483675ee89de8c8f72a5c8" - integrity sha512-xBDxPe8/nx251u0VJ2dFAFz2H23Y98qdIaNwnMK6dFQr05jc+Ne/2np73lOAx+5mSBO/yuQldRrQOf6hP1h92g== +"@jest/environment@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz" + integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== + dependencies: + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + +"@jest/expect-utils@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz" + integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== + dependencies: + jest-get-type "^29.6.3" + +"@jest/expect@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz" + integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== dependencies: - "@jest/fake-timers" "^26.0.1" - "@jest/types" "^26.0.1" - jest-mock "^26.0.1" + expect "^29.7.0" + jest-snapshot "^29.7.0" -"@jest/fake-timers@^26.0.1": - version "26.0.1" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-26.0.1.tgz#f7aeff13b9f387e9d0cac9a8de3bba538d19d796" - integrity sha512-Oj/kCBnTKhm7CR+OJSjZty6N1bRDr9pgiYQr4wY221azLz5PHi08x/U+9+QpceAYOWheauLP8MhtSVFrqXQfhg== +"@jest/fake-timers@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz" + integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== dependencies: - "@jest/types" "^26.0.1" - "@sinonjs/fake-timers" "^6.0.1" - jest-message-util "^26.0.1" - jest-mock "^26.0.1" - jest-util "^26.0.1" + "@jest/types" "^29.6.3" + "@sinonjs/fake-timers" "^10.0.2" + "@types/node" "*" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-util "^29.7.0" -"@jest/globals@^26.0.1": - version "26.0.1" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.0.1.tgz#3f67b508a7ce62b6e6efc536f3d18ec9deb19a9c" - integrity sha512-iuucxOYB7BRCvT+TYBzUqUNuxFX1hqaR6G6IcGgEqkJ5x4htNKo1r7jk1ji9Zj8ZMiMw0oB5NaA7k5Tx6MVssA== +"@jest/globals@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz" + integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== dependencies: - "@jest/environment" "^26.0.1" - "@jest/types" "^26.0.1" - expect "^26.0.1" + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/types" "^29.6.3" + jest-mock "^29.7.0" -"@jest/reporters@^26.0.1": - version "26.0.1" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.0.1.tgz#14ae00e7a93e498cec35b0c00ab21c375d9b078f" - integrity sha512-NWWy9KwRtE1iyG/m7huiFVF9YsYv/e+mbflKRV84WDoJfBqUrNRyDbL/vFxQcYLl8IRqI4P3MgPn386x76Gf2g== +"@jest/reporters@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz" + integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== dependencies: "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^26.0.1" - "@jest/test-result" "^26.0.1" - "@jest/transform" "^26.0.1" - "@jest/types" "^26.0.1" + "@jest/console" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + "@types/node" "*" chalk "^4.0.0" collect-v8-coverage "^1.0.0" exit "^0.1.2" - glob "^7.1.2" - graceful-fs "^4.2.4" + glob "^7.1.3" + graceful-fs "^4.2.9" istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^4.0.0" + istanbul-lib-instrument "^6.0.0" istanbul-lib-report "^3.0.0" istanbul-lib-source-maps "^4.0.0" - istanbul-reports "^3.0.2" - jest-haste-map "^26.0.1" - jest-resolve "^26.0.1" - jest-util "^26.0.1" - jest-worker "^26.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + jest-worker "^29.7.0" slash "^3.0.0" - source-map "^0.6.0" string-length "^4.0.1" - terminal-link "^2.0.0" - v8-to-istanbul "^4.1.3" - optionalDependencies: - node-notifier "^7.0.0" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" -"@jest/source-map@^26.0.0": - version "26.0.0" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-26.0.0.tgz#fd7706484a7d3faf7792ae29783933bbf48a4749" - integrity sha512-S2Z+Aj/7KOSU2TfW0dyzBze7xr95bkm5YXNUqqCek+HE0VbNNSNzrRwfIi5lf7wvzDTSS0/ib8XQ1krFNyYgbQ== +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jest/source-map@^29.6.3": + version "29.6.3" + resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz" + integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== + dependencies: + "@jridgewell/trace-mapping" "^0.3.18" callsites "^3.0.0" - graceful-fs "^4.2.4" - source-map "^0.6.0" + graceful-fs "^4.2.9" -"@jest/test-result@^26.0.1": - version "26.0.1" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-26.0.1.tgz#1ffdc1ba4bc289919e54b9414b74c9c2f7b2b718" - integrity sha512-oKwHvOI73ICSYRPe8WwyYPTtiuOAkLSbY8/MfWF3qDEd/sa8EDyZzin3BaXTqufir/O/Gzea4E8Zl14XU4Mlyg== +"@jest/test-result@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz" + integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== dependencies: - "@jest/console" "^26.0.1" - "@jest/types" "^26.0.1" + "@jest/console" "^29.7.0" + "@jest/types" "^29.6.3" "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^26.0.1": - version "26.0.1" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-26.0.1.tgz#b0563424728f3fe9e75d1442b9ae4c11da73f090" - integrity sha512-ssga8XlwfP8YjbDcmVhwNlrmblddMfgUeAkWIXts1V22equp2GMIHxm7cyeD5Q/B0ZgKPK/tngt45sH99yLLGg== - dependencies: - "@jest/test-result" "^26.0.1" - graceful-fs "^4.2.4" - jest-haste-map "^26.0.1" - jest-runner "^26.0.1" - jest-runtime "^26.0.1" - -"@jest/transform@^26.0.1": - version "26.0.1" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-26.0.1.tgz#0e3ecbb34a11cd4b2080ed0a9c4856cf0ceb0639" - integrity sha512-pPRkVkAQ91drKGbzCfDOoHN838+FSbYaEAvBXvKuWeeRRUD8FjwXkqfUNUZL6Ke48aA/1cqq/Ni7kVMCoqagWA== - dependencies: - "@babel/core" "^7.1.0" - "@jest/types" "^26.0.1" - babel-plugin-istanbul "^6.0.0" - chalk "^4.0.0" - convert-source-map "^1.4.0" - fast-json-stable-stringify "^2.0.0" - graceful-fs "^4.2.4" - jest-haste-map "^26.0.1" - jest-regex-util "^26.0.0" - jest-util "^26.0.1" - micromatch "^4.0.2" - pirates "^4.0.1" +"@jest/test-sequencer@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz" + integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== + dependencies: + "@jest/test-result" "^29.7.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" slash "^3.0.0" - source-map "^0.6.1" - write-file-atomic "^3.0.0" -"@jest/types@^25.3.0": - version "25.3.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-25.3.0.tgz#88f94b277a1d028fd7117bc1f74451e0fc2131e7" - integrity sha512-UkaDNewdqXAmCDbN2GlUM6amDKS78eCqiw/UmF5nE0mmLTd6moJkiZJML/X52Ke3LH7Swhw883IRXq8o9nWjVw== +"@jest/transform@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz" + integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^1.1.1" - "@types/yargs" "^15.0.0" - chalk "^3.0.0" + "@babel/core" "^7.11.6" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.2" -"@jest/types@^26.0.1": - version "26.0.1" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.0.1.tgz#b78333fbd113fa7aec8d39de24f88de8686dac67" - integrity sha512-IbtjvqI9+eS1qFnOIEL7ggWmT+iK/U+Vde9cGWtYb/b6XgKb3X44ZAe/z9YZzoAAZ/E92m0DqrilF934IGNnQA== +"@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== dependencies: + "@jest/schemas" "^29.6.3" "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^1.1.1" - "@types/yargs" "^15.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" chalk "^4.0.0" +"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": + version "0.3.3" + resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.1" + resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/source-map@^0.3.3": + version "0.3.5" + resolved "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz" + integrity sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15": + version "1.4.15" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.22" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz" + integrity sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@ljharb/through@^2.3.11": + version "2.3.12" + resolved "https://registry.npmjs.org/@ljharb/through/-/through-2.3.12.tgz" + integrity sha512-ajo/heTlG3QgC8EGP6APIejksVAYt4ayz4tqoP3MolFELzcH1x1fzwEYRJTPO0IELutZ5HQ0c26/GqAYy79u3g== + dependencies: + call-bind "^1.0.5" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@octokit/auth-token@^4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz" + integrity sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA== + +"@octokit/core@^5.0.0": + version "5.1.0" + resolved "https://registry.npmjs.org/@octokit/core/-/core-5.1.0.tgz" + integrity sha512-BDa2VAMLSh3otEiaMJ/3Y36GU4qf6GI+VivQ/P41NC6GHcdxpKlqV0ikSZ5gdQsmS3ojXeRx5vasgNTinF0Q4g== + dependencies: + "@octokit/auth-token" "^4.0.0" + "@octokit/graphql" "^7.0.0" + "@octokit/request" "^8.0.2" + "@octokit/request-error" "^5.0.0" + "@octokit/types" "^12.0.0" + before-after-hook "^2.2.0" + universal-user-agent "^6.0.0" + +"@octokit/endpoint@^9.0.0": + version "9.0.4" + resolved "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.4.tgz" + integrity sha512-DWPLtr1Kz3tv8L0UvXTDP1fNwM0S+z6EJpRcvH66orY6Eld4XBMCSYsaWp4xIm61jTWxK68BrR7ibO+vSDnZqw== + dependencies: + "@octokit/types" "^12.0.0" + universal-user-agent "^6.0.0" + +"@octokit/graphql@^7.0.0": + version "7.0.2" + resolved "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.0.2.tgz" + integrity sha512-OJ2iGMtj5Tg3s6RaXH22cJcxXRi7Y3EBqbHTBRq+PQAqfaS8f/236fUrWhfSn8P4jovyzqucxme7/vWSSZBX2Q== + dependencies: + "@octokit/request" "^8.0.1" + "@octokit/types" "^12.0.0" + universal-user-agent "^6.0.0" + +"@octokit/openapi-types@^19.1.0": + version "19.1.0" + resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-19.1.0.tgz" + integrity sha512-6G+ywGClliGQwRsjvqVYpklIfa7oRPA0vyhPQG/1Feh+B+wU0vGH1JiJ5T25d3g1JZYBHzR2qefLi9x8Gt+cpw== + +"@octokit/plugin-paginate-rest@^9.0.0": + version "9.1.5" + resolved "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.1.5.tgz" + integrity sha512-WKTQXxK+bu49qzwv4qKbMMRXej1DU2gq017euWyKVudA6MldaSSQuxtz+vGbhxV4CjxpUxjZu6rM2wfc1FiWVg== + dependencies: + "@octokit/types" "^12.4.0" + +"@octokit/plugin-request-log@^4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-4.0.0.tgz" + integrity sha512-2uJI1COtYCq8Z4yNSnM231TgH50bRkheQ9+aH8TnZanB6QilOnx8RMD2qsnamSOXtDj0ilxvevf5fGsBhBBzKA== + +"@octokit/plugin-rest-endpoint-methods@^10.0.0": + version "10.2.0" + resolved "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-10.2.0.tgz" + integrity sha512-ePbgBMYtGoRNXDyKGvr9cyHjQ163PbwD0y1MkDJCpkO2YH4OeXX40c4wYHKikHGZcpGPbcRLuy0unPUuafco8Q== + dependencies: + "@octokit/types" "^12.3.0" + +"@octokit/request-error@^5.0.0": + version "5.0.1" + resolved "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.0.1.tgz" + integrity sha512-X7pnyTMV7MgtGmiXBwmO6M5kIPrntOXdyKZLigNfQWSEQzVxR4a4vo49vJjTWX70mPndj8KhfT4Dx+2Ng3vnBQ== + dependencies: + "@octokit/types" "^12.0.0" + deprecation "^2.0.0" + once "^1.4.0" + +"@octokit/request@^8.0.1", "@octokit/request@^8.0.2": + version "8.1.6" + resolved "https://registry.npmjs.org/@octokit/request/-/request-8.1.6.tgz" + integrity sha512-YhPaGml3ncZC1NfXpP3WZ7iliL1ap6tLkAp6MvbK2fTTPytzVUyUesBBogcdMm86uRYO5rHaM1xIWxigWZ17MQ== + dependencies: + "@octokit/endpoint" "^9.0.0" + "@octokit/request-error" "^5.0.0" + "@octokit/types" "^12.0.0" + universal-user-agent "^6.0.0" + +"@octokit/rest@20.0.2": + version "20.0.2" + resolved "https://registry.npmjs.org/@octokit/rest/-/rest-20.0.2.tgz" + integrity sha512-Ux8NDgEraQ/DMAU1PlAohyfBBXDwhnX2j33Z1nJNziqAfHi70PuxkFYIcIt8aIAxtRE7KVuKp8lSR8pA0J5iOQ== + dependencies: + "@octokit/core" "^5.0.0" + "@octokit/plugin-paginate-rest" "^9.0.0" + "@octokit/plugin-request-log" "^4.0.0" + "@octokit/plugin-rest-endpoint-methods" "^10.0.0" + +"@octokit/types@^12.0.0", "@octokit/types@^12.3.0", "@octokit/types@^12.4.0": + version "12.4.0" + resolved "https://registry.npmjs.org/@octokit/types/-/types-12.4.0.tgz" + integrity sha512-FLWs/AvZllw/AGVs+nJ+ELCDZZJk+kY0zMen118xhL2zD0s1etIUHm1odgjP7epxYU1ln7SZxEUWYop5bhsdgQ== + dependencies: + "@octokit/openapi-types" "^19.1.0" + "@pdf-lib/fontkit@^1.1.0": version "1.1.1" - resolved "https://registry.yarnpkg.com/@pdf-lib/fontkit/-/fontkit-1.1.1.tgz#f18473892b65e3253eb73f4569785abd2c03b1e0" + resolved "https://registry.npmjs.org/@pdf-lib/fontkit/-/fontkit-1.1.1.tgz" integrity sha512-KjMd7grNapIWS/Dm0gvfHEilSyAmeLvrEGVcqLGi0VYebuqqzTbgF29efCx7tvx+IEbG3zQciRSWl3GkUSvjZg== dependencies: pako "^1.0.6" "@pdf-lib/standard-fonts@^1.0.0": version "1.0.0" - resolved "https://registry.yarnpkg.com/@pdf-lib/standard-fonts/-/standard-fonts-1.0.0.tgz#8ba691c4421f71662ed07c9a0294b44528af2d7f" + resolved "https://registry.npmjs.org/@pdf-lib/standard-fonts/-/standard-fonts-1.0.0.tgz" integrity sha512-hU30BK9IUN/su0Mn9VdlVKsWBS6GyhVfqjwl1FjZN4TxP6cCw0jP2w7V3Hf5uX7M0AZJ16vey9yE0ny7Sa59ZA== dependencies: pako "^1.0.6" -"@pdf-lib/upng@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@pdf-lib/upng/-/upng-1.0.1.tgz#7dc9c636271aca007a9df4deaf2dd7e7960280cb" - integrity sha512-dQK2FUMQtowVP00mtIksrlZhdFXQZPC+taih1q4CvPZ5vqdxR/LKBaFg0oAfzd1GlHZXXSPdQfzQnt+ViGvEIQ== +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + +"@pkgr/core@^0.2.3": + version "0.2.4" + resolved "https://registry.npmjs.org/@pkgr/core/-/core-0.2.4.tgz" + integrity sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw== + +"@pnpm/config.env-replace@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz" + integrity sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w== + +"@pnpm/network.ca-file@^1.0.1": + version "1.0.2" + resolved "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz" + integrity sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA== dependencies: - pako "^1.0.10" + graceful-fs "4.2.10" -"@rollup/plugin-commonjs@^13.0.0": - version "13.0.0" - resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-13.0.0.tgz#8a1d684ba6848afe8b9e3d85649d4b2f6f7217ec" - integrity sha512-Anxc3qgkAi7peAyesTqGYidG5GRim9jtg8xhmykNaZkImtvjA7Wsqep08D2mYsqw1IF7rA3lYfciLgzUSgRoqw== +"@pnpm/npm-conf@^2.1.0": + version "2.2.2" + resolved "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz" + integrity sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA== + dependencies: + "@pnpm/config.env-replace" "^1.1.0" + "@pnpm/network.ca-file" "^1.0.1" + config-chain "^1.1.11" + +"@rollup/plugin-commonjs@^25.0.7": + version "25.0.7" + resolved "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.7.tgz" + integrity sha512-nEvcR+LRjEjsaSsc4x3XZfCCvZIaSMenZu/OiwOKGN2UhQpAYI7ru7czFvyWbErlpoGjnSX3D5Ch5FcMA3kRWQ== dependencies: - "@rollup/pluginutils" "^3.0.8" + "@rollup/pluginutils" "^5.0.1" commondir "^1.0.1" - estree-walker "^1.0.1" - glob "^7.1.2" - is-reference "^1.1.2" - magic-string "^0.25.2" - resolve "^1.11.0" + estree-walker "^2.0.2" + glob "^8.0.3" + is-reference "1.2.1" + magic-string "^0.30.3" -"@rollup/plugin-json@^4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@rollup/plugin-json/-/plugin-json-4.1.0.tgz#54e09867ae6963c593844d8bd7a9c718294496f3" - integrity sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw== +"@rollup/plugin-json@^6.1.0": + version "6.1.0" + resolved "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz" + integrity sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA== dependencies: - "@rollup/pluginutils" "^3.0.8" + "@rollup/pluginutils" "^5.1.0" -"@rollup/plugin-node-resolve@^8.0.1": - version "8.0.1" - resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-8.0.1.tgz#364b5938808ee6b5164dea5ef7291be3f7395199" - integrity sha512-KIeAmueDDaYMqMBnUngLVVZhURwxA12nq/YB6nGm5/JpVyOMwI1fCVU3oL/dAnnLBG7oiPXntO5LHOiMrfNXCA== +"@rollup/plugin-node-resolve@^15.2.3": + version "15.2.3" + resolved "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz" + integrity sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ== dependencies: - "@rollup/pluginutils" "^3.0.8" - "@types/resolve" "0.0.8" - builtin-modules "^3.1.0" - deep-freeze "^0.0.1" + "@rollup/pluginutils" "^5.0.1" + "@types/resolve" "1.20.2" deepmerge "^4.2.2" + is-builtin-module "^3.2.1" is-module "^1.0.0" - resolve "^1.14.2" + resolve "^1.22.1" -"@rollup/pluginutils@^3.0.8": - version "3.0.9" - resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.0.9.tgz#aa6adca2c45e5a1b950103a999e3cddfe49fd775" - integrity sha512-TLZavlfPAZYI7v33wQh4mTP6zojne14yok3DNSLcjoG/Hirxfkonn6icP5rrNWRn8nZsirJBFFpijVOJzkUHDg== +"@rollup/plugin-terser@^0.4.4": + version "0.4.4" + resolved "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz" + integrity sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A== dependencies: - "@types/estree" "0.0.39" - estree-walker "^1.0.1" - micromatch "^4.0.2" + serialize-javascript "^6.0.1" + smob "^1.0.0" + terser "^5.17.4" + +"@rollup/pluginutils@^5.0.1", "@rollup/pluginutils@^5.1.0": + version "5.1.0" + resolved "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz" + integrity sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g== + dependencies: + "@types/estree" "^1.0.0" + estree-walker "^2.0.2" + picomatch "^2.3.1" + +"@rollup/rollup-android-arm-eabi@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.6.tgz#66b8d9cb2b3a474d115500f9ebaf43e2126fe496" + integrity sha512-MVNXSSYN6QXOulbHpLMKYi60ppyO13W9my1qogeiAqtjb2yR4LSmfU2+POvDkLzhjYLXz9Rf9+9a3zFHW1Lecg== + +"@rollup/rollup-android-arm64@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.6.tgz#46327d5b86420d2307946bec1535fdf00356e47d" + integrity sha512-T14aNLpqJ5wzKNf5jEDpv5zgyIqcpn1MlwCrUXLrwoADr2RkWA0vOWP4XxbO9aiO3dvMCQICZdKeDrFl7UMClw== + +"@rollup/rollup-darwin-arm64@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.6.tgz#166987224d2f8b1e2fd28ee90c447d52271d5e90" + integrity sha512-CqNNAyhRkTbo8VVZ5R85X73H3R5NX9ONnKbXuHisGWC0qRbTTxnF1U4V9NafzJbgGM0sHZpdO83pLPzq8uOZFw== + +"@rollup/rollup-darwin-x64@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.6.tgz#a2e6e096f74ccea6e2f174454c26aef6bcdd1274" + integrity sha512-zRDtdJuRvA1dc9Mp6BWYqAsU5oeLixdfUvkTHuiYOHwqYuQ4YgSmi6+/lPvSsqc/I0Omw3DdICx4Tfacdzmhog== + +"@rollup/rollup-linux-arm-gnueabihf@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.6.tgz#09fcd4c55a2d6160c5865fec708a8e5287f30515" + integrity sha512-oNk8YXDDnNyG4qlNb6is1ojTOGL/tRhbbKeE/YuccItzerEZT68Z9gHrY3ROh7axDc974+zYAPxK5SH0j/G+QQ== + +"@rollup/rollup-linux-arm64-gnu@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.6.tgz#19a3c0b6315c747ca9acf86e9b710cc2440f83c9" + integrity sha512-Z3O60yxPtuCYobrtzjo0wlmvDdx2qZfeAWTyfOjEDqd08kthDKexLpV97KfAeUXPosENKd8uyJMRDfFMxcYkDQ== + +"@rollup/rollup-linux-arm64-musl@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.6.tgz#94aaf95fdaf2ad9335983a4552759f98e6b2e850" + integrity sha512-gpiG0qQJNdYEVad+1iAsGAbgAnZ8j07FapmnIAQgODKcOTjLEWM9sRb+MbQyVsYCnA0Im6M6QIq6ax7liws6eQ== + +"@rollup/rollup-linux-riscv64-gnu@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.6.tgz#160510e63f4b12618af4013bddf1761cf9fc9880" + integrity sha512-+uCOcvVmFUYvVDr27aiyun9WgZk0tXe7ThuzoUTAukZJOwS5MrGbmSlNOhx1j80GdpqbOty05XqSl5w4dQvcOA== + +"@rollup/rollup-linux-x64-gnu@4.9.6": + version "4.9.6" + resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.6.tgz" + integrity sha512-HUNqM32dGzfBKuaDUBqFB7tP6VMN74eLZ33Q9Y1TBqRDn+qDonkAUyKWwF9BR9unV7QUzffLnz9GrnKvMqC/fw== + +"@rollup/rollup-linux-x64-musl@4.9.6": + version "4.9.6" + resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.6.tgz" + integrity sha512-ch7M+9Tr5R4FK40FHQk8VnML0Szi2KRujUgHXd/HjuH9ifH72GUmw6lStZBo3c3GB82vHa0ZoUfjfcM7JiiMrQ== + +"@rollup/rollup-win32-arm64-msvc@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.6.tgz#1cc3416682e5a20d8f088f26657e6e47f8db468e" + integrity sha512-VD6qnR99dhmTQ1mJhIzXsRcTBvTjbfbGGwKAHcu+52cVl15AC/kplkhxzW/uT0Xl62Y/meBKDZvoJSJN+vTeGA== + +"@rollup/rollup-win32-ia32-msvc@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.6.tgz#7d2251e1aa5e8a1e47c86891fe4547a939503461" + integrity sha512-J9AFDq/xiRI58eR2NIDfyVmTYGyIZmRcvcAoJ48oDld/NTR8wyiPUu2X/v1navJ+N/FGg68LEbX3Ejd6l8B7MQ== + +"@rollup/rollup-win32-x64-msvc@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.6.tgz#2c1fb69e02a3f1506f52698cfdc3a8b6386df9a6" + integrity sha512-jqzNLhNDvIZOrt69Ce4UjGRpXJBzhUBzawMwnaDAwyHriki3XollsewxWzOzz+4yOFDkuJHtTsZFwMxhYJWmLQ== + +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + +"@sindresorhus/is@^5.2.0": + version "5.6.0" + resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz" + integrity sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g== + +"@sindresorhus/merge-streams@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-1.0.0.tgz" + integrity sha512-rUV5WyJrJLoloD4NDN1V1+LDMDWOa4OTsT4yYJwQNpTU6FWxkxHpL7eu4w+DmiH8x/EAM1otkPE1+LaspIbplw== -"@sinonjs/commons@^1.7.0": - version "1.7.2" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.7.2.tgz#505f55c74e0272b43f6c52d81946bed7058fc0e2" - integrity sha512-+DUO6pnp3udV/v2VfUWgaY5BIE1IfT7lLfeDzPVeMT1XKkaAp9LgSI9x5RtrFQoZ9Oi0PgXQQHPaoKu7dCjVxw== +"@sinonjs/commons@^3.0.0": + version "3.0.1" + resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz" + integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== dependencies: type-detect "4.0.8" -"@sinonjs/fake-timers@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40" - integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA== +"@sinonjs/fake-timers@^10.0.2": + version "10.3.0" + resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz" + integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== dependencies: - "@sinonjs/commons" "^1.7.0" + "@sinonjs/commons" "^3.0.0" -"@types/babel__core@^7.1.7": - version "7.1.7" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.7.tgz#1dacad8840364a57c98d0dd4855c6dd3752c6b89" - integrity sha512-RL62NqSFPCDK2FM1pSDH0scHpJvsXtZNiYlMB73DgPBaG1E38ZYVL+ei5EkWRbr+KC4YNiAUNBnRj+bgwpgjMw== +"@szmarczak/http-timer@^5.0.1": + version "5.0.1" + resolved "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz" + integrity sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw== dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" + defer-to-connect "^2.0.1" + +"@tootallnate/quickjs-emscripten@^0.23.0": + version "0.23.0" + resolved "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz" + integrity sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA== + +"@types/babel__core@^7.1.14": + version "7.20.5" + resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" "@types/babel__generator" "*" "@types/babel__template" "*" "@types/babel__traverse" "*" "@types/babel__generator@*": - version "7.0.2" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.0.2.tgz#d2112a6b21fad600d7674274293c85dce0cb47fc" - integrity sha512-NHcOfab3Zw4q5sEE2COkpfXjoE7o+PmqD9DQW4koUT3roNxwziUdXGnRndMat/LJNUtePwn1TlP4do3uoe3KZQ== + version "7.6.8" + resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz" + integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw== dependencies: "@babel/types" "^7.0.0" "@types/babel__template@*": - version "7.0.2" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.0.2.tgz#4ff63d6b52eddac1de7b975a5223ed32ecea9307" - integrity sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg== + version "7.4.4" + resolved "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" "@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": - version "7.0.6" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.0.6.tgz#328dd1a8fc4cfe3c8458be9477b219ea158fd7b2" - integrity sha512-XYVgHF2sQ0YblLRMLNPB3CkFMewzFmlDsH/TneZFHUXDlABQgh88uOxuez7ZcXxayLFrqLwtDH1t+FmlFwNZxw== + version "7.20.5" + resolved "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz" + integrity sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ== dependencies: - "@babel/types" "^7.3.0" + "@babel/types" "^7.20.7" -"@types/color-name@^1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" - integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== +"@types/color-convert@*": + version "2.0.3" + resolved "https://registry.npmjs.org/@types/color-convert/-/color-convert-2.0.3.tgz" + integrity sha512-2Q6wzrNiuEvYxVQqhh7sXM2mhIhvZR/Paq4FdsQkOMgWsCIkKvSGj8Le1/XalulrmgOzPMqNa0ix+ePY4hTrfg== + dependencies: + "@types/color-name" "*" -"@types/estree@0.0.39": - version "0.0.39" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" - integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== +"@types/color-name@*": + version "1.1.3" + resolved "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.3.tgz" + integrity sha512-87W6MJCKZYDhLAx/J1ikW8niMvmGRyY+rpUxWpL1cO7F8Uu5CHuQoFv+R0/L5pgNdW4jTyda42kv60uwVIPjLw== -"@types/graceful-fs@^4.1.2": - version "4.1.3" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.3.tgz#039af35fe26bec35003e8d86d2ee9c586354348f" - integrity sha512-AiHRaEB50LQg0pZmm659vNBb9f4SJ0qrAnteuzhSeAUcJKxoYgEnprg/83kppCnc2zvtCKbdZry1a5pVY3lOTQ== +"@types/color@^3.0.1": + version "3.0.6" + resolved "https://registry.npmjs.org/@types/color/-/color-3.0.6.tgz" + integrity sha512-NMiNcZFRUAiUUCCf7zkAelY8eV3aKqfbzyFQlXpPIEeoNDbsEHGpb854V3gzTsGKYj830I5zPuOwU/TP5/cW6A== + dependencies: + "@types/color-convert" "*" + +"@types/crypto-js@^4.2.2": + version "4.2.2" + resolved "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.2.tgz" + integrity sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ== + +"@types/estree@*", "@types/estree@1.0.5", "@types/estree@^1.0.0": + version "1.0.5" + resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz" + integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== + +"@types/graceful-fs@^4.1.3": + version "4.1.9" + resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz" + integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== dependencies: "@types/node" "*" +"@types/http-cache-semantics@^4.0.2": + version "4.0.4" + resolved "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz" + integrity sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA== + "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff" - integrity sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg== + version "2.0.6" + resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== "@types/istanbul-lib-report@*": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz#e5471e7fa33c61358dd38426189c037a58433b8c" - integrity sha512-3BUTyMzbZa2DtDI2BkERNC6jJw2Mr2Y0oGI7mRxYNBPxppbtEK1F66u3bKwU2g+wxwWI7PAoRpJnOY1grJqzHg== + version "3.0.3" + resolved "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== dependencies: "@types/istanbul-lib-coverage" "*" -"@types/istanbul-reports@^1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz#7a8cbf6a406f36c8add871625b278eaf0b0d255a" - integrity sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA== +"@types/istanbul-reports@^3.0.0": + version "3.0.4" + resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== dependencies: - "@types/istanbul-lib-coverage" "*" "@types/istanbul-lib-report" "*" -"@types/jest@^26.0.0": - version "26.0.0" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.0.tgz#a6d7573dffa9c68cbbdf38f2e0de26f159e11134" - integrity sha512-/yeMsH9HQ1RLORlXAwoLXe8S98xxvhNtUz3yrgrwbaxYjT+6SFPZZRksmRKRA6L5vsUtSHeN71viDOTTyYAD+g== +"@types/jest@^29.5.12": + version "29.5.12" + resolved "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz" + integrity sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw== dependencies: - jest-diff "^25.2.1" - pretty-format "^25.2.1" + expect "^29.0.0" + pretty-format "^29.0.0" "@types/node-fetch@^2.5.7": - version "2.5.7" - resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c" - integrity sha512-o2WVNf5UhWRkxlf6eq+jMZDu7kjgpgJfl4xVNlvryc95O/6F2ld8ztKX+qu+Rjyet93WAWm5LjeX9H5FGkODvw== + version "2.6.11" + resolved "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz" + integrity sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g== dependencies: "@types/node" "*" - form-data "^3.0.0" + form-data "^4.0.0" "@types/node@*": - version "12.0.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.0.0.tgz#d11813b9c0ff8aaca29f04cbc12817f4c7d656e5" - integrity sha512-Jrb/x3HT4PTJp6a4avhmJCDEVrPdqLfl3e8GGMbpkGGdwAV5UGlIs4vVEfsHHfylZVOKZWpOqmqFH8CbfOZ6kg== - -"@types/normalize-package-data@^2.4.0": - version "2.4.0" - resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" - integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA== + version "20.11.13" + resolved "https://registry.npmjs.org/@types/node/-/node-20.11.13.tgz" + integrity sha512-5G4zQwdiQBSWYTDAH1ctw2eidqdhMJaNsiIDKHFr55ihz5Trl2qqR8fdrT732yPBho5gkNxXm67OxWFBqX9aPg== + dependencies: + undici-types "~5.26.4" "@types/pako@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@types/pako/-/pako-1.0.1.tgz#33b237f3c9aff44d0f82fe63acffa4a365ef4a61" - integrity sha512-GdZbRSJ3Cv5fiwT6I0SQ3ckeN2PWNqxd26W9Z2fCK1tGrrasGy4puvNFtnddqH9UJFMQYXxEuuB7B8UK+LLwSg== + version "1.0.7" + resolved "https://registry.npmjs.org/@types/pako/-/pako-1.0.7.tgz" + integrity sha512-YBtzT2ztNF6R/9+UXj2wTGFnC9NklAnASt3sC0h2m1bbH7G6FyBIkt4AN8ThZpNfxUo1b2iMVO0UawiJymEt8A== -"@types/prettier@^2.0.0": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.0.1.tgz#b6e98083f13faa1e5231bfa3bdb1b0feff536b6d" - integrity sha512-boy4xPNEtiw6N3abRhBi/e7hNvy3Tt8E9ZRAQrwAGzoCGZS/1wjo9KY7JHhnfnEsG5wSjDbymCozUM9a3ea7OQ== +"@types/parse-json@^4.0.0": + version "4.0.2" + resolved "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz" + integrity sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw== -"@types/resolve@0.0.8": - version "0.0.8" - resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194" - integrity sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ== - dependencies: - "@types/node" "*" +"@types/resolve@1.20.2": + version "1.20.2" + resolved "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz" + integrity sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q== -"@types/stack-utils@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" - integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== +"@types/stack-utils@^2.0.0": + version "2.0.3" + resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz" + integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== "@types/yargs-parser@*": - version "13.0.0" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-13.0.0.tgz#453743c5bbf9f1bed61d959baab5b06be029b2d0" - integrity sha512-wBlsw+8n21e6eTd4yVv8YD/E3xq0O6nNnJIquutAsFGE7EyMKz7W6RNT6BRu1SmdgmlCZ9tb0X+j+D6HGr8pZw== + version "21.0.3" + resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== -"@types/yargs@^15.0.0": - version "15.0.4" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.4.tgz#7e5d0f8ca25e9d5849f2ea443cf7c402decd8299" - integrity sha512-9T1auFmbPZoxHz0enUFlUuKRy3it01R+hlggyVUMtnCTQRunsQYifnSGb8hET4Xo8yiC0o0r1paW3ud5+rbURg== +"@types/yargs@^17.0.8": + version "17.0.32" + resolved "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz" + integrity sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog== dependencies: "@types/yargs-parser" "*" -"@zerollup/ts-helpers@^1.7.18": - version "1.7.18" - resolved "https://registry.yarnpkg.com/@zerollup/ts-helpers/-/ts-helpers-1.7.18.tgz#747177f6d5abc06c3a0f5dffe7362d365cf0391d" - integrity sha512-S9zN+y+i5yN/evfWquzSO3lubqPXIsPQf6p9OiPMpRxDx/0totPLF39XoRw48Dav5dSvbIE8D2eAPpXXJxvKwg== - dependencies: - resolve "^1.12.0" +"@typescript-eslint/eslint-plugin@^7.0.0": + version "7.18.0" + resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz" + integrity sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "7.18.0" + "@typescript-eslint/type-utils" "7.18.0" + "@typescript-eslint/utils" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" + graphemer "^1.4.0" + ignore "^5.3.1" + natural-compare "^1.4.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/parser@^7.0.0": + version "7.18.0" + resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz" + integrity sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg== + dependencies: + "@typescript-eslint/scope-manager" "7.18.0" + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/typescript-estree" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@7.18.0": + version "7.18.0" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz" + integrity sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA== + dependencies: + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" + +"@typescript-eslint/type-utils@7.18.0": + version "7.18.0" + resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz" + integrity sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA== + dependencies: + "@typescript-eslint/typescript-estree" "7.18.0" + "@typescript-eslint/utils" "7.18.0" + debug "^4.3.4" + ts-api-utils "^1.3.0" + +"@typescript-eslint/types@7.18.0": + version "7.18.0" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz" + integrity sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ== + +"@typescript-eslint/typescript-estree@7.18.0": + version "7.18.0" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz" + integrity sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA== + dependencies: + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/utils@7.18.0": + version "7.18.0" + resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz" + integrity sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "7.18.0" + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/typescript-estree" "7.18.0" + +"@typescript-eslint/visitor-keys@7.18.0": + version "7.18.0" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz" + integrity sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg== + dependencies: + "@typescript-eslint/types" "7.18.0" + eslint-visitor-keys "^3.4.3" + +"@ungap/structured-clone@^1.2.0": + version "1.3.0" + resolved "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz" + integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== -"@zerollup/ts-transform-paths@^1.7.18": - version "1.7.18" - resolved "https://registry.yarnpkg.com/@zerollup/ts-transform-paths/-/ts-transform-paths-1.7.18.tgz#72f705c66690879e51d53c73dc76c4e2518a8c50" - integrity sha512-YPVUxvWQVzRx1OBN0Pmkd58+R9FcfUJuwTaPUSoi5rKxuXMtxevTXdfi0w5mEaIH8b0DfL+wg0wFDHiJE+S2zA== - dependencies: - "@zerollup/ts-helpers" "^1.7.18" +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -abab@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.3.tgz#623e2075e02eb2d3f2475e49f99c91846467907a" - integrity sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg== +acorn@^8.8.2, acorn@^8.9.0: + version "8.14.1" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz" + integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg== -acorn-globals@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" - integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== +agent-base@^7.0.2, agent-base@^7.1.0: + version "7.1.0" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz" + integrity sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg== dependencies: - acorn "^7.1.1" - acorn-walk "^7.1.1" - -acorn-walk@^7.1.1: - version "7.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" - integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== + debug "^4.3.4" -acorn@^7.1.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.3.1.tgz#85010754db53c3fbaf3b9ea3e083aa5c5d147ffd" - integrity sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA== - -ajv@^6.5.5: - version "6.10.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1" - integrity sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg== +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== dependencies: - fast-deep-equal "^2.0.1" + fast-deep-equal "^3.1.1" fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ansi-escapes@^4.2.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" - integrity sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA== +ansi-align@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz" + integrity sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w== dependencies: - type-fest "^0.11.0" + string-width "^4.1.0" -ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" - integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== +ansi-escapes@^4.2.1, ansi-escapes@^4.3.2: + version "4.3.2" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-escapes@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz" + integrity sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw== + dependencies: + environment "^1.0.0" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== ansi-styles@^3.2.1: version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" - integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== + version "4.3.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: - "@types/color-name" "^1.1.1" color-convert "^2.0.1" -anymatch@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" - integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== - dependencies: - micromatch "^3.1.4" - normalize-path "^2.1.1" +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +ansi-styles@^6.0.0, ansi-styles@^6.1.0, ansi-styles@^6.2.1: + version "6.2.1" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== anymatch@^3.0.3: - version "3.1.1" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" - integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== + version "3.1.3" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== dependencies: normalize-path "^3.0.0" picomatch "^2.0.4" argparse@^1.0.7: version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== dependencies: sprintf-js "~1.0.2" -arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== +array-buffer-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz" + integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== + dependencies: + call-bind "^1.0.2" + is-array-buffer "^3.0.1" -arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= +array.prototype.map@^1.0.5: + version "1.0.6" + resolved "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.6.tgz" + integrity sha512-nK1psgF2cXqP3wSyCSq0Hc7zwNq3sfljQqaG27r/7a7ooNUnn5nGq6yYWyks9jMO5EoFQ0ax80hSg6oXSRNXaw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-array-method-boxes-properly "^1.0.0" + is-string "^1.0.7" -asn1@~0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== +arraybuffer.prototype.slice@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz" + integrity sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw== dependencies: - safer-buffer "~2.1.0" + array-buffer-byte-length "^1.0.0" + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + is-array-buffer "^3.0.2" + is-shared-array-buffer "^1.0.2" -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= +ast-types@^0.13.4: + version "0.13.4" + resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz" + integrity sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w== + dependencies: + tslib "^2.0.1" -assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= +async-retry@1.3.3: + version "1.3.3" + resolved "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz" + integrity sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw== + dependencies: + retry "0.13.1" -async@^2.6.2: - version "2.6.3" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" - integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== +async@^2.6.4: + version "2.6.4" + resolved "https://registry.npmjs.org/async/-/async-2.6.4.tgz" + integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== dependencies: lodash "^4.17.14" asynckit@^0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -atob@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" - integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= - -aws4@^1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" - integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== - -babel-jest@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.0.1.tgz#450139ce4b6c17174b136425bda91885c397bc46" - integrity sha512-Z4GGmSNQ8pX3WS1O+6v3fo41YItJJZsVxG5gIQ+HuB/iuAQBJxMTHTwz292vuYws1LnHfwSRgoqI+nxdy/pcvw== - dependencies: - "@jest/transform" "^26.0.1" - "@jest/types" "^26.0.1" - "@types/babel__core" "^7.1.7" - babel-plugin-istanbul "^6.0.0" - babel-preset-jest "^26.0.0" +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + +babel-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz" + integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== + dependencies: + "@jest/transform" "^29.7.0" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.6.3" chalk "^4.0.0" - graceful-fs "^4.2.4" + graceful-fs "^4.2.9" slash "^3.0.0" -babel-plugin-istanbul@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765" - integrity sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ== +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@istanbuljs/load-nyc-config" "^1.0.0" "@istanbuljs/schema" "^0.1.2" - istanbul-lib-instrument "^4.0.0" + istanbul-lib-instrument "^5.0.4" test-exclude "^6.0.0" -babel-plugin-jest-hoist@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.0.0.tgz#fd1d35f95cf8849fc65cb01b5e58aedd710b34a8" - integrity sha512-+AuoehOrjt9irZL7DOt2+4ZaTM6dlu1s5TTS46JBa0/qem4dy7VNW3tMb96qeEqcIh20LD73TVNtmVEeymTG7w== +babel-plugin-jest-hoist@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz" + integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== dependencies: "@babel/template" "^7.3.3" "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" "@types/babel__traverse" "^7.0.6" -babel-preset-current-node-syntax@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.2.tgz#fb4a4c51fe38ca60fede1dc74ab35eb843cb41d6" - integrity sha512-u/8cS+dEiK1SFILbOC8/rUI3ml9lboKuuMvZ/4aQnQmhecQAgPw5ew066C1ObnEAUmlx7dv/s2z52psWEtLNiw== +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== dependencies: "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-bigint" "^7.8.3" "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" "@babel/plugin-syntax-json-strings" "^7.8.3" "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" @@ -1039,290 +1397,396 @@ babel-preset-current-node-syntax@^0.1.2: "@babel/plugin-syntax-object-rest-spread" "^7.8.3" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" -babel-preset-jest@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-26.0.0.tgz#1eac82f513ad36c4db2e9263d7c485c825b1faa6" - integrity sha512-9ce+DatAa31DpR4Uir8g4Ahxs5K4W4L8refzt+qHWQANb6LhGcAEfIFgLUwk67oya2cCUd6t4eUMtO/z64ocNw== +babel-preset-jest@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz" + integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== dependencies: - babel-plugin-jest-hoist "^26.0.0" - babel-preset-current-node-syntax "^0.1.2" + babel-plugin-jest-hoist "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - -base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - -basic-auth@^1.0.3: - version "1.1.0" - resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-1.1.0.tgz#45221ee429f7ee1e5035be3f51533f1cdfd29884" - integrity sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ= - -bcrypt-pbkdf@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +basic-auth@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz" + integrity sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg== dependencies: - tweetnacl "^0.14.3" + safe-buffer "5.1.2" + +basic-ftp@^5.0.2: + version "5.0.4" + resolved "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.4.tgz" + integrity sha512-8PzkB0arJFV4jJWSGOYR+OEic6aeKMu/osRhBULN6RY0ykby6LKhbmuQ5ublvaas5BOwboah5D87nrHyuh8PPA== + +before-after-hook@^2.2.0: + version "2.2.3" + resolved "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz" + integrity sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ== + +bl@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + +boxen@^7.1.1: + version "7.1.1" + resolved "https://registry.npmjs.org/boxen/-/boxen-7.1.1.tgz" + integrity sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog== + dependencies: + ansi-align "^3.0.1" + camelcase "^7.0.1" + chalk "^5.2.0" + cli-boxes "^3.0.0" + string-width "^5.1.2" + type-fest "^2.13.0" + widest-line "^4.0.1" + wrap-ansi "^8.1.0" brace-expansion@^1.1.7: version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - -braces@^3.0.1: +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== dependencies: fill-range "^7.0.1" -browser-process-hrtime@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" - integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +browserslist@^4.22.2: + version "4.22.3" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.22.3.tgz" + integrity sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A== + dependencies: + caniuse-lite "^1.0.30001580" + electron-to-chromium "^1.4.648" + node-releases "^2.0.14" + update-browserslist-db "^1.0.13" bs-logger@0.x: version "0.2.6" - resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + resolved "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz" integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== dependencies: fast-json-stable-stringify "2.x" -bser@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" - integrity sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk= +bser@2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== dependencies: node-int64 "^0.4.0" -buffer-from@1.x, buffer-from@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== -builtin-modules@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" - integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= +buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" -builtin-modules@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.1.0.tgz#aad97c15131eb76b65b50ef208e7584cd76a7484" - integrity sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw== +builtin-modules@^3.3.0: + version "3.3.0" + resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz" + integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== -cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" +bundle-name@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz" + integrity sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q== + dependencies: + run-applescript "^7.0.0" + +cacheable-lookup@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz" + integrity sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w== + +cacheable-request@^10.2.8: + version "10.2.14" + resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz" + integrity sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ== + dependencies: + "@types/http-cache-semantics" "^4.0.2" + get-stream "^6.0.1" + http-cache-semantics "^4.1.1" + keyv "^4.5.3" + mimic-response "^4.0.0" + normalize-url "^8.0.0" + responselike "^3.0.0" + +call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz" + integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== + dependencies: + function-bind "^1.1.2" + get-intrinsic "^1.2.1" + set-function-length "^1.1.1" callsites@^3.0.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -camelcase@^5.0.0, camelcase@^5.3.1: +camelcase@^5.3.1: version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== -camelcase@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.0.0.tgz#5259f7c30e35e278f1bdc2a4d91230b37cad981e" - integrity sha512-8KMDF1Vz2gzOq54ONPJS65IvTUaB1cHJ2DMM7MbPmLZljDH1qpzzLsWdiN9pHh6qvkRVDTi/07+eNGch/oLU4w== +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -capture-exit@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" - integrity sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g== - dependencies: - rsvp "^4.8.4" +camelcase@^7.0.1: + version "7.0.1" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz" + integrity sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw== -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= +caniuse-lite@^1.0.30001580: + version "1.0.30001581" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001581.tgz" + integrity sha512-whlTkwhqV2tUmP3oYhtNfaWGYHDdS3JYFQBKXxcUR9qqPWsRhFHhoISO2Xnl/g0xyKzht9mI1LZpiNWfMzHixQ== -chalk@^2.0.0, chalk@^2.3.0: +chalk@5.3.0, chalk@^5.2.0, chalk@^5.3.0: + version "5.3.0" + resolved "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz" + integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== + +chalk@^2.4.2: version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== dependencies: ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" - integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== dependencies: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" - integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" +chalk@^5.4.1: + version "5.4.1" + resolved "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz" + integrity sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w== char-regex@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + ci-info@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== -class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== +ci-info@^3.2.0: + version "3.9.0" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== + +cjs-module-lexer@^1.0.0: + version "1.2.3" + resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz" + integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== + +cli-boxes@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz" + integrity sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g== + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-cursor@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz" + integrity sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg== dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" + restore-cursor "^4.0.0" -cliui@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" - integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== +cli-cursor@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz" + integrity sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw== + dependencies: + restore-cursor "^5.0.0" + +cli-spinners@^2.5.0, cli-spinners@^2.9.2: + version "2.9.2" + resolved "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz" + integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg== + +cli-truncate@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz" + integrity sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA== + dependencies: + slice-ansi "^5.0.0" + string-width "^7.0.0" + +cli-width@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz" + integrity sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ== + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== dependencies: string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^6.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz" + integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== co@^4.6.0: version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= + resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== collect-v8-coverage@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" - integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== - -collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" + version "1.0.2" + resolved "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz" + integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== color-convert@^1.9.0: version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== dependencies: color-name "1.1.3" color-convert@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== dependencies: color-name "~1.1.4" color-name@1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== -color-name@~1.1.4: +color-name@^1.0.0, color-name@~1.1.4: version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -colors@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" - integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== +color-string@^1.9.0: + version "1.9.1" + resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz" + integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" -combined-stream@^1.0.6, combined-stream@~1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" - integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w== +color@^4.2.3: + version "4.2.3" + resolved "https://registry.npmjs.org/color/-/color-4.2.3.tgz" + integrity sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A== dependencies: - delayed-stream "~1.0.0" + color-convert "^2.0.1" + color-string "^1.9.0" + +colorette@^2.0.20: + version "2.0.20" + resolved "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== combined-stream@^1.0.8: version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== dependencies: delayed-stream "~1.0.0" -commander@^2.12.1, commander@^2.20.0: - version "2.20.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" - integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== +commander@^13.1.0: + version "13.1.0" + resolved "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz" + integrity sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw== + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== commondir@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + resolved "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz" + integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== -component-emitter@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" - integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== +compare-versions@^3.6.0: + version "3.6.0" + resolved "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz" + integrity sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA== concat-map@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== concat-stream@^1.6.2: version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz" integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== dependencies: buffer-from "^1.0.0" @@ -1330,2042 +1794,3024 @@ concat-stream@^1.6.2: readable-stream "^2.2.2" typedarray "^0.0.6" -convert-source-map@^1.1.0, convert-source-map@^1.4.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" - integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A== +config-chain@^1.1.11: + version "1.1.13" + resolved "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz" + integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ== dependencies: - safe-buffer "~5.1.1" + ini "^1.3.4" + proto-list "~1.2.1" -convert-source-map@^1.6.0, convert-source-map@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" - integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== +configstore@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/configstore/-/configstore-6.0.0.tgz" + integrity sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA== dependencies: - safe-buffer "~5.1.1" + dot-prop "^6.0.1" + graceful-fs "^4.2.6" + unique-string "^3.0.0" + write-file-atomic "^3.0.3" + xdg-basedir "^5.0.1" -copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== -core-util-is@1.0.2, core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== corser@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/corser/-/corser-2.0.1.tgz#8eda252ecaab5840dcd975ceb90d9370c819ff87" - integrity sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c= + resolved "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz" + integrity sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ== -cross-spawn@^6.0.0: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== +cosmiconfig@9.0.0: + version "9.0.0" + resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz" + integrity sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg== dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" + env-paths "^2.2.1" + import-fresh "^3.3.0" + js-yaml "^4.1.0" + parse-json "^5.2.0" -cross-spawn@^7.0.0: - version "7.0.2" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.2.tgz#d0d7dcfa74e89115c7619f4f721a94e1fdb716d6" - integrity sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw== +cosmiconfig@^7.0.0: + version "7.1.0" + resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz" + integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.2.1" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.10.0" + +create-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz" + integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-config "^29.7.0" + jest-util "^29.7.0" + prompts "^2.0.1" + +cross-spawn@^7.0.0, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== dependencies: path-key "^3.1.0" shebang-command "^2.0.0" which "^2.0.1" -cssom@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" - integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== +cross-spawn@^7.0.2: + version "7.0.6" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" -cssom@~0.3.6: - version "0.3.8" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" - integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== +crypto-js@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz" + integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q== -cssstyle@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" - integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== +crypto-random-string@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz" + integrity sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA== dependencies: - cssom "~0.3.6" + type-fest "^1.0.1" -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= - dependencies: - assert-plus "^1.0.0" +data-uri-to-buffer@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz" + integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A== -data-urls@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" - integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== - dependencies: - abab "^2.0.3" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.0.0" +data-uri-to-buffer@^6.0.0: + version "6.0.1" + resolved "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.1.tgz" + integrity sha512-MZd3VlchQkp8rdend6vrx7MmVDJzSNTBvghvKjirLkD+WTChA3KUf0jkE68Q4UyctNqI11zZO9/x2Yx+ub5Cvg== -debug@^2.2.0, debug@^2.3.3: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: - ms "2.0.0" + ms "2.1.2" -debug@^3.1.1, debug@^3.2.6: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== +debug@^3.2.7: + version "3.2.7" + resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== dependencies: ms "^2.1.1" -debug@^4.1.0, debug@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== +debug@^4.3.2, debug@^4.4.0: + version "4.4.0" + resolved "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== dependencies: - ms "^2.1.1" - -decamelize@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + ms "^2.1.3" -decimal.js@^10.2.0: - version "10.2.0" - resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.2.0.tgz#39466113a9e036111d02f82489b5fd6b0b5ed231" - integrity sha512-vDPw+rDgn3bZe1+F/pyEwb1oMG2XTlRVgAa6B4KccTEpYgF8w6eQllVbQcfIJnZyvzFtFpxnpGtx8dd7DJp/Rw== +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== + dependencies: + mimic-response "^3.1.0" -decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= +dedent@^1.0.0: + version "1.5.1" + resolved "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz" + integrity sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg== -deep-freeze@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/deep-freeze/-/deep-freeze-0.0.1.tgz#3a0b0005de18672819dfd38cd31f91179c893e84" - integrity sha1-OgsABd4YZygZ39OM0x+RF5yJPoQ= +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== -deep-is@~0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== deepmerge@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" - integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + version "4.3.1" + resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + +default-browser-id@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz" + integrity sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA== -define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= +default-browser@^5.2.1: + version "5.2.1" + resolved "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz" + integrity sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg== dependencies: - is-descriptor "^0.1.0" + bundle-name "^4.1.0" + default-browser-id "^5.0.0" -define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= +defaults@^1.0.3: + version "1.0.4" + resolved "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz" + integrity sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A== dependencies: - is-descriptor "^1.0.0" + clone "^1.0.2" -define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== +defer-to-connect@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz" + integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== + +define-data-property@^1.0.1, define-data-property@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz" + integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ== dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + +define-lazy-prop@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz" + integrity sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg== + +define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +degenerator@^5.0.0: + version "5.0.1" + resolved "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz" + integrity sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ== + dependencies: + ast-types "^0.13.4" + escodegen "^2.1.0" + esprima "^4.0.1" delayed-stream@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +deprecation@^2.0.0: + version "2.3.1" + resolved "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz" + integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== detect-newline@^3.0.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -diff-sequences@^25.2.6: - version "25.2.6" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd" - integrity sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg== +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== -diff-sequences@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.0.0.tgz#0760059a5c287637b842bd7085311db7060e88a6" - integrity sha512-JC/eHYEC3aSS0vZGjuoc4vHA0yAQTzhQQldXMeMF+JlxLGJlCO38Gma82NV9gk1jGFz8mDzUMeaKXvjRRdJ2dg== +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" -diff@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.1.tgz#0c667cb467ebbb5cea7f14f135cc2dba7780a8ff" - integrity sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q== +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" -domexception@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" - integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== +dot-prop@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz" + integrity sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA== dependencies: - webidl-conversions "^5.0.0" + is-obj "^2.0.0" -downlevel-dts@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/downlevel-dts/-/downlevel-dts-0.5.0.tgz#7db798f303f124d0d2dace838fd3ee5cf4bf53b4" - integrity sha512-hGikqjcnlkDXqga55u/jQx0ZdQz9Q3LtSqyceHSYavWOmSUoVUGjWZ/zwfiVMFL8rl+LKvJn9L5uaAq7P7xMNA== +downlevel-dts@^0.11.0: + version "0.11.0" + resolved "https://registry.npmjs.org/downlevel-dts/-/downlevel-dts-0.11.0.tgz" + integrity sha512-vo835pntK7kzYStk7xUHDifiYJvXxVhUapt85uk2AI94gUUAQX9HNRtrcMHNSc3YHJUEHGbYIGsM99uIbgAtxw== dependencies: + semver "^7.3.2" shelljs "^0.8.3" - typescript "^3.8.0-dev.20200111" + typescript next -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== -ecstatic@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/ecstatic/-/ecstatic-3.3.2.tgz#6d1dd49814d00594682c652adb66076a69d46c48" - integrity sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog== - dependencies: - he "^1.1.1" - mime "^1.6.0" - minimist "^1.1.0" - url-join "^2.0.5" +electron-to-chromium@^1.4.648: + version "1.4.652" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.652.tgz" + integrity sha512-XvQaa8hVUAuEJtLw6VKQqvdOxTOfBLWfI10t2xWpezx4XXD3k8bdLweEKeItqaa0+OkJX5l0mP1W+JWobyIDrg== + +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== + +emoji-regex@^10.3.0: + version "10.3.0" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz" + integrity sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw== emoji-regex@^8.0.0: version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== -end-of-stream@^1.1.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" - integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== - dependencies: - once "^1.4.0" +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +env-paths@^2.2.1: + version "2.2.1" + resolved "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz" + integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== + +environment@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz" + integrity sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q== error-ex@^1.3.1: version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== dependencies: is-arrayish "^0.2.1" +es-abstract@^1.22.1: + version "1.22.3" + resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz" + integrity sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA== + dependencies: + array-buffer-byte-length "^1.0.0" + arraybuffer.prototype.slice "^1.0.2" + available-typed-arrays "^1.0.5" + call-bind "^1.0.5" + es-set-tostringtag "^2.0.1" + es-to-primitive "^1.2.1" + function.prototype.name "^1.1.6" + get-intrinsic "^1.2.2" + get-symbol-description "^1.0.0" + globalthis "^1.0.3" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + internal-slot "^1.0.5" + is-array-buffer "^3.0.2" + is-callable "^1.2.7" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-typed-array "^1.1.12" + is-weakref "^1.0.2" + object-inspect "^1.13.1" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.5.1" + safe-array-concat "^1.0.1" + safe-regex-test "^1.0.0" + string.prototype.trim "^1.2.8" + string.prototype.trimend "^1.0.7" + string.prototype.trimstart "^1.0.7" + typed-array-buffer "^1.0.0" + typed-array-byte-length "^1.0.0" + typed-array-byte-offset "^1.0.0" + typed-array-length "^1.0.4" + unbox-primitive "^1.0.2" + which-typed-array "^1.1.13" + +es-array-method-boxes-properly@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz" + integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== + +es-get-iterator@^1.0.2: + version "1.1.3" + resolved "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz" + integrity sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + has-symbols "^1.0.3" + is-arguments "^1.1.1" + is-map "^2.0.2" + is-set "^2.0.2" + is-string "^1.0.7" + isarray "^2.0.5" + stop-iteration-iterator "^1.0.0" + +es-set-tostringtag@^2.0.1: + version "2.0.2" + resolved "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz" + integrity sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q== + dependencies: + get-intrinsic "^1.2.2" + has-tostringtag "^1.0.0" + hasown "^2.0.0" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-goat@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz" + integrity sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg== + escape-string-regexp@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== escape-string-regexp@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== -escodegen@^1.14.1: - version "1.14.2" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.2.tgz#14ab71bf5026c2aa08173afba22c6f3173284a84" - integrity sha512-InuOIiKk8wwuOFg6x9BQXbzjrQhtyXh46K9bqVTPzSo2FnyMBaYGBMC6PhQy7yxxil9vIedFBweQBMK74/7o8A== +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +escape-string-regexp@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz" + integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw== + +escodegen@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz" + integrity sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w== dependencies: esprima "^4.0.1" - estraverse "^4.2.0" + estraverse "^5.2.0" esutils "^2.0.2" - optionator "^0.8.1" optionalDependencies: source-map "~0.6.1" +eslint-config-prettier@^9.1.0: + version "9.1.0" + resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz" + integrity sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw== + +eslint-plugin-prettier@^5.1.3: + version "5.4.0" + resolved "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.4.0.tgz" + integrity sha512-BvQOvUhkVQM1i63iMETK9Hjud9QhqBnbtT1Zc642p9ynzBuCe5pybkOnvqZIBypXmMlsGcnU4HZ8sCTPfpAexA== + dependencies: + prettier-linter-helpers "^1.0.0" + synckit "^0.11.0" + +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint@^8.56.0: + version "8.57.1" + resolved "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz" + integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.57.1" + "@humanwhocodes/config-array" "^0.13.0" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== + dependencies: + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -estraverse@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" - integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= +esquery@^1.4.2: + version "1.6.0" + resolved "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + dependencies: + estraverse "^5.1.0" -estree-walker@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700" - integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg== +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" -esutils@^2.0.2: +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +estree-walker@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" - integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= + resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz" + integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== eventemitter3@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb" - integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg== + version "4.0.7" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== -exec-sh@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.2.tgz#6738de2eb7c8e671d0366aea0b0db8c6f7d7391b" - integrity sha512-9sLAvzhI5nc8TpuQUh4ahMdCrWT00wPWz7j47/emR5+2qEfoZP5zzUXvx+vdx+H6ohhnsYC31iX04QLYJK8zTg== +eventemitter3@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz" + integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== -execa@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" - integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== - dependencies: - cross-spawn "^6.0.0" - get-stream "^4.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -execa@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/execa/-/execa-4.0.2.tgz#ad87fb7b2d9d564f70d2b62d511bee41d5cbb240" - integrity sha512-QI2zLa6CjGWdiQsmSkZoGtDx2N+cQIGb3yNolGTdjSQzydzLgYYf8LRuagp7S7fPimjcrzUDSUFd/MgzELMi4Q== +execa@8.0.1, execa@^8.0.1: + version "8.0.1" + resolved "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz" + integrity sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg== dependencies: - cross-spawn "^7.0.0" - get-stream "^5.0.0" - human-signals "^1.1.1" + cross-spawn "^7.0.3" + get-stream "^8.0.1" + human-signals "^5.0.0" + is-stream "^3.0.0" + merge-stream "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^4.1.0" + strip-final-newline "^3.0.0" + +execa@^5.0.0, execa@^5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" is-stream "^2.0.0" merge-stream "^2.0.0" - npm-run-path "^4.0.0" - onetime "^5.1.0" - signal-exit "^3.0.2" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" strip-final-newline "^2.0.0" exit@^0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= - -expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -expect@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/expect/-/expect-26.0.1.tgz#18697b9611a7e2725e20ba3ceadda49bc9865421" - integrity sha512-QcCy4nygHeqmbw564YxNbHTJlXh47dVID2BUP52cZFpLU9zHViMFK6h07cC1wf7GYCTIigTdAXhVua8Yl1FkKg== - dependencies: - "@jest/types" "^26.0.1" - ansi-styles "^4.0.0" - jest-get-type "^26.0.0" - jest-matcher-utils "^26.0.1" - jest-message-util "^26.0.1" - jest-regex-util "^26.0.0" + resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= +expect@^29.0.0, expect@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz" + integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== dependencies: - is-extendable "^0.1.0" + "@jest/expect-utils" "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" -extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= +external-editor@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" -extend@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -extsprintf@1.3.0: +fast-diff@^1.1.2: version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + resolved "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz" + integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= +fast-glob@^3.2.9: + version "3.3.3" + resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz" + integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.8" -fast-deep-equal@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" - integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= +fast-glob@^3.3.2: + version "3.3.2" + resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" -fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== -fast-levenshtein@~2.0.4: +fast-levenshtein@^2.0.6: version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.17.0" + resolved "https://registry.npmjs.org/fastq/-/fastq-1.17.0.tgz" + integrity sha512-zGygtijUMT7jnk3h26kUms3BkSDp4IfIKjmnqI2tvx6nuBfiF1UqOxbnLfzdv+apBy+53oaImsKtMw/xYbW+1w== + dependencies: + reusify "^1.0.4" fb-watchman@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" - integrity sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg= + version "2.0.2" + resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== dependencies: - bser "^2.0.0" + bser "2.1.1" -fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= +fetch-blob@^3.1.2, fetch-blob@^3.1.4: + version "3.2.0" + resolved "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz" + integrity sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ== dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" + node-domexception "^1.0.0" + web-streams-polyfill "^3.0.3" + +figures@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz" + integrity sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg== + dependencies: + escape-string-regexp "^5.0.0" + is-unicode-supported "^1.2.0" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" fill-range@^7.0.1: version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== dependencies: to-regex-range "^5.0.1" +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== dependencies: locate-path "^5.0.0" path-exists "^4.0.0" +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +find-versions@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/find-versions/-/find-versions-4.0.0.tgz" + integrity sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ== + dependencies: + semver-regex "^3.1.2" + flamebearer@^1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/flamebearer/-/flamebearer-1.1.3.tgz#aac0cb56305e1af2b16528aca649c76103f75c08" + resolved "https://registry.npmjs.org/flamebearer/-/flamebearer-1.1.3.tgz" integrity sha512-3AEti4HwtsVRQTHTB47kQZvXkenSn5YfmpGGZX/mRW8R+9ZDFO+iqgEC4W7Nb8PQvUceYVfbM7nqQxI/m6DeDA== dependencies: concat-stream "^1.6.2" opn "^5.3.0" +flat-cache@^3.0.4: + version "3.2.0" + resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.3" + rimraf "^3.0.2" + +flatted@^3.2.9: + version "3.3.3" + resolved "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz" + integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== + follow-redirects@^1.0.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.7.0.tgz#489ebc198dc0e7f64167bd23b03c4c19b5784c76" - integrity sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ== + version "1.15.5" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz" + integrity sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw== + +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== dependencies: - debug "^3.2.6" + is-callable "^1.1.3" -for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= +foreground-child@^3.1.0: + version "3.1.1" + resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz" + integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= +form-data-encoder@^2.1.2: + version "2.1.4" + resolved "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz" + integrity sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw== -form-data@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682" - integrity sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg== +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== dependencies: asynckit "^0.4.0" combined-stream "^1.0.8" mime-types "^2.1.12" -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== +formdata-polyfill@^4.0.10: + version "4.0.10" + resolved "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz" + integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g== dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" + fetch-blob "^3.1.2" -fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== dependencies: - map-cache "^0.2.2" + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" fs.realpath@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.2.tgz#4c0a1fb34bc68e543b4b82a9ec392bfbda840805" - integrity sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA== +fsevents@^2.3.2, fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== -fsevents@~2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" - integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +function.prototype.name@^1.1.6: + version "1.1.6" + resolved "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz" + integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + functions-have-names "^1.2.3" -gensync@^1.0.0-beta.1: - version "1.0.0-beta.1" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" - integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== +functions-have-names@^1.2.3: + version "1.2.3" + resolved "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== -get-caller-file@^2.0.1: +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-stream@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== +get-east-asian-width@^1.0.0: + version "1.2.0" + resolved "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz" + integrity sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: + version "1.2.2" + resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz" + integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA== dependencies: - pump "^3.0.0" + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" -get-stream@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9" - integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw== +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stream@^6.0.0, get-stream@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +get-stream@^8.0.1: + version "8.0.1" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz" + integrity sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA== + +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== dependencies: - pump "^3.0.0" + call-bind "^1.0.2" + get-intrinsic "^1.1.1" -get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= +get-uri@^6.0.1: + version "6.0.2" + resolved "https://registry.npmjs.org/get-uri/-/get-uri-6.0.2.tgz" + integrity sha512-5KLucCJobh8vBY1K07EFV4+cPZH3mrV9YeAruUseCQKHB58SGjjT2l9/eA9LD082IiuMjSlFJEcdJ27TXvbZNw== + dependencies: + basic-ftp "^5.0.2" + data-uri-to-buffer "^6.0.0" + debug "^4.3.4" + fs-extra "^8.1.0" + +git-up@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/git-up/-/git-up-7.0.0.tgz" + integrity sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ== + dependencies: + is-ssh "^1.4.0" + parse-url "^8.1.0" + +git-url-parse@14.0.0: + version "14.0.0" + resolved "https://registry.npmjs.org/git-url-parse/-/git-url-parse-14.0.0.tgz" + integrity sha512-NnLweV+2A4nCvn4U/m2AoYu0pPKlsmhK9cknG7IMwsjFY1S2jxM+mAhsDxyxfCIGfGaD+dozsyX4b6vkYc83yQ== + dependencies: + git-up "^7.0.0" + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= +glob@^10.3.7: + version "10.3.10" + resolved "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz" + integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g== dependencies: - assert-plus "^1.0.0" + foreground-child "^3.1.0" + jackspeak "^2.3.5" + minimatch "^9.0.1" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-scurry "^1.10.1" -glob@^7.0.0, glob@^7.1.4: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== +glob@^7.0.0, glob@^7.1.3, glob@^7.1.4: + version "7.2.3" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" - minimatch "^3.0.4" + minimatch "^3.1.1" once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.1.1, glob@^7.1.2, glob@^7.1.3: - version "7.1.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" - integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== +glob@^8.0.3: + version "8.1.0" + resolved "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" - minimatch "^3.0.4" + minimatch "^5.0.1" once "^1.3.0" - path-is-absolute "^1.0.0" + +global-dirs@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz" + integrity sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA== + dependencies: + ini "2.0.0" globals@^11.1.0: version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -graceful-fs@^4.2.4: - version "4.2.4" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" - integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== +globals@^13.19.0: + version "13.24.0" + resolved "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== + dependencies: + type-fest "^0.20.2" -growly@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" - integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= +globalthis@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz" + integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== + dependencies: + define-properties "^1.1.3" + +globby@14.0.0: + version "14.0.0" + resolved "https://registry.npmjs.org/globby/-/globby-14.0.0.tgz" + integrity sha512-/1WM/LNHRAOH9lZta77uGbq0dAEQM+XjNesWwhlERDVenqothRbnzTrL3/LrIoEPPjeUHC3vrS6TwoyxeHs7MQ== + dependencies: + "@sindresorhus/merge-streams" "^1.0.0" + fast-glob "^3.3.2" + ignore "^5.2.4" + path-type "^5.0.0" + slash "^5.1.0" + unicorn-magic "^0.1.0" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" -har-validator@~5.1.3: - version "5.1.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" - integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== dependencies: - ajv "^6.5.5" - har-schema "^2.0.0" + get-intrinsic "^1.1.3" + +got@13.0.0: + version "13.0.0" + resolved "https://registry.npmjs.org/got/-/got-13.0.0.tgz" + integrity sha512-XfBk1CxOOScDcMr9O1yKkNaQyy865NbYs+F7dr4H0LZMVgCj2Le59k6PqbNHoL5ToeaEQUYh6c6yMfVcc6SJxA== + dependencies: + "@sindresorhus/is" "^5.2.0" + "@szmarczak/http-timer" "^5.0.1" + cacheable-lookup "^7.0.0" + cacheable-request "^10.2.8" + decompress-response "^6.0.0" + form-data-encoder "^2.1.2" + get-stream "^6.0.1" + http2-wrapper "^2.1.10" + lowercase-keys "^3.0.0" + p-cancelable "^3.0.0" + responselike "^3.0.0" + +got@^12.1.0: + version "12.6.1" + resolved "https://registry.npmjs.org/got/-/got-12.6.1.tgz" + integrity sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ== + dependencies: + "@sindresorhus/is" "^5.2.0" + "@szmarczak/http-timer" "^5.0.1" + cacheable-lookup "^7.0.0" + cacheable-request "^10.2.8" + decompress-response "^6.0.0" + form-data-encoder "^2.1.2" + get-stream "^6.0.1" + http2-wrapper "^2.1.10" + lowercase-keys "^3.0.0" + p-cancelable "^3.0.0" + responselike "^3.0.0" + +graceful-fs@4.2.10: + version "4.2.10" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + +graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.6, graceful-fs@^4.2.9: + version "4.2.11" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +has-bigints@^1.0.1, has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== has-flag@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== has-flag@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz" + integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg== + dependencies: + get-intrinsic "^1.2.2" + +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== -has-value@^1.0.0: +has-tostringtag@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - -has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + has-symbols "^1.0.2" -has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= +hasown@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz" + integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" + function-bind "^1.1.2" -he@^1.1.1: +he@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== -hosted-git-info@^2.1.4: - version "2.8.8" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" - integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== - -html-encoding-sniffer@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" - integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== +html-encoding-sniffer@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz" + integrity sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA== dependencies: - whatwg-encoding "^1.0.5" + whatwg-encoding "^2.0.0" + +html-entities@^2.3.2: + version "2.4.0" + resolved "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz" + integrity sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ== html-escaper@^2.0.0: version "2.0.2" - resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== -http-proxy@^1.18.0: +http-cache-semantics@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz" + integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== + +http-proxy-agent@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz" + integrity sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ== + dependencies: + agent-base "^7.1.0" + debug "^4.3.4" + +http-proxy@^1.18.1: version "1.18.1" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + resolved "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz" integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== dependencies: eventemitter3 "^4.0.0" follow-redirects "^1.0.0" requires-port "^1.0.0" -http-server@^0.12.3: - version "0.12.3" - resolved "https://registry.yarnpkg.com/http-server/-/http-server-0.12.3.tgz#ba0471d0ecc425886616cb35c4faf279140a0d37" - integrity sha512-be0dKG6pni92bRjq0kvExtj/NrrAd28/8fCXkaI/4piTwQMSDSLMhWyW0NI1V+DBI3aa1HMlQu46/HjVLfmugA== +http-server@^14.1.1: + version "14.1.1" + resolved "https://registry.npmjs.org/http-server/-/http-server-14.1.1.tgz" + integrity sha512-+cbxadF40UXd9T01zUHgA+rlo2Bg1Srer4+B4NwIHdaGxAGGv59nYRnGGDJ9LBk7alpS0US+J+bLLdQOOkJq4A== dependencies: - basic-auth "^1.0.3" - colors "^1.4.0" + basic-auth "^2.0.1" + chalk "^4.1.2" corser "^2.0.1" - ecstatic "^3.3.2" - http-proxy "^1.18.0" - minimist "^1.2.5" + he "^1.2.0" + html-encoding-sniffer "^3.0.0" + http-proxy "^1.18.1" + mime "^1.6.0" + minimist "^1.2.6" opener "^1.5.1" - portfinder "^1.0.25" + portfinder "^1.0.28" secure-compare "3.0.1" union "~0.5.0" + url-join "^4.0.1" -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= +http2-wrapper@^2.1.10: + version "2.2.1" + resolved "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz" + integrity sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ== dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" + quick-lru "^5.1.1" + resolve-alpn "^1.2.0" -human-signals@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" - integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== +https-proxy-agent@^7.0.2: + version "7.0.2" + resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz" + integrity sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA== + dependencies: + agent-base "^7.0.2" + debug "4" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +human-signals@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz" + integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== + +husky@4: + version "4.3.8" + resolved "https://registry.npmjs.org/husky/-/husky-4.3.8.tgz" + integrity sha512-LCqqsB0PzJQ/AlCgfrfzRe3e3+NvmefAdKQhRYpxS4u6clblBoDdzzvHi8fmxKRzvMxPY/1WZWzomPZww0Anow== + dependencies: + chalk "^4.0.0" + ci-info "^2.0.0" + compare-versions "^3.6.0" + cosmiconfig "^7.0.0" + find-versions "^4.0.0" + opencollective-postinstall "^2.0.2" + pkg-dir "^5.0.0" + please-upgrade-node "^3.2.0" + slash "^3.0.0" + which-pm-runs "^1.0.0" + +iconv-lite@0.6.3: + version "0.6.3" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" -iconv-lite@0.4.24: +iconv-lite@^0.4.24: version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== dependencies: safer-buffer ">= 2.1.2 < 3" +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +ignore@^5.2.0, ignore@^5.2.4, ignore@^5.3.1: + version "5.3.2" + resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + +import-fresh@^3.2.1, import-fresh@^3.3.0: + version "3.3.1" + resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz" + integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-lazy@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz" + integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw== + import-local@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.0.2.tgz#a8cfd0431d1de4a2199703d003e3e62364fa6db6" - integrity sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA== + version "3.1.0" + resolved "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== dependencies: pkg-dir "^4.2.0" resolve-cwd "^3.0.0" imurmurhash@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== inflight@^1.0.4: version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== dependencies: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.3, inherits@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= +inherits@2, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ini@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz" + integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== + +ini@^1.3.4, ini@~1.3.0: + version "1.3.8" + resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +inquirer@9.2.12: + version "9.2.12" + resolved "https://registry.npmjs.org/inquirer/-/inquirer-9.2.12.tgz" + integrity sha512-mg3Fh9g2zfuVWJn6lhST0O7x4n03k7G8Tx5nvikJkbq8/CK47WDVm+UznF0G6s5Zi0KcyUisr6DU8T67N5U+1Q== + dependencies: + "@ljharb/through" "^2.3.11" + ansi-escapes "^4.3.2" + chalk "^5.3.0" + cli-cursor "^3.1.0" + cli-width "^4.1.0" + external-editor "^3.1.0" + figures "^5.0.0" + lodash "^4.17.21" + mute-stream "1.0.0" + ora "^5.4.1" + run-async "^3.0.0" + rxjs "^7.8.1" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wrap-ansi "^6.2.0" + +internal-slot@^1.0.4, internal-slot@^1.0.5: + version "1.0.6" + resolved "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz" + integrity sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg== + dependencies: + get-intrinsic "^1.2.2" + hasown "^2.0.0" + side-channel "^1.0.4" interpret@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" - integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== + version "1.4.0" + resolved "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz" + integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== -ip-regex@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" - integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= +ip@^1.1.8: + version "1.1.8" + resolved "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz" + integrity sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg== + +ip@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz" + integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== -is-accessor-descriptor@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= +is-arguments@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== dependencies: - kind-of "^3.0.2" + call-bind "^1.0.2" + has-tostringtag "^1.0.0" -is-accessor-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== +is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz" + integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== dependencies: - kind-of "^6.0.0" + call-bind "^1.0.2" + get-intrinsic "^1.2.0" + is-typed-array "^1.1.10" is-arrayish@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== -is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== -is-ci@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" - integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== dependencies: - ci-info "^2.0.0" + has-bigints "^1.0.1" -is-data-descriptor@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== dependencies: - kind-of "^3.0.2" + call-bind "^1.0.2" + has-tostringtag "^1.0.0" -is-data-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== +is-builtin-module@^3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz" + integrity sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A== dependencies: - kind-of "^6.0.0" + builtin-modules "^3.3.0" -is-descriptor@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== - dependencies: - is-accessor-descriptor "^0.1.6" - is-data-descriptor "^0.1.4" - kind-of "^5.0.0" +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== +is-ci@3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz" + integrity sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ== dependencies: - is-accessor-descriptor "^1.0.0" - is-data-descriptor "^1.0.0" - kind-of "^6.0.2" + ci-info "^3.2.0" -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= +is-core-module@^2.13.0: + version "2.13.1" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + dependencies: + hasown "^2.0.0" -is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== +is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== dependencies: - is-plain-object "^2.0.4" + has-tostringtag "^1.0.0" + +is-docker@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz" + integrity sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== is-fullwidth-code-point@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== +is-fullwidth-code-point@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz" + integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== + +is-fullwidth-code-point@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz" + integrity sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA== + dependencies: + get-east-asian-width "^1.0.0" + is-generator-fn@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-in-ci@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/is-in-ci/-/is-in-ci-0.1.0.tgz" + integrity sha512-d9PXLEY0v1iJ64xLiQMJ51J128EYHAaOR4yZqQi8aHGfw6KgifM3/Viw1oZZ1GCVmb3gBuyhLyHj0HgR2DhSXQ== + +is-inside-container@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz" + integrity sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA== + dependencies: + is-docker "^3.0.0" + +is-installed-globally@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz" + integrity sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ== + dependencies: + global-dirs "^3.0.0" + is-path-inside "^3.0.2" + +is-interactive@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz" + integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== + +is-interactive@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz" + integrity sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ== + +is-map@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz" + integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== + is-module@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" - integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE= + resolved "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz" + integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g== -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= +is-negative-zero@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +is-npm@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz" + integrity sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== dependencies: - kind-of "^3.0.2" + has-tostringtag "^1.0.0" is-number@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + +is-path-inside@^3.0.2, is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-reference@1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz" + integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ== dependencies: - isobject "^3.0.1" + "@types/estree" "*" -is-potential-custom-element-name@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz#0c52e54bcca391bb2c494b21e8626d7336c6e397" - integrity sha1-DFLlS8yjkbssSUsh6GJtczbG45c= +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" -is-reference@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.1.2.tgz#01cf91517d21db66a34642287ed6e70d53dcbe5c" - integrity sha512-Kn5g8c7XHKejFOpTf2QN9YjiHHKl5xRj+2uAZf9iM2//nkBNi/NNeB5JMoun28nEaUVHyPUzqzhfRlfAirEjXg== +is-set@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz" + integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== + +is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== dependencies: - "@types/estree" "0.0.39" + call-bind "^1.0.2" -is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= +is-ssh@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/is-ssh/-/is-ssh-1.4.0.tgz" + integrity sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ== + dependencies: + protocols "^2.0.1" is-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" - integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== + version "2.0.1" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz" + integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.9: + version "1.1.12" + resolved "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz" + integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== + dependencies: + which-typed-array "^1.1.11" -is-typedarray@^1.0.0, is-typedarray@~1.0.0: +is-typedarray@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz" + integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +is-unicode-supported@^1.2.0, is-unicode-supported@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz" + integrity sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ== -is-windows@^1.0.2: +is-unicode-supported@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.0.0.tgz" + integrity sha512-FRdAyx5lusK1iHG0TWpVtk9+1i+GjrzRffhDg4ovQ7mcidMQ6mj+MhKPmvh7Xwyv5gIS06ns49CA7Sqg7lC22Q== + +is-weakref@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + resolved "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" is-wsl@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" - integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= + resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz" + integrity sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw== -is-wsl@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.1.1.tgz#4a1c152d429df3d441669498e2486d3596ebaf1d" - integrity sha512-umZHcSrwlDHo2TGMXv0DZ8dIUGunZ2Iv68YZnrmCiBPkZ4aaOhtv7pXJKeki9k3qJ3RJr0cDyitcl5wEH3AYog== +is-wsl@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz" + integrity sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw== + dependencies: + is-inside-container "^1.0.0" + +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== -isarray@1.0.0, isarray@~1.0.0: +isarray@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== isexe@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= +issue-parser@6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/issue-parser/-/issue-parser-6.0.0.tgz" + integrity sha512-zKa/Dxq2lGsBIXQ7CUZWTHfvxPC2ej0KfO7fIPqLlHB9J2hJ7rGhZ5rilhuufylr4RXYPzJUeFjKxz305OsNlA== dependencies: - isarray "1.0.0" - -isobject@^3.0.0, isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + lodash.capitalize "^4.2.1" + lodash.escaperegexp "^4.1.2" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.uniqby "^4.7.0" -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= - -istanbul-lib-coverage@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" - integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.2" + resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== -istanbul-lib-instrument@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz#61f13ac2c96cfefb076fe7131156cc05907874e6" - integrity sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg== +istanbul-lib-instrument@^5.0.4: + version "5.2.1" + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz" + integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== dependencies: - "@babel/core" "^7.7.5" - "@babel/parser" "^7.7.5" - "@babel/template" "^7.7.4" - "@babel/traverse" "^7.7.4" + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.0.0" + istanbul-lib-coverage "^3.2.0" semver "^6.3.0" +istanbul-lib-instrument@^6.0.0: + version "6.0.1" + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz" + integrity sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^7.5.4" + istanbul-lib-report@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" - integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + version "3.0.1" + resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== dependencies: istanbul-lib-coverage "^3.0.0" - make-dir "^3.0.0" + make-dir "^4.0.0" supports-color "^7.1.0" istanbul-lib-source-maps@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz#75743ce6d96bb86dc7ee4352cf6366a23f0b1ad9" - integrity sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg== + version "4.0.1" + resolved "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== dependencies: debug "^4.1.1" istanbul-lib-coverage "^3.0.0" source-map "^0.6.1" -istanbul-reports@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b" - integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw== +istanbul-reports@^3.1.3: + version "3.1.6" + resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz" + integrity sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg== dependencies: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jest-changed-files@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.0.1.tgz#1334630c6a1ad75784120f39c3aa9278e59f349f" - integrity sha512-q8LP9Sint17HaE2LjxQXL+oYWW/WeeXMPE2+Op9X3mY8IEGFVc14xRxFjUuXUbcPAlDLhtWdIEt59GdQbn76Hw== +iterate-iterator@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.2.tgz" + integrity sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw== + +iterate-value@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz" + integrity sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ== dependencies: - "@jest/types" "^26.0.1" - execa "^4.0.0" - throat "^5.0.0" + es-get-iterator "^1.0.2" + iterate-iterator "^1.0.1" -jest-cli@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.0.1.tgz#3a42399a4cbc96a519b99ad069a117d955570cac" - integrity sha512-pFLfSOBcbG9iOZWaMK4Een+tTxi/Wcm34geqZEqrst9cZDkTQ1LZ2CnBrTlHWuYAiTMFr0EQeK52ScyFU8wK+w== +jackspeak@^2.3.5: + version "2.3.6" + resolved "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz" + integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== dependencies: - "@jest/core" "^26.0.1" - "@jest/test-result" "^26.0.1" - "@jest/types" "^26.0.1" + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + +jest-changed-files@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz" + integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== + dependencies: + execa "^5.0.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + +jest-circus@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz" + integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" chalk "^4.0.0" - exit "^0.1.2" - graceful-fs "^4.2.4" - import-local "^3.0.2" - is-ci "^2.0.0" - jest-config "^26.0.1" - jest-util "^26.0.1" - jest-validate "^26.0.1" - prompts "^2.0.1" - yargs "^15.3.1" + co "^4.6.0" + dedent "^1.0.0" + is-generator-fn "^2.0.0" + jest-each "^29.7.0" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + pretty-format "^29.7.0" + pure-rand "^6.0.0" + slash "^3.0.0" + stack-utils "^2.0.3" -jest-config@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.0.1.tgz#096a3d4150afadf719d1fab00e9a6fb2d6d67507" - integrity sha512-9mWKx2L1LFgOXlDsC4YSeavnblN6A4CPfXFiobq+YYLaBMymA/SczN7xYTSmLaEYHZOcB98UdoN4m5uNt6tztg== +jest-cli@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz" + integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== dependencies: - "@babel/core" "^7.1.0" - "@jest/test-sequencer" "^26.0.1" - "@jest/types" "^26.0.1" - babel-jest "^26.0.1" + "@jest/core" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" chalk "^4.0.0" + create-jest "^29.7.0" + exit "^0.1.2" + import-local "^3.0.2" + jest-config "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + yargs "^17.3.1" + +jest-config@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz" + integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.7.0" + "@jest/types" "^29.6.3" + babel-jest "^29.7.0" + chalk "^4.0.0" + ci-info "^3.2.0" deepmerge "^4.2.2" - glob "^7.1.1" - graceful-fs "^4.2.4" - jest-environment-jsdom "^26.0.1" - jest-environment-node "^26.0.1" - jest-get-type "^26.0.0" - jest-jasmine2 "^26.0.1" - jest-regex-util "^26.0.0" - jest-resolve "^26.0.1" - jest-util "^26.0.1" - jest-validate "^26.0.1" - micromatch "^4.0.2" - pretty-format "^26.0.1" - -jest-diff@^25.2.1: - version "25.3.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-25.3.0.tgz#0d7d6f5d6171e5dacde9e05be47b3615e147c26f" - integrity sha512-vyvs6RPoVdiwARwY4kqFWd4PirPLm2dmmkNzKqo38uZOzJvLee87yzDjIZLmY1SjM3XR5DwsUH+cdQ12vgqi1w== - dependencies: - chalk "^3.0.0" - diff-sequences "^25.2.6" - jest-get-type "^25.2.6" - pretty-format "^25.3.0" - -jest-diff@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.0.1.tgz#c44ab3cdd5977d466de69c46929e0e57f89aa1de" - integrity sha512-odTcHyl5X+U+QsczJmOjWw5tPvww+y9Yim5xzqxVl/R1j4z71+fHW4g8qu1ugMmKdFdxw+AtQgs5mupPnzcIBQ== + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^29.7.0" + jest-environment-node "^29.7.0" + jest-get-type "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-runner "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz" + integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== dependencies: chalk "^4.0.0" - diff-sequences "^26.0.0" - jest-get-type "^26.0.0" - pretty-format "^26.0.1" + diff-sequences "^29.6.3" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" -jest-docblock@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5" - integrity sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w== +jest-docblock@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz" + integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== dependencies: detect-newline "^3.0.0" -jest-each@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-26.0.1.tgz#633083061619302fc90dd8f58350f9d77d67be04" - integrity sha512-OTgJlwXCAR8NIWaXFL5DBbeS4QIYPuNASkzSwMCJO+ywo9BEa6TqkaSWsfR7VdbMLdgYJqSfQcIyjJCNwl5n4Q== +jest-each@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz" + integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^29.6.3" chalk "^4.0.0" - jest-get-type "^26.0.0" - jest-util "^26.0.1" - pretty-format "^26.0.1" - -jest-environment-jsdom@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-26.0.1.tgz#217690852e5bdd7c846a4e3b50c8ffd441dfd249" - integrity sha512-u88NJa3aptz2Xix2pFhihRBAatwZHWwSiRLBDBQE1cdJvDjPvv7ZGA0NQBxWwDDn7D0g1uHqxM8aGgfA9Bx49g== - dependencies: - "@jest/environment" "^26.0.1" - "@jest/fake-timers" "^26.0.1" - "@jest/types" "^26.0.1" - jest-mock "^26.0.1" - jest-util "^26.0.1" - jsdom "^16.2.2" - -jest-environment-node@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-26.0.1.tgz#584a9ff623124ff6eeb49e0131b5f7612b310b13" - integrity sha512-4FRBWcSn5yVo0KtNav7+5NH5Z/tEgDLp7VRQVS5tCouWORxj+nI+1tOLutM07Zb2Qi7ja+HEDoOUkjBSWZg/IQ== - dependencies: - "@jest/environment" "^26.0.1" - "@jest/fake-timers" "^26.0.1" - "@jest/types" "^26.0.1" - jest-mock "^26.0.1" - jest-util "^26.0.1" - -jest-get-type@^25.2.6: - version "25.2.6" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-25.2.6.tgz#0b0a32fab8908b44d508be81681487dbabb8d877" - integrity sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig== - -jest-get-type@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.0.0.tgz#381e986a718998dbfafcd5ec05934be538db4039" - integrity sha512-zRc1OAPnnws1EVfykXOj19zo2EMw5Hi6HLbFCSjpuJiXtOWAYIjNsHVSbpQ8bDX7L5BGYGI8m+HmKdjHYFF0kg== - -jest-haste-map@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.0.1.tgz#40dcc03c43ac94d25b8618075804d09cd5d49de7" - integrity sha512-J9kBl/EdjmDsvyv7CiyKY5+DsTvVOScenprz/fGqfLg/pm1gdjbwwQ98nW0t+OIt+f+5nAVaElvn/6wP5KO7KA== - dependencies: - "@jest/types" "^26.0.1" - "@types/graceful-fs" "^4.1.2" + jest-get-type "^29.6.3" + jest-util "^29.7.0" + pretty-format "^29.7.0" + +jest-environment-node@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz" + integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +jest-get-type@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz" + integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== + +jest-haste-map@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz" + integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== + dependencies: + "@jest/types" "^29.6.3" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" anymatch "^3.0.3" fb-watchman "^2.0.0" - graceful-fs "^4.2.4" - jest-serializer "^26.0.0" - jest-util "^26.0.1" - jest-worker "^26.0.0" - micromatch "^4.0.2" - sane "^4.0.3" - walker "^1.0.7" - which "^2.0.2" + graceful-fs "^4.2.9" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + jest-worker "^29.7.0" + micromatch "^4.0.4" + walker "^1.0.8" optionalDependencies: - fsevents "^2.1.2" - -jest-jasmine2@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.0.1.tgz#947c40ee816636ba23112af3206d6fa7b23c1c1c" - integrity sha512-ILaRyiWxiXOJ+RWTKupzQWwnPaeXPIoLS5uW41h18varJzd9/7I0QJGqg69fhTT1ev9JpSSo9QtalriUN0oqOg== - dependencies: - "@babel/traverse" "^7.1.0" - "@jest/environment" "^26.0.1" - "@jest/source-map" "^26.0.0" - "@jest/test-result" "^26.0.1" - "@jest/types" "^26.0.1" - chalk "^4.0.0" - co "^4.6.0" - expect "^26.0.1" - is-generator-fn "^2.0.0" - jest-each "^26.0.1" - jest-matcher-utils "^26.0.1" - jest-message-util "^26.0.1" - jest-runtime "^26.0.1" - jest-snapshot "^26.0.1" - jest-util "^26.0.1" - pretty-format "^26.0.1" - throat "^5.0.0" - -jest-leak-detector@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-26.0.1.tgz#79b19ab3f41170e0a78eb8fa754a116d3447fb8c" - integrity sha512-93FR8tJhaYIWrWsbmVN1pQ9ZNlbgRpfvrnw5LmgLRX0ckOJ8ut/I35CL7awi2ecq6Ca4lL59bEK9hr7nqoHWPA== - dependencies: - jest-get-type "^26.0.0" - pretty-format "^26.0.1" - -jest-matcher-utils@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.0.1.tgz#12e1fc386fe4f14678f4cc8dbd5ba75a58092911" - integrity sha512-PUMlsLth0Azen8Q2WFTwnSkGh2JZ8FYuwijC8NR47vXKpsrKmA1wWvgcj1CquuVfcYiDEdj985u5Wmg7COEARw== + fsevents "^2.3.2" + +jest-leak-detector@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz" + integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== dependencies: - chalk "^4.0.0" - jest-diff "^26.0.1" - jest-get-type "^26.0.0" - pretty-format "^26.0.1" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" -jest-message-util@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.0.1.tgz#07af1b42fc450b4cc8e90e4c9cef11b33ce9b0ac" - integrity sha512-CbK8uQREZ8umUfo8+zgIfEt+W7HAHjQCoRaNs4WxKGhAYBGwEyvxuK81FXa7VeB9pwDEXeeKOB2qcsNVCAvB7Q== +jest-matcher-utils@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz" + integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== dependencies: - "@babel/code-frame" "^7.0.0" - "@jest/types" "^26.0.1" - "@types/stack-utils" "^1.0.1" chalk "^4.0.0" - graceful-fs "^4.2.4" - micromatch "^4.0.2" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-message-util@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz" + integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.6.3" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.7.0" slash "^3.0.0" - stack-utils "^2.0.2" + stack-utils "^2.0.3" -jest-mock@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.0.1.tgz#7fd1517ed4955397cf1620a771dc2d61fad8fd40" - integrity sha512-MpYTBqycuPYSY6xKJognV7Ja46/TeRbAZept987Zp+tuJvMN0YBWyyhG9mXyYQaU3SBI0TUlSaO5L3p49agw7Q== +jest-mock@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz" + integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-util "^29.7.0" -jest-pnp-resolver@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz#ecdae604c077a7fbc70defb6d517c3c1c898923a" - integrity sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ== +jest-pnp-resolver@^1.2.2: + version "1.2.3" + resolved "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz" + integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== -jest-regex-util@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" - integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== +jest-regex-util@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz" + integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== -jest-resolve-dependencies@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-26.0.1.tgz#607ba7ccc32151d185a477cff45bf33bce417f0b" - integrity sha512-9d5/RS/ft0vB/qy7jct/qAhzJsr6fRQJyGAFigK3XD4hf9kIbEH5gks4t4Z7kyMRhowU6HWm/o8ILqhaHdSqLw== +jest-resolve-dependencies@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz" + integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== dependencies: - "@jest/types" "^26.0.1" - jest-regex-util "^26.0.0" - jest-snapshot "^26.0.1" + jest-regex-util "^29.6.3" + jest-snapshot "^29.7.0" -jest-resolve@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.0.1.tgz#21d1ee06f9ea270a343a8893051aeed940cde736" - integrity sha512-6jWxk0IKZkPIVTvq6s72RH735P8f9eCJW3IM5CX/SJFeKq1p2cZx0U49wf/SdMlhaB/anann5J2nCJj6HrbezQ== +jest-resolve@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz" + integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== dependencies: - "@jest/types" "^26.0.1" chalk "^4.0.0" - graceful-fs "^4.2.4" - jest-pnp-resolver "^1.2.1" - jest-util "^26.0.1" - read-pkg-up "^7.0.1" - resolve "^1.17.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-pnp-resolver "^1.2.2" + jest-util "^29.7.0" + jest-validate "^29.7.0" + resolve "^1.20.0" + resolve.exports "^2.0.0" slash "^3.0.0" -jest-runner@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-26.0.1.tgz#ea03584b7ae4bacfb7e533d680a575a49ae35d50" - integrity sha512-CApm0g81b49Znm4cZekYQK67zY7kkB4umOlI2Dx5CwKAzdgw75EN+ozBHRvxBzwo1ZLYZ07TFxkaPm+1t4d8jA== +jest-runner@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz" + integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== dependencies: - "@jest/console" "^26.0.1" - "@jest/environment" "^26.0.1" - "@jest/test-result" "^26.0.1" - "@jest/types" "^26.0.1" + "@jest/console" "^29.7.0" + "@jest/environment" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" chalk "^4.0.0" - exit "^0.1.2" - graceful-fs "^4.2.4" - jest-config "^26.0.1" - jest-docblock "^26.0.0" - jest-haste-map "^26.0.1" - jest-jasmine2 "^26.0.1" - jest-leak-detector "^26.0.1" - jest-message-util "^26.0.1" - jest-resolve "^26.0.1" - jest-runtime "^26.0.1" - jest-util "^26.0.1" - jest-worker "^26.0.0" - source-map-support "^0.5.6" - throat "^5.0.0" - -jest-runtime@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.0.1.tgz#a121a6321235987d294168e282d52b364d7d3f89" - integrity sha512-Ci2QhYFmANg5qaXWf78T2Pfo6GtmIBn2rRaLnklRyEucmPccmCKvS9JPljcmtVamsdMmkyNkVFb9pBTD6si9Lw== - dependencies: - "@jest/console" "^26.0.1" - "@jest/environment" "^26.0.1" - "@jest/fake-timers" "^26.0.1" - "@jest/globals" "^26.0.1" - "@jest/source-map" "^26.0.0" - "@jest/test-result" "^26.0.1" - "@jest/transform" "^26.0.1" - "@jest/types" "^26.0.1" - "@types/yargs" "^15.0.0" + emittery "^0.13.1" + graceful-fs "^4.2.9" + jest-docblock "^29.7.0" + jest-environment-node "^29.7.0" + jest-haste-map "^29.7.0" + jest-leak-detector "^29.7.0" + jest-message-util "^29.7.0" + jest-resolve "^29.7.0" + jest-runtime "^29.7.0" + jest-util "^29.7.0" + jest-watcher "^29.7.0" + jest-worker "^29.7.0" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz" + integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/globals" "^29.7.0" + "@jest/source-map" "^29.6.3" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" chalk "^4.0.0" + cjs-module-lexer "^1.0.0" collect-v8-coverage "^1.0.0" - exit "^0.1.2" glob "^7.1.3" - graceful-fs "^4.2.4" - jest-config "^26.0.1" - jest-haste-map "^26.0.1" - jest-message-util "^26.0.1" - jest-mock "^26.0.1" - jest-regex-util "^26.0.0" - jest-resolve "^26.0.1" - jest-snapshot "^26.0.1" - jest-util "^26.0.1" - jest-validate "^26.0.1" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" slash "^3.0.0" strip-bom "^4.0.0" - yargs "^15.3.1" -jest-serializer@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.0.0.tgz#f6c521ddb976943b93e662c0d4d79245abec72a3" - integrity sha512-sQGXLdEGWFAE4wIJ2ZaIDb+ikETlUirEOBsLXdoBbeLhTHkZUJwgk3+M8eyFizhM6le43PDCCKPA1hzkSDo4cQ== +jest-snapshot@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz" + integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== dependencies: - graceful-fs "^4.2.4" - -jest-snapshot@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.0.1.tgz#1baa942bd83d47b837a84af7fcf5fd4a236da399" - integrity sha512-jxd+cF7+LL+a80qh6TAnTLUZHyQoWwEHSUFJjkw35u3Gx+BZUNuXhYvDqHXr62UQPnWo2P6fvQlLjsU93UKyxA== - dependencies: - "@babel/types" "^7.0.0" - "@jest/types" "^26.0.1" - "@types/prettier" "^2.0.0" + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" chalk "^4.0.0" - expect "^26.0.1" - graceful-fs "^4.2.4" - jest-diff "^26.0.1" - jest-get-type "^26.0.0" - jest-matcher-utils "^26.0.1" - jest-message-util "^26.0.1" - jest-resolve "^26.0.1" - make-dir "^3.0.0" + expect "^29.7.0" + graceful-fs "^4.2.9" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" natural-compare "^1.4.0" - pretty-format "^26.0.1" - semver "^7.3.2" + pretty-format "^29.7.0" + semver "^7.5.3" -jest-util@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.0.1.tgz#72c4c51177b695fdd795ca072a6f94e3d7cef00a" - integrity sha512-byQ3n7ad1BO/WyFkYvlWQHTsomB6GIewBh8tlGtusiylAlaxQ1UpS0XYH0ngOyhZuHVLN79Qvl6/pMiDMSSG1g== +jest-util@^29.0.0, jest-util@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz" + integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^29.6.3" + "@types/node" "*" chalk "^4.0.0" - graceful-fs "^4.2.4" - is-ci "^2.0.0" - make-dir "^3.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" -jest-validate@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.0.1.tgz#a62987e1da5b7f724130f904725e22f4e5b2e23c" - integrity sha512-u0xRc+rbmov/VqXnX3DlkxD74rHI/CfS5xaV2VpeaVySjbb1JioNVOyly5b56q2l9ZKe7bVG5qWmjfctkQb0bA== +jest-validate@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz" + integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== dependencies: - "@jest/types" "^26.0.1" - camelcase "^6.0.0" + "@jest/types" "^29.6.3" + camelcase "^6.2.0" chalk "^4.0.0" - jest-get-type "^26.0.0" + jest-get-type "^29.6.3" leven "^3.1.0" - pretty-format "^26.0.1" + pretty-format "^29.7.0" -jest-watcher@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-26.0.1.tgz#5b5e3ebbdf10c240e22a98af66d645631afda770" - integrity sha512-pdZPydsS8475f89kGswaNsN3rhP6lnC3/QDCppP7bg1L9JQz7oU9Mb/5xPETk1RHDCWeqmVC47M4K5RR7ejxFw== +jest-watcher@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz" + integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== dependencies: - "@jest/test-result" "^26.0.1" - "@jest/types" "^26.0.1" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" - jest-util "^26.0.1" + emittery "^0.13.1" + jest-util "^29.7.0" string-length "^4.0.1" -jest-worker@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.0.0.tgz#4920c7714f0a96c6412464718d0c58a3df3fb066" - integrity sha512-pPaYa2+JnwmiZjK9x7p9BoZht+47ecFCDFA/CJxspHzeDvQcfVBLWzCiWyo+EGrSiQMWZtCFo9iSvMZnAAo8vw== +jest-worker@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz" + integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== dependencies: + "@types/node" "*" + jest-util "^29.7.0" merge-stream "^2.0.0" - supports-color "^7.0.0" + supports-color "^8.0.0" -jest@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest/-/jest-26.0.1.tgz#5c51a2e58dff7525b65f169721767173bf832694" - integrity sha512-29Q54kn5Bm7ZGKIuH2JRmnKl85YRigp0o0asTc6Sb6l2ch1DCXIeZTLLFy9ultJvhkTqbswF5DEx4+RlkmCxWg== +jest@29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz" + integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== dependencies: - "@jest/core" "^26.0.1" + "@jest/core" "^29.7.0" + "@jest/types" "^29.6.3" import-local "^3.0.2" - jest-cli "^26.0.1" + jest-cli "^29.7.0" js-tokens@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== js-yaml@^3.13.1: - version "3.13.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" - integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== + version "3.14.1" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== dependencies: argparse "^1.0.7" esprima "^4.0.0" -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - -jsdom@^16.2.2: - version "16.2.2" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.2.2.tgz#76f2f7541646beb46a938f5dc476b88705bedf2b" - integrity sha512-pDFQbcYtKBHxRaP55zGXCJWgFHkDAYbKcsXEK/3Icu9nKYZkutUXfLBwbD+09XDutkYSHcgfQLZ0qvpAAm9mvg== - dependencies: - abab "^2.0.3" - acorn "^7.1.1" - acorn-globals "^6.0.0" - cssom "^0.4.4" - cssstyle "^2.2.0" - data-urls "^2.0.0" - decimal.js "^10.2.0" - domexception "^2.0.1" - escodegen "^1.14.1" - html-encoding-sniffer "^2.0.1" - is-potential-custom-element-name "^1.0.0" - nwsapi "^2.2.0" - parse5 "5.1.1" - request "^2.88.2" - request-promise-native "^1.0.8" - saxes "^5.0.0" - symbol-tree "^3.2.4" - tough-cookie "^3.0.1" - w3c-hr-time "^1.0.2" - w3c-xmlserializer "^2.0.0" - webidl-conversions "^6.0.0" - whatwg-encoding "^1.0.5" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.0.0" - ws "^7.2.3" - xml-name-validator "^3.0.0" +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" jsesc@^2.5.1: version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== -json-parse-better-errors@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== json-schema-traverse@^0.4.1: version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== -json5@2.x, json5@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850" - integrity sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ== +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz" + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== + optionalDependencies: + graceful-fs "^4.1.6" + +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== dependencies: - minimist "^1.2.0" + json-buffer "3.0.1" -json5@^2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" - integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +latest-version@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz" + integrity sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg== dependencies: - minimist "^1.2.5" + package-json "^8.1.0" -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" + prelude-ls "^1.2.1" + type-check "~0.4.0" -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= +lilconfig@^3.1.3: + version "3.1.3" + resolved "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz" + integrity sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw== + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +lint-staged@^15.5.0: + version "15.5.0" + resolved "https://registry.npmjs.org/lint-staged/-/lint-staged-15.5.0.tgz" + integrity sha512-WyCzSbfYGhK7cU+UuDDkzUiytbfbi0ZdPy2orwtM75P3WTtQBzmG40cCxIa8Ii2+XjfxzLH6Be46tUfWS85Xfg== + dependencies: + chalk "^5.4.1" + commander "^13.1.0" + debug "^4.4.0" + execa "^8.0.1" + lilconfig "^3.1.3" + listr2 "^8.2.5" + micromatch "^4.0.8" + pidtree "^0.6.0" + string-argv "^0.3.2" + yaml "^2.7.0" + +listr2@^8.2.5: + version "8.2.5" + resolved "https://registry.npmjs.org/listr2/-/listr2-8.2.5.tgz" + integrity sha512-iyAZCeyD+c1gPyE9qpFu8af0Y+MRtmKOncdGoA2S5EY8iFq99dmmvkNnHiWo+pj0s7yH7l3KPIgee77tKpXPWQ== + dependencies: + cli-truncate "^4.0.0" + colorette "^2.0.20" + eventemitter3 "^5.0.1" + log-update "^6.1.0" + rfdc "^1.4.1" + wrap-ansi "^9.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== dependencies: - is-buffer "^1.1.5" + p-locate "^4.1.0" -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== dependencies: - is-buffer "^1.1.5" + p-locate "^5.0.0" -kind-of@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== +lodash.capitalize@^4.2.1: + version "4.2.1" + resolved "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz" + integrity sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw== -kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" - integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== +lodash.escaperegexp@^4.1.2: + version "4.1.2" + resolved "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz" + integrity sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw== -kleur@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" - integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz" + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== -leven@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" - integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz" + integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== + +lodash.memoize@4.x: + version "4.1.2" + resolved "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" +lodash.uniqby@^4.7.0: + version "4.7.0" + resolved "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz" + integrity sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww== -lines-and-columns@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" - integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= +lodash@4.17.21, lodash@^4.17.14, lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== +log-symbols@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== dependencies: - p-locate "^4.1.0" + chalk "^4.1.0" + is-unicode-supported "^0.1.0" -lodash.memoize@4.x: - version "4.1.2" - resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" - integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= +log-symbols@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz" + integrity sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw== + dependencies: + chalk "^5.3.0" + is-unicode-supported "^1.3.0" -lodash.sortby@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" - integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= +log-update@^6.1.0: + version "6.1.0" + resolved "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz" + integrity sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w== + dependencies: + ansi-escapes "^7.0.0" + cli-cursor "^5.0.0" + slice-ansi "^7.1.0" + strip-ansi "^7.1.0" + wrap-ansi "^9.0.0" -lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15: - version "4.17.19" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" - integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ== +lowercase-keys@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz" + integrity sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ== -magic-string@^0.25.2: - version "0.25.2" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.2.tgz#139c3a729515ec55e96e69e82a11fe890a293ad9" - integrity sha512-iLs9mPjh9IuTtRsqqhNGYcZXGei0Nh/A4xirrsqW7c+QhKVFL2vm7U09ru6cHRD22azaP/wMDgI+HCqbETMTtg== +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== dependencies: - sourcemap-codec "^1.4.4" + yallist "^3.0.2" -make-dir@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.0.2.tgz#04a1acbf22221e1d6ef43559f43e05a90dbb4392" - integrity sha512-rYKABKutXa6vXTXhoV18cBE7PaewPXHe/Bdq4v+ZLMhxbWApkFFplT0LcbMW+6BbjnQXzZ/sAvSE/JdguApG5w== +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== dependencies: - semver "^6.0.0" + yallist "^4.0.0" -make-error@1.x: - version "1.3.5" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8" - integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g== +lru-cache@^7.14.1: + version "7.18.3" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz" + integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== -makeerror@1.0.x: - version "1.0.11" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" - integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= +"lru-cache@^9.1.1 || ^10.0.0": + version "10.2.0" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz" + integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q== + +macos-release@^3.1.0: + version "3.2.0" + resolved "https://registry.npmjs.org/macos-release/-/macos-release-3.2.0.tgz" + integrity sha512-fSErXALFNsnowREYZ49XCdOHF8wOPWuFOGQrAhP7x5J/BqQv+B02cNsTykGpDgRVx43EKg++6ANmTaGTtW+hUA== + +magic-string@^0.30.3: + version "0.30.6" + resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.30.6.tgz" + integrity sha512-n62qCLbPjNjyo+owKtveQxZFZTBm+Ms6YoGD23Wew6Vw337PElFNifQpknPruVRQV57kVShPnLGo9vWxVhpPvA== dependencies: - tmpl "1.0.x" + "@jridgewell/sourcemap-codec" "^1.4.15" -map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" -map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= +make-error@1.x: + version "1.3.6" + resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== dependencies: - object-visit "^1.0.0" + tmpl "1.0.5" merge-stream@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -micromatch@4.x, micromatch@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" - integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== - dependencies: - braces "^3.0.1" - picomatch "^2.0.5" - -micromatch@^3.1.4: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - -mime-db@1.40.0: - version "1.40.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" - integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== - -mime-types@^2.1.12, mime-types@~2.1.19: - version "2.1.24" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" - integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ== - dependencies: - mime-db "1.40.0" +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@2.1.35, mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" mime@^1.6.0: version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== mimic-fn@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" +mimic-fn@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz" + integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= +mimic-function@^5.0.0: + version "5.0.1" + resolved "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz" + integrity sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA== -minimist@^1.1.0, minimist@^1.1.1, minimist@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== -minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +mimic-response@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz" + integrity sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg== -mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" - integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== +minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" + brace-expansion "^1.1.7" -mkdirp@1.x: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== +minimatch@^5.0.1: + version "5.1.6" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" -mkdirp@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= +minimatch@^9.0.1: + version "9.0.3" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== dependencies: - minimist "0.0.8" + brace-expansion "^2.0.1" -mkdirp@^0.5.3: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== dependencies: - minimist "^1.2.5" + brace-expansion "^2.0.1" -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= +minimist@^1.2.0, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== -ms@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== - -nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0": + version "7.0.4" + resolved "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz" + integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== + +mkdirp@^0.5.6: + version "0.5.6" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@^2.1.1, ms@^2.1.3: + version "2.1.3" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +mute-stream@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz" + integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA== natural-compare@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - -node-fetch@^2.6.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" - integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== +netmask@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz" + integrity sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg== -node-int64@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" - integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= +new-github-release-url@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/new-github-release-url/-/new-github-release-url-2.0.0.tgz" + integrity sha512-NHDDGYudnvRutt/VhKFlX26IotXe1w0cmkDm6JGquh5bz/bDTw0LufSmH/GxTjEdpHEO+bVKFTwdrcGa/9XlKQ== + dependencies: + type-fest "^2.5.1" -node-modules-regexp@^1.0.0: +node-domexception@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" - integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= + resolved "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz" + integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== -node-notifier@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-7.0.1.tgz#a355e33e6bebacef9bf8562689aed0f4230ca6f9" - integrity sha512-VkzhierE7DBmQEElhTGJIoiZa1oqRijOtgOlsXg32KrJRXsPy0NXFBqWGW/wTswnJlDCs5viRYaqWguqzsKcmg== - dependencies: - growly "^1.3.0" - is-wsl "^2.1.1" - semver "^7.2.1" - shellwords "^0.1.1" - uuid "^7.0.3" - which "^2.0.2" - -normalize-package-data@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" - integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - -normalize-path@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= +node-fetch@3.3.2, node-fetch@^3.3.2: + version "3.3.2" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz" + integrity sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA== + dependencies: + data-uri-to-buffer "^4.0.0" + fetch-blob "^3.1.4" + formdata-polyfill "^4.0.10" + +node-html-better-parser@^1.4.0: + version "1.4.3" + resolved "https://registry.npmjs.org/node-html-better-parser/-/node-html-better-parser-1.4.3.tgz" + integrity sha512-Ks/yImEI7A5Yav3p0ecyH2/q3YOllFQ4BQUgk8I/BZgISdXNMhNHQhX7D5kjHQhd6oMok0f9FUaHNFJBVqylHw== dependencies: - remove-trailing-separator "^1.0.1" + html-entities "^2.3.2" + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-releases@^2.0.14: + version "2.0.14" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz" + integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== normalize-path@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= - dependencies: - path-key "^2.0.0" +normalize-url@^8.0.0: + version "8.0.0" + resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz" + integrity sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw== -npm-run-path@^4.0.0: +npm-run-path@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz" integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== dependencies: path-key "^3.0.0" -nwsapi@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" - integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== - -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== - -object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= +npm-run-path@^5.1.0: + version "5.2.0" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz" + integrity sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg== dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" + path-key "^4.0.0" -object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= - dependencies: - isobject "^3.0.0" +object-inspect@^1.13.1, object-inspect@^1.9.0: + version "1.13.1" + resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz" + integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== -object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.4: + version "4.1.5" + resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz" + integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== dependencies: - isobject "^3.0.1" + call-bind "^1.0.5" + define-properties "^1.2.1" + has-symbols "^1.0.3" + object-keys "^1.1.1" -once@^1.3.0, once@^1.3.1, once@^1.4.0: +once@^1.3.0, once@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" -onetime@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.0.tgz#fff0f3c91617fe62bb50189636e99ac8a6df7be5" - integrity sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q== +onetime@^5.1.0, onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== dependencies: mimic-fn "^2.1.0" +onetime@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz" + integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== + dependencies: + mimic-fn "^4.0.0" + +onetime@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz" + integrity sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ== + dependencies: + mimic-function "^5.0.0" + +open@10.0.3: + version "10.0.3" + resolved "https://registry.npmjs.org/open/-/open-10.0.3.tgz" + integrity sha512-dtbI5oW7987hwC9qjJTyABldTaa19SuyJse1QboWv3b0qCcrrLNVDqBx1XgELAjh9QTVQaP/C5b1nhQebd1H2A== + dependencies: + default-browser "^5.2.1" + define-lazy-prop "^3.0.0" + is-inside-container "^1.0.0" + is-wsl "^3.1.0" + +opencollective-postinstall@^2.0.2: + version "2.0.3" + resolved "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz" + integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q== + opener@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.1.tgz#6d2f0e77f1a0af0032aca716c2c1fbb8e7e8abed" - integrity sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA== + version "1.5.2" + resolved "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz" + integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== opn@^5.3.0: version "5.5.0" - resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" + resolved "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz" integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA== dependencies: is-wsl "^1.1.0" -optionator@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" - integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.4" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - wordwrap "~1.0.0" + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.5" -p-each-series@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.1.0.tgz#961c8dd3f195ea96c747e636b262b800a6b1af48" - integrity sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ== +ora@8.0.1: + version "8.0.1" + resolved "https://registry.npmjs.org/ora/-/ora-8.0.1.tgz" + integrity sha512-ANIvzobt1rls2BDny5fWZ3ZVKyD6nscLvfFRpQgfWsythlcsVUC9kL0zq6j2Z5z9wwp1kd7wpsD/T9qNPVLCaQ== + dependencies: + chalk "^5.3.0" + cli-cursor "^4.0.0" + cli-spinners "^2.9.2" + is-interactive "^2.0.0" + is-unicode-supported "^2.0.0" + log-symbols "^6.0.0" + stdin-discarder "^0.2.1" + string-width "^7.0.0" + strip-ansi "^7.1.0" + +ora@^5.4.1: + version "5.4.1" + resolved "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz" + integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== + dependencies: + bl "^4.1.0" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-spinners "^2.5.0" + is-interactive "^1.0.0" + is-unicode-supported "^0.1.0" + log-symbols "^4.1.0" + strip-ansi "^6.0.0" + wcwidth "^1.0.1" -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= +os-name@5.1.0: + version "5.1.0" + resolved "https://registry.npmjs.org/os-name/-/os-name-5.1.0.tgz" + integrity sha512-YEIoAnM6zFmzw3PQ201gCVCIWbXNyKObGlVvpAVvraAeOHnlYVKFssbA/riRX5R40WA6kKrZ7Dr7dWzO3nKSeQ== + dependencies: + macos-release "^3.1.0" + windows-release "^5.0.1" + +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz" + integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== + +p-cancelable@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz" + integrity sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw== p-limit@^2.2.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== dependencies: p-try "^2.0.0" +p-limit@^3.0.2, p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + p-locate@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz" integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== dependencies: p-limit "^2.2.0" +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + p-try@^2.0.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== -pako@^1.0.10, pako@^1.0.6: - version "1.0.10" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732" - integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw== +pac-proxy-agent@^7.0.1: + version "7.0.1" + resolved "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.1.tgz" + integrity sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A== + dependencies: + "@tootallnate/quickjs-emscripten" "^0.23.0" + agent-base "^7.0.2" + debug "^4.3.4" + get-uri "^6.0.1" + http-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.2" + pac-resolver "^7.0.0" + socks-proxy-agent "^8.0.2" + +pac-resolver@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.0.tgz" + integrity sha512-Fd9lT9vJbHYRACT8OhCbZBbxr6KRSawSovFpy8nDGshaK99S/EBhVIHp9+crhxrsZOuvLpgL1n23iyPg6Rl2hg== + dependencies: + degenerator "^5.0.0" + ip "^1.1.8" + netmask "^2.0.2" + +package-json@^8.1.0: + version "8.1.1" + resolved "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz" + integrity sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA== + dependencies: + got "^12.1.0" + registry-auth-token "^5.0.1" + registry-url "^6.0.0" + semver "^7.3.7" -pako@^1.0.11: +pako@^1.0.10, pako@^1.0.11, pako@^1.0.6: version "1.0.11" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz" integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== -parse-json@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.0.0.tgz#73e5114c986d143efa3712d4ea24db9a4266f60f" - integrity sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw== +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.0.0, parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== dependencies: "@babel/code-frame" "^7.0.0" error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" + json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" -parse5@5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" - integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== +parse-path@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/parse-path/-/parse-path-7.0.0.tgz" + integrity sha512-Euf9GG8WT9CdqwuWJGdf3RkUcTBArppHABkO7Lm8IzRQp0e2r/kkFnmhu4TSK30Wcu5rVAZLmfPKSBBi9tWFog== + dependencies: + protocols "^2.0.0" -pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= +parse-url@^8.1.0: + version "8.1.0" + resolved "https://registry.npmjs.org/parse-url/-/parse-url-8.1.0.tgz" + integrity sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w== + dependencies: + parse-path "^7.0.0" path-exists@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== path-is-absolute@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-key@^2.0.0, path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= +path-key@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz" + integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== -picomatch@^2.0.4, picomatch@^2.0.5: - version "2.2.2" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" - integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -pirates@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" - integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== +path-scurry@^1.10.1: + version "1.10.1" + resolved "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz" + integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ== dependencies: - node-modules-regexp "^1.0.0" + lru-cache "^9.1.1 || ^10.0.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +path-type@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz" + integrity sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pidtree@^0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz" + integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== + +pirates@^4.0.4: + version "4.0.6" + resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz" + integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== pkg-dir@^4.2.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz" integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== dependencies: find-up "^4.0.0" -portfinder@^1.0.25: - version "1.0.26" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.26.tgz#475658d56ca30bed72ac7f1378ed350bd1b64e70" - integrity sha512-Xi7mKxJHHMI3rIUrnm/jjUgwhbYMkp/XKEcZX3aG4BrumLpq3nmoQMX+ClYnDZnZ/New7IatC1no5RX0zo1vXQ== +pkg-dir@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz" + integrity sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA== dependencies: - async "^2.6.2" - debug "^3.1.1" - mkdirp "^0.5.1" + find-up "^5.0.0" -posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= +please-upgrade-node@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz" + integrity sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg== + dependencies: + semver-compare "^1.0.0" -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= +portfinder@^1.0.28: + version "1.0.32" + resolved "https://registry.npmjs.org/portfinder/-/portfinder-1.0.32.tgz" + integrity sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg== + dependencies: + async "^2.6.4" + debug "^3.2.7" + mkdirp "^0.5.6" -prettier@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.5.tgz#d6d56282455243f2f92cc1716692c08aa31522d4" - integrity sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg== +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -pretty-format@^25.2.1, pretty-format@^25.3.0: - version "25.3.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.3.0.tgz#d0a4f988ff4a6cd350342fdabbb809aeb4d49ad5" - integrity sha512-wToHwF8bkQknIcFkBqNfKu4+UZqnrLn/Vr+wwKQwwvPzkBfDDKp/qIabFqdgtoi5PEnM8LFByVsOrHoa3SpTVA== +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== dependencies: - "@jest/types" "^25.3.0" - ansi-regex "^5.0.0" - ansi-styles "^4.0.0" - react-is "^16.12.0" + fast-diff "^1.1.2" -pretty-format@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.0.1.tgz#a4fe54fe428ad2fd3413ca6bbd1ec8c2e277e197" - integrity sha512-SWxz6MbupT3ZSlL0Po4WF/KujhQaVehijR2blyRDCzk9e45EaYMVhMBn49fnRuHxtkSpXTes1GxNpVmH86Bxfw== +prettier@^3.2.5: + version "3.5.3" + resolved "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz" + integrity sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw== + +pretty-format@^29.0.0, pretty-format@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== dependencies: - "@jest/types" "^26.0.1" - ansi-regex "^5.0.0" - ansi-styles "^4.0.0" - react-is "^16.12.0" + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" process-nextick-args@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" - integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== + version "2.0.1" + resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +promise.allsettled@1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.7.tgz" + integrity sha512-hezvKvQQmsFkOdrZfYxUxkyxl8mgFQeT259Ajj9PXdbg9VzBCWrItOev72JyWxkCD5VSSqAeHmlN3tWx4DlmsA== + dependencies: + array.prototype.map "^1.0.5" + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + iterate-value "^1.0.2" prompts@^2.0.1: - version "2.0.4" - resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.0.4.tgz#179f9d4db3128b9933aa35f93a800d8fce76a682" - integrity sha512-HTzM3UWp/99A0gk51gAegwo1QRYA7xjcZufMNe33rCclFszUYAuHe1fIN/3ZmiHeGPkUsNaRyQm1hHOfM0PKxA== + version "2.4.2" + resolved "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== dependencies: - kleur "^3.0.2" - sisteransi "^1.0.0" + kleur "^3.0.3" + sisteransi "^1.0.5" -psl@^1.1.28: - version "1.1.31" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.31.tgz#e9aa86d0101b5b105cbe93ac6b784cd547276184" - integrity sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw== +proto-list@~1.2.1: + version "1.2.4" + resolved "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz" + integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA== -pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== +protocols@^2.0.0, protocols@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/protocols/-/protocols-2.0.1.tgz" + integrity sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q== + +proxy-agent@6.3.1: + version "6.3.1" + resolved "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.1.tgz" + integrity sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ== + dependencies: + agent-base "^7.0.2" + debug "^4.3.4" + http-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.2" + lru-cache "^7.14.1" + pac-proxy-agent "^7.0.1" + proxy-from-env "^1.1.0" + socks-proxy-agent "^8.0.2" + +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +pupa@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz" + integrity sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug== dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" + escape-goat "^4.0.0" -punycode@^2.1.0, punycode@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +pure-rand@^6.0.0: + version "6.0.4" + resolved "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz" + integrity sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA== qs@^6.4.0: - version "6.9.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.1.tgz#20082c65cb78223635ab1a9eaca8875a29bf8ec9" - integrity sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA== + version "6.11.2" + resolved "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz" + integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== + dependencies: + side-channel "^1.0.4" + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== -qs@~6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== +quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz" + integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== randombytes@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== dependencies: safe-buffer "^5.1.0" -react-is@^16.12.0: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== - -read-pkg-up@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" - integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== +rc@1.2.8: + version "1.2.8" + resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== dependencies: - find-up "^4.1.0" - read-pkg "^5.2.0" - type-fest "^0.8.1" + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" -read-pkg@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" - integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== - dependencies: - "@types/normalize-package-data" "^2.4.0" - normalize-package-data "^2.5.0" - parse-json "^5.0.0" - type-fest "^0.6.0" +react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== readable-stream@^2.2.2: - version "2.3.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" - integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== + version "2.3.8" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== dependencies: core-util-is "~1.0.0" inherits "~2.0.3" @@ -3375,986 +4821,1053 @@ readable-stream@^2.2.2: string_decoder "~1.1.1" util-deprecate "~1.0.1" +readable-stream@^3.4.0: + version "3.6.2" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + rechoir@^0.6.2: version "0.6.2" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" - integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= + resolved "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz" + integrity sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw== dependencies: resolve "^1.1.6" -regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== +regexp.prototype.flags@^1.5.1: + version "1.5.1" + resolved "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz" + integrity sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg== dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" + call-bind "^1.0.2" + define-properties "^1.2.0" + set-function-name "^2.0.0" -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= - -repeat-element@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" - integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== - -repeat-string@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= - -request-promise-core@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.3.tgz#e9a3c081b51380dfea677336061fea879a829ee9" - integrity sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ== +registry-auth-token@^5.0.1: + version "5.0.2" + resolved "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz" + integrity sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ== dependencies: - lodash "^4.17.15" + "@pnpm/npm-conf" "^2.1.0" -request-promise-native@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.8.tgz#a455b960b826e44e2bf8999af64dff2bfe58cb36" - integrity sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ== - dependencies: - request-promise-core "1.1.3" - stealthy-require "^1.1.1" - tough-cookie "^2.3.3" - -request@^2.88.2: - version "2.88.2" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" - integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.5.0" - tunnel-agent "^0.6.0" - uuid "^3.3.2" +registry-url@^6.0.0: + version "6.0.1" + resolved "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz" + integrity sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q== + dependencies: + rc "1.2.8" + +release-it@^17.0.3: + version "17.0.3" + resolved "https://registry.npmjs.org/release-it/-/release-it-17.0.3.tgz" + integrity sha512-QjTCmvQm91pwLEbvavEs9jofHNe8thsb9Uimin+8DNSwFRdUd73p0Owy2PP/Dzh/EegRkKq/o+4Pn1xp8pC1og== + dependencies: + "@iarna/toml" "2.2.5" + "@octokit/rest" "20.0.2" + async-retry "1.3.3" + chalk "5.3.0" + cosmiconfig "9.0.0" + execa "8.0.1" + git-url-parse "14.0.0" + globby "14.0.0" + got "13.0.0" + inquirer "9.2.12" + is-ci "3.0.1" + issue-parser "6.0.0" + lodash "4.17.21" + mime-types "2.1.35" + new-github-release-url "2.0.0" + node-fetch "3.3.2" + open "10.0.3" + ora "8.0.1" + os-name "5.1.0" + promise.allsettled "1.0.7" + proxy-agent "6.3.1" + semver "7.5.4" + shelljs "0.8.5" + update-notifier "7.0.0" + url-join "5.0.0" + wildcard-match "5.1.2" + yargs-parser "21.1.1" require-directory@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= - -require-main-filename@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" - integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== requires-port@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + +resolve-alpn@^1.2.0: + version "1.2.1" + resolved "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz" + integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== resolve-cwd@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz" integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== dependencies: resolve-from "^5.0.0" +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + resolve-from@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== -resolve-url@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= +resolve.exports@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz" + integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== -resolve@^1.1.6, resolve@^1.14.2: - version "1.15.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8" - integrity sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w== +resolve@^1.1.6, resolve@^1.20.0, resolve@^1.22.1: + version "1.22.8" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== dependencies: - path-parse "^1.0.6" + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" -resolve@^1.10.0, resolve@^1.17.0: - version "1.17.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" - integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== +responselike@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz" + integrity sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg== dependencies: - path-parse "^1.0.6" + lowercase-keys "^3.0.0" -resolve@^1.11.0: - version "1.11.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.1.tgz#ea10d8110376982fef578df8fc30b9ac30a07a3e" - integrity sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw== +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== dependencies: - path-parse "^1.0.6" + onetime "^5.1.0" + signal-exit "^3.0.2" -resolve@^1.12.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.13.1.tgz#be0aa4c06acd53083505abb35f4d66932ab35d16" - integrity sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w== +restore-cursor@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz" + integrity sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg== dependencies: - path-parse "^1.0.6" + onetime "^5.1.0" + signal-exit "^3.0.2" -resolve@^1.3.2, resolve@^1.9.0: - version "1.10.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.1.tgz#664842ac960795bbe758221cdccda61fb64b5f18" - integrity sha512-KuIe4mf++td/eFb6wkaPbMDnP6kObCaEtIDuHOUED6MNUo4K670KZUHuuvYPZDxNF0WVLw49n06M2m2dXphEzA== +restore-cursor@^5.0.0: + version "5.1.0" + resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz" + integrity sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA== dependencies: - path-parse "^1.0.6" + onetime "^7.0.0" + signal-exit "^4.1.0" -ret@~0.1.10: - version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== +retry@0.13.1: + version "0.13.1" + resolved "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== -rimraf@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.0.tgz#614176d4b3010b75e5c390eb0ee96f6dc0cebb9b" - integrity sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg== - dependencies: - glob "^7.1.3" +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rfdc@^1.4.1: + version "1.4.1" + resolved "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz" + integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== rimraf@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== dependencies: glob "^7.1.3" -rollup-plugin-terser@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-6.1.0.tgz#071866585aea104bfbb9dd1019ac523e63c81e45" - integrity sha512-4fB3M9nuoWxrwm39habpd4hvrbrde2W2GG4zEGPQg1YITNkM3Tqur5jSuXlWNzbv/2aMLJ+dZJaySc3GCD8oDw== - dependencies: - "@babel/code-frame" "^7.8.3" - jest-worker "^26.0.0" - serialize-javascript "^3.0.0" - terser "^4.7.0" - -rollup@^2.17.1: - version "2.17.1" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.17.1.tgz#d01a27c1b76e42efe2cd786609589f6332e81aa6" - integrity sha512-lVrtCXJ+08Eapa0SfApLmRNWNWm2FsYFnLPIJZJvZz2uI2Gv+dfPyu1zgF7KKF/HYFJDvjxbdCbI8lUVMnG7Sg== +rimraf@^5.0.5: + version "5.0.5" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz" + integrity sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A== + dependencies: + glob "^10.3.7" + +rollup@^4.9.6: + version "4.9.6" + resolved "https://registry.npmjs.org/rollup/-/rollup-4.9.6.tgz" + integrity sha512-05lzkCS2uASX0CiLFybYfVkwNbKZG5NFQ6Go0VWyogFTXXbR039UVsegViTntkk4OglHBdF54ccApXRRuXRbsg== + dependencies: + "@types/estree" "1.0.5" optionalDependencies: - fsevents "~2.1.2" + "@rollup/rollup-android-arm-eabi" "4.9.6" + "@rollup/rollup-android-arm64" "4.9.6" + "@rollup/rollup-darwin-arm64" "4.9.6" + "@rollup/rollup-darwin-x64" "4.9.6" + "@rollup/rollup-linux-arm-gnueabihf" "4.9.6" + "@rollup/rollup-linux-arm64-gnu" "4.9.6" + "@rollup/rollup-linux-arm64-musl" "4.9.6" + "@rollup/rollup-linux-riscv64-gnu" "4.9.6" + "@rollup/rollup-linux-x64-gnu" "4.9.6" + "@rollup/rollup-linux-x64-musl" "4.9.6" + "@rollup/rollup-win32-arm64-msvc" "4.9.6" + "@rollup/rollup-win32-ia32-msvc" "4.9.6" + "@rollup/rollup-win32-x64-msvc" "4.9.6" + fsevents "~2.3.2" + +run-applescript@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz" + integrity sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A== + +run-async@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz" + integrity sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q== -rsvp@^4.8.4: - version "4.8.4" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.4.tgz#b50e6b34583f3dd89329a2f23a8a2be072845911" - integrity sha512-6FomvYPfs+Jy9TfXmBpBuMWNH94SgCsZmJKcanySzgNNP6LjWxBvyLTa9KaMfDDM5oxRfrKDB0r/qeRsLwnBfA== +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +rxjs@^7.8.1: + version "7.8.1" + resolved "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz" + integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== + dependencies: + tslib "^2.1.0" -safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-array-concat@^1.0.1: + version "1.1.0" + resolved "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz" + integrity sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg== + dependencies: + call-bind "^1.0.5" + get-intrinsic "^1.2.2" + has-symbols "^1.0.3" + isarray "^2.0.5" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@^5.1.0: +safe-buffer@^5.1.0, safe-buffer@~5.2.0: version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= +safe-regex-test@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.2.tgz" + integrity sha512-83S9w6eFq12BBIJYvjMux6/dkirb8+4zJRA9cxNBVb7Wq5fJBW+Xze48WqR8pxua7bDuAaaAxtVVd4Idjp1dBQ== dependencies: - ret "~0.1.10" + call-bind "^1.0.5" + get-intrinsic "^1.2.2" + is-regex "^1.1.4" -"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -sane@^4.0.3: - version "4.1.0" - resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" - integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== - dependencies: - "@cnakazawa/watch" "^1.0.3" - anymatch "^2.0.0" - capture-exit "^2.0.0" - exec-sh "^0.3.2" - execa "^1.0.0" - fb-watchman "^2.0.0" - micromatch "^3.1.4" - minimist "^1.1.1" - walker "~1.0.5" - -saxes@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" - integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== - dependencies: - xmlchars "^2.2.0" + resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== secure-compare@3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/secure-compare/-/secure-compare-3.0.1.tgz#f1a0329b308b221fae37b9974f3d578d0ca999e3" - integrity sha1-8aAymzCLIh+uN7mXTz1XjQypmeM= + resolved "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz" + integrity sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw== -"semver@2 || 3 || 4 || 5": - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== +semver-compare@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz" + integrity sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow== -semver@7.x, semver@^7.2.1, semver@^7.3.2: - version "7.3.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" - integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== +semver-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz" + integrity sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA== + dependencies: + semver "^7.3.5" -semver@^5.3.0, semver@^5.4.1, semver@^5.5.0: - version "5.7.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" - integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== +semver-regex@^3.1.2: + version "3.1.4" + resolved "https://registry.npmjs.org/semver-regex/-/semver-regex-3.1.4.tgz" + integrity sha512-6IiqeZNgq01qGf0TId0t3NvKzSvUsjcpdEO3AQNeIjR6A2+ckTnQlDpl4qu1bjRv0RzN3FP9hzFmws3lKqRWkA== -semver@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.0.0.tgz#05e359ee571e5ad7ed641a6eec1e547ba52dea65" - integrity sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ== +semver@7.5.4, semver@^7.3.2, semver@^7.3.5, semver@^7.3.7, semver@^7.5.3, semver@^7.5.4: + version "7.5.4" + resolved "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" -semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -serialize-javascript@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-3.1.0.tgz#8bf3a9170712664ef2561b44b691eafe399214ea" - integrity sha512-JIJT1DGiWmIKhzRsG91aS6Ze4sFUrYbltlkg2onR5OrnNM02Kl/hnY/T4FN2omvyeBbQmMJv+K4cPOpGzOTFBg== +semver@^7.6.0: + version "7.7.1" + resolved "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz" + integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== + +serialize-javascript@^6.0.1: + version "6.0.2" + resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz" + integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== dependencies: randombytes "^2.1.0" -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= - -set-value@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" - integrity sha1-fbCPnT0i3H945Trzw79GZuzfzPE= +set-function-length@^1.1.1: + version "1.2.0" + resolved "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz" + integrity sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w== dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.1" - to-object-path "^0.3.0" + define-data-property "^1.1.1" + function-bind "^1.1.2" + get-intrinsic "^1.2.2" + gopd "^1.0.1" + has-property-descriptors "^1.0.1" -set-value@^2.0.0: +set-function-name@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" - integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + resolved "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz" + integrity sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA== dependencies: - shebang-regex "^1.0.0" + define-data-property "^1.0.1" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.0" shebang-command@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== dependencies: shebang-regex "^3.0.0" -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - shebang-regex@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shelljs@^0.8.3: - version "0.8.3" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.3.tgz#a7f3319520ebf09ee81275b2368adb286659b097" - integrity sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A== +shelljs@0.8.5, shelljs@^0.8.3: + version "0.8.5" + resolved "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz" + integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow== dependencies: glob "^7.0.0" interpret "^1.0.0" rechoir "^0.6.2" -shellwords@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" - integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" -signal-exit@^3.0.0, signal-exit@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= +signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== -sisteransi@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.0.tgz#77d9622ff909080f1c19e5f4a1df0c1b0a27b88c" - integrity sha512-N+z4pHB4AmUv0SjveWRd6q1Nj5w62m5jodv+GD8lvmbY/83T/rpbJGZOnK5T149OldDj4Db07BSv9xY4K6NTPQ== +signal-exit@^4.0.1, signal-exit@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz" + integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== + dependencies: + is-arrayish "^0.3.1" + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== slash@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== +slash@^5.1.0: + version "5.1.0" + resolved "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz" + integrity sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg== + +slice-ansi@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz" + integrity sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ== dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" + ansi-styles "^6.0.0" + is-fullwidth-code-point "^4.0.0" -snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== - dependencies: - kind-of "^3.2.0" - -snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - -source-map-resolve@^0.5.0: - version "0.5.2" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" - integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== - dependencies: - atob "^2.1.1" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" - -source-map-support@^0.5.6: - version "0.5.12" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599" - integrity sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ== +slice-ansi@^7.1.0: + version "7.1.0" + resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz" + integrity sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg== dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" + ansi-styles "^6.2.1" + is-fullwidth-code-point "^5.0.0" + +smart-buffer@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== + +smob@^1.0.0: + version "1.4.1" + resolved "https://registry.npmjs.org/smob/-/smob-1.4.1.tgz" + integrity sha512-9LK+E7Hv5R9u4g4C3p+jjLstaLe11MDsL21UpYaCNmapvMkYhqCV4A/f/3gyH8QjMyh6l68q9xC85vihY9ahMQ== + +socks-proxy-agent@^8.0.2: + version "8.0.2" + resolved "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz" + integrity sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g== + dependencies: + agent-base "^7.0.2" + debug "^4.3.4" + socks "^2.7.1" + +socks@^2.7.1: + version "2.7.1" + resolved "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz" + integrity sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ== + dependencies: + ip "^2.0.0" + smart-buffer "^4.2.0" -source-map-support@~0.5.12: +source-map-support@0.5.13: version "0.5.13" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz" integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" -source-map-url@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" - integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= - -source-map@^0.5.0, source-map@^0.5.6: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= +source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -source-map@^0.7.3: - version "0.7.3" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" - integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== -sourcemap-codec@^1.4.4: - version "1.4.4" - resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.4.tgz#c63ea927c029dd6bd9a2b7fa03b3fec02ad56e9f" - integrity sha512-CYAPYdBu34781kLHkaW3m6b/uUSyMOC2R61gcYMWooeuaGtjof86ZA/8T+qVPPt7np1085CR9hmMGrySwEc8Xg== +stack-utils@^2.0.3: + version "2.0.6" + resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" -spdx-correct@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" - integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== +stdin-discarder@^0.2.1: + version "0.2.2" + resolved "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz" + integrity sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ== + +stop-iteration-iterator@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz" + integrity sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ== dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" + internal-slot "^1.0.4" -spdx-exceptions@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" - integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== +string-argv@^0.3.2: + version "0.3.2" + resolved "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz" + integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== -spdx-expression-parse@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" - integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" + char-regex "^1.0.2" + strip-ansi "^6.0.0" -spdx-license-ids@^3.0.0: - version "3.0.5" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" - integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" -split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: - extend-shallow "^3.0.0" + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -sshpk@^1.7.0: - version "1.16.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" - integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - -stack-utils@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.2.tgz#5cf48b4557becb4638d0bc4f21d23f5d19586593" - integrity sha512-0H7QK2ECz3fyZMzQ8rH0j2ykpfbnd20BFtfg/SqVC2+sCTtcw0aDTGB7dk+de4U4uUeuz6nOtJcrkFFLG1B0Rg== +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== dependencies: - escape-string-regexp "^2.0.0" + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" -static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= +string-width@^7.0.0: + version "7.1.0" + resolved "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz" + integrity sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw== dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" + emoji-regex "^10.3.0" + get-east-asian-width "^1.0.0" + strip-ansi "^7.1.0" -stealthy-require@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" - integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= +string.prototype.trim@^1.2.8: + version "1.2.8" + resolved "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz" + integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" -string-length@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.1.tgz#4a973bf31ef77c4edbceadd6af2611996985f8a1" - integrity sha512-PKyXUd0LK0ePjSOnWn34V2uD6acUWev9uy0Ft05k0E8xRW+SKcA0F7eMr7h5xlzfn+4O3N+55rduYyet3Jk+jw== +string.prototype.trimend@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz" + integrity sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA== dependencies: - char-regex "^1.0.2" - strip-ansi "^6.0.0" + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" -string-width@^4.1.0, string-width@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" - integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== +string.prototype.trimstart@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz" + integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg== dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" string_decoder@~1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== dependencies: safe-buffer "~5.1.0" -strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" - integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: - ansi-regex "^5.0.0" + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^7.0.1, strip-ansi@^7.1.0: + version "7.1.0" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" strip-bom@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz" integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= - strip-final-newline@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== +strip-final-newline@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz" + integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz" + integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== + supports-color@^5.3.0: version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== dependencies: has-flag "^3.0.0" -supports-color@^7.0.0, supports-color@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" - integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: has-flag "^4.0.0" -supports-hyperlinks@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz#f663df252af5f37c5d49bbd7eeefa9e0b9e59e47" - integrity sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA== +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== dependencies: has-flag "^4.0.0" - supports-color "^7.0.0" -symbol-tree@^3.2.4: - version "3.2.4" - resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" - integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -terminal-link@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" - integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== +synckit@^0.11.0: + version "0.11.4" + resolved "https://registry.npmjs.org/synckit/-/synckit-0.11.4.tgz" + integrity sha512-Q/XQKRaJiLiFIBNN+mndW7S/RHxvwzuZS6ZwmRzUBqJBv/5QIKCEwkBC8GBf8EQJKYnaFs0wOZbKTXBPj8L9oQ== dependencies: - ansi-escapes "^4.2.1" - supports-hyperlinks "^2.0.0" + "@pkgr/core" "^0.2.3" + tslib "^2.8.1" -terser@^4.7.0: - version "4.8.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" - integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw== +terser@^5.17.4: + version "5.27.0" + resolved "https://registry.npmjs.org/terser/-/terser-5.27.0.tgz" + integrity sha512-bi1HRwVRskAjheeYl291n3JC4GgO/Ty4z1nVs5AAsmonJulGxpSektecnNedrwK9C7vpvVtcX3cw00VSLt7U2A== dependencies: + "@jridgewell/source-map" "^0.3.3" + acorn "^8.8.2" commander "^2.20.0" - source-map "~0.6.1" - source-map-support "~0.5.12" + source-map-support "~0.5.20" test-exclude@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz" integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== dependencies: "@istanbuljs/schema" "^0.1.2" glob "^7.1.4" minimatch "^3.0.4" -throat@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" - integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== -tmpl@1.0.x: - version "1.0.4" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" - integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== to-fast-properties@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - -to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= - dependencies: - kind-of "^3.0.2" - -to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== to-regex-range@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== dependencies: is-number "^7.0.0" -to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - -tough-cookie@^2.3.3, tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - -tough-cookie@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-3.0.1.tgz#9df4f57e739c26930a018184887f4adb7dca73b2" - integrity sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg== - dependencies: - ip-regex "^2.1.0" - psl "^1.1.28" - punycode "^2.1.1" - -tr46@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.0.2.tgz#03273586def1595ae08fedb38d7733cee91d2479" - integrity sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg== - dependencies: - punycode "^2.1.1" - -trim-right@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" - integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= +ts-api-utils@^1.3.0: + version "1.4.3" + resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz" + integrity sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw== -ts-jest@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.1.0.tgz#e9070fc97b3ea5557a48b67c631c74eb35e15417" - integrity sha512-JbhQdyDMYN5nfKXaAwCIyaWLGwevcT2/dbqRPsQeh6NZPUuXjZQZEfeLb75tz0ubCIgEELNm6xAzTe5NXs5Y4Q== +ts-jest@^29.0: + version "29.1.2" + resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.2.tgz" + integrity sha512-br6GJoH/WUX4pu7FbZXuWGKGNDuU7b8Uj77g/Sp7puZV6EXzuByl6JrECvm0MzVzSTkSHWTihsXt+5XYER5b+g== dependencies: bs-logger "0.x" - buffer-from "1.x" fast-json-stable-stringify "2.x" - json5 "2.x" + jest-util "^29.0.0" + json5 "^2.2.3" lodash.memoize "4.x" make-error "1.x" - micromatch "4.x" - mkdirp "1.x" - semver "7.x" - yargs-parser "18.x" - -tslib@^1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" - integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== - -tslib@^1.11.1: - version "1.11.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" - integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== - -tslib@^1.8.1: - version "1.9.3" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" - integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== + semver "^7.5.3" + yargs-parser "^21.0.1" -tslint-config-prettier@^1.18.0: - version "1.18.0" - resolved "https://registry.yarnpkg.com/tslint-config-prettier/-/tslint-config-prettier-1.18.0.tgz#75f140bde947d35d8f0d238e0ebf809d64592c37" - integrity sha512-xPw9PgNPLG3iKRxmK7DWr+Ea/SzrvfHtjFt5LBl61gk2UBG/DB9kCXRjv+xyIU1rUtnayLeMUVJBcMX8Z17nDg== +tslib@>=2, tslib@^2.0.1, tslib@^2.1.0, tslib@^2.8.1: + version "2.8.1" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== -tslint@^6.1.2: - version "6.1.2" - resolved "https://registry.yarnpkg.com/tslint/-/tslint-6.1.2.tgz#2433c248512cc5a7b2ab88ad44a6b1b34c6911cf" - integrity sha512-UyNrLdK3E0fQG/xWNqAFAC5ugtFyPO4JJR1KyyfQAyzR8W0fTRrC91A8Wej4BntFzcvETdCSDa/4PnNYJQLYiA== +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== dependencies: - "@babel/code-frame" "^7.0.0" - builtin-modules "^1.1.1" - chalk "^2.3.0" - commander "^2.12.1" - diff "^4.0.1" - glob "^7.1.1" - js-yaml "^3.13.1" - minimatch "^3.0.4" - mkdirp "^0.5.3" - resolve "^1.3.2" - semver "^5.3.0" - tslib "^1.10.0" - tsutils "^2.29.0" + prelude-ls "^1.2.1" -tsutils@^2.29.0: - version "2.29.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" - integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA== - dependencies: - tslib "^1.8.1" +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== -ttypescript@^1.5.10: - version "1.5.10" - resolved "https://registry.yarnpkg.com/ttypescript/-/ttypescript-1.5.10.tgz#5045083a91cf09a735ecc95d4711c1f3b83f2059" - integrity sha512-Hk7TRej1hM+p+Fo+Pyb/XK9pe9CAt3Sh5n5YRutxFS8hUgkh2u1Vd2K40kMcNP3WYhiVFBMqXwM/2E8O95Ep6g== - dependencies: - resolve "^1.9.0" +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - dependencies: - safe-buffer "^5.0.1" +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= +type-fest@^1.0.1: + version "1.4.0" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz" + integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA== -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= - dependencies: - prelude-ls "~1.1.2" +type-fest@^2.13.0, type-fest@^2.5.1: + version "2.19.0" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz" + integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== -type-detect@4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" - integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== +typed-array-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz" + integrity sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + is-typed-array "^1.1.10" -type-fest@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" - integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== +typed-array-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz" + integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" -type-fest@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" - integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== +typed-array-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz" + integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" -type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== +typed-array-length@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz" + integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + is-typed-array "^1.1.9" typedarray-to-buffer@^3.1.5: version "3.1.5" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + resolved "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz" integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== dependencies: is-typedarray "^1.0.0" typedarray@^0.0.6: version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz" + integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== -typescript@^3.8.0-dev.20200111: - version "3.8.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" - integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== +typescript@^4.9.5: + version "4.9.5" + resolved "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== -typescript@^3.9.5: - version "3.9.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36" - integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ== +typescript@next: + version "6.0.0-dev.20260323" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-6.0.0-dev.20260323.tgz#2aa2363d7e1b574a932b454ffb02edb4ce8292b4" + integrity sha512-nCvhfEJAUm4YK06mVZUCgwdCFT0ArNJlR4KYBcspKNvh+mAsNKNSTQ2NvYxQKV9mPFoey03HpO86XqxKhlOeFA== -union-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" - integrity sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ= +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^0.4.3" + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" + +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + +unicorn-magic@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz" + integrity sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ== union@~0.5.0: version "0.5.0" - resolved "https://registry.yarnpkg.com/union/-/union-0.5.0.tgz#b2c11be84f60538537b846edb9ba266ba0090075" + resolved "https://registry.npmjs.org/union/-/union-0.5.0.tgz" integrity sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA== dependencies: qs "^6.4.0" -unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= +unique-string@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz" + integrity sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ== + dependencies: + crypto-random-string "^4.0.0" + +universal-user-agent@^6.0.0: + version "6.0.1" + resolved "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz" + integrity sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ== + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +update-browserslist-db@^1.0.13: + version "1.0.13" + resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz" + integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== dependencies: - has-value "^0.3.1" - isobject "^3.0.0" + escalade "^3.1.1" + picocolors "^1.0.0" + +update-notifier@7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/update-notifier/-/update-notifier-7.0.0.tgz" + integrity sha512-Hv25Bh+eAbOLlsjJreVPOs4vd51rrtCrmhyOJtbpAojro34jS4KQaEp4/EvlHJX7jSO42VvEFpkastVyXyIsdQ== + dependencies: + boxen "^7.1.1" + chalk "^5.3.0" + configstore "^6.0.0" + import-lazy "^4.0.0" + is-in-ci "^0.1.0" + is-installed-globally "^0.4.0" + is-npm "^6.0.0" + latest-version "^7.0.0" + pupa "^3.1.0" + semver "^7.5.4" + semver-diff "^4.0.0" + xdg-basedir "^5.1.0" uri-js@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" - integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + version "4.4.1" + resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== dependencies: punycode "^2.1.0" -urix@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= - -url-join@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/url-join/-/url-join-2.0.5.tgz#5af22f18c052a000a48d7b82c5e9c2e2feeda728" - integrity sha1-WvIvGMBSoACkjXuCxenC4v7tpyg= +url-join@5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz" + integrity sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA== -use@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== +url-join@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz" + integrity sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA== -util-deprecate@~1.0.1: +util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -uuid@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" - integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== -uuid@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b" - integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg== - -v8-to-istanbul@^4.1.3: - version "4.1.3" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-4.1.3.tgz#22fe35709a64955f49a08a7c7c959f6520ad6f20" - integrity sha512-sAjOC+Kki6aJVbUOXJbcR0MnbfjvBzwKZazEJymA2IX49uoOdEdk+4fBq5cXgYgiyKtAyrrJNtBZdOeDIF+Fng== +v8-to-istanbul@^9.0.1: + version "9.2.0" + resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz" + integrity sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA== dependencies: + "@jridgewell/trace-mapping" "^0.3.12" "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^1.6.0" - source-map "^0.7.3" + convert-source-map "^2.0.0" -validate-npm-package-license@^3.0.1: - version "3.0.4" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== +walker@^1.0.8: + version "1.0.8" + resolved "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" + makeerror "1.0.12" -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= +wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz" + integrity sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg== dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" + defaults "^1.0.3" -w3c-hr-time@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" - integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== - dependencies: - browser-process-hrtime "^1.0.0" +web-streams-polyfill@^3.0.3: + version "3.3.2" + resolved "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.2.tgz" + integrity sha512-3pRGuxRF5gpuZc0W+EpwQRmCD7gRqcDOMt688KmdlDAgAyaB1XlN0zq2njfDNm44XVdIouE7pZ6GzbdyH47uIQ== -w3c-xmlserializer@^2.0.0: +whatwg-encoding@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" - integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== + resolved "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz" + integrity sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg== dependencies: - xml-name-validator "^3.0.0" + iconv-lite "0.6.3" -walker@^1.0.7, walker@~1.0.5: - version "1.0.7" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" - integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== dependencies: - makeerror "1.0.x" - -webidl-conversions@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" - integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" -webidl-conversions@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" - integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== +which-pm-runs@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz" + integrity sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA== -whatwg-encoding@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" - integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== +which-typed-array@^1.1.11, which-typed-array@^1.1.13: + version "1.1.13" + resolved "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz" + integrity sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow== dependencies: - iconv-lite "0.4.24" + available-typed-arrays "^1.0.5" + call-bind "^1.0.4" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" -whatwg-mimetype@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" - integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== +which@^2.0.1: + version "2.0.2" + resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" -whatwg-url@^8.0.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.1.0.tgz#c628acdcf45b82274ce7281ee31dd3c839791771" - integrity sha512-vEIkwNi9Hqt4TV9RdnaBPNt+E2Sgmo3gePebCRgZ1R7g6d23+53zCTnuB0amKI4AXq6VM8jj2DUAa0S1vjJxkw== +widest-line@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz" + integrity sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig== dependencies: - lodash.sortby "^4.7.0" - tr46 "^2.0.2" - webidl-conversions "^5.0.0" + string-width "^5.0.1" -which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= +wildcard-match@5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/wildcard-match/-/wildcard-match-5.1.2.tgz" + integrity sha512-qNXwI591Z88c8bWxp+yjV60Ch4F8Riawe3iGxbzquhy8Xs9m+0+SLFBGb/0yCTIDElawtaImC37fYZ+dr32KqQ== -which@^1.2.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== +windows-release@^5.0.1: + version "5.1.1" + resolved "https://registry.npmjs.org/windows-release/-/windows-release-5.1.1.tgz" + integrity sha512-NMD00arvqcq2nwqc5Q6KtrSRHK+fVD31erE5FEMahAw5PmVCgD7MUXodq3pdZSUkqA9Cda2iWx6s1XYwiJWRmw== dependencies: - isexe "^2.0.0" + execa "^5.1.1" -which@^2.0.1, which@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== -wordwrap@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" wrap-ansi@^6.2.0: version "6.2.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz" integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== dependencies: ansi-styles "^4.0.0" string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + +wrap-ansi@^9.0.0: + version "9.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz" + integrity sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q== + dependencies: + ansi-styles "^6.2.1" + string-width "^7.0.0" + strip-ansi "^7.1.0" + wrappy@1: version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -write-file-atomic@^3.0.0: +write-file-atomic@^3.0.3: version "3.0.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz" integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== dependencies: imurmurhash "^0.1.4" @@ -4362,47 +5875,63 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -ws@^7.2.3: - version "7.3.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.0.tgz#4b2f7f219b3d3737bc1a2fbf145d825b94d38ffd" - integrity sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w== - -xml-name-validator@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" - integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== +write-file-atomic@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" -xmlchars@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" - integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== +xdg-basedir@^5.0.1, xdg-basedir@^5.1.0: + version "5.1.0" + resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz" + integrity sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ== -y18n@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" - integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yargs-parser@18.x, yargs-parser@^18.1.1: - version "18.1.2" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.2.tgz#2f482bea2136dbde0861683abea7756d30b504f1" - integrity sha512-hlIPNR3IzC1YuL1c2UwwDKpXlNFBqD1Fswwh1khz5+d8Cq/8yc/Mn0i+rQXduu8hcrFKvO7Eryk+09NecTQAAQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== -yargs@^15.3.1: - version "15.3.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.3.1.tgz#9505b472763963e54afe60148ad27a330818e98b" - integrity sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA== - dependencies: - cliui "^6.0.0" - decamelize "^1.2.0" - find-up "^4.1.0" - get-caller-file "^2.0.1" +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yaml@^1.10.0: + version "1.10.2" + resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + +yaml@^2.7.0: + version "2.7.0" + resolved "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz" + integrity sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA== + +yargs-parser@21.1.1, yargs-parser@^21.0.1, yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.3.1: + version "17.7.2" + resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^4.2.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^18.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==