From acd70ae6a8067b8721383c7eea3bf143db1656a5 Mon Sep 17 00:00:00 2001 From: JounQin Date: Tue, 7 Nov 2023 13:30:56 +0800 Subject: [PATCH] feat: first blood, should just work --- .changeset/config.json | 2 +- .github/workflows/release.yml | 4 +- README.md | 58 +++++++++---- docs/index.html | 2 +- package.json | 9 +-- src/index.ts | 148 +++++++++++++++++++++++++++++++++- src/types.ts | 13 +++ src/utils.ts | 44 ++++++++++ test/basic.spec.ts | 59 +++++++++++++- tsconfig.json | 1 + vercel.json | 2 +- vitest.config.ts | 3 +- yarn.lock | 142 ++++++++++++++------------------ 13 files changed, 375 insertions(+), 112 deletions(-) create mode 100644 src/types.ts create mode 100644 src/utils.ts diff --git a/.changeset/config.json b/.changeset/config.json index 50ee5ae..6e24af1 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -3,7 +3,7 @@ "changelog": [ "@changesets/changelog-github", { - "repo": "un-ts/lib-boilerplate" + "repo": "un-ts/fetch-api" } ], "commit": false, diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d8ed634..a5143dd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,8 +33,8 @@ jobs: with: publish: yarn release version: yarn changeset version - commit: 'chore: release lib-boilerplate' - title: 'chore: release lib-boilerplate' + commit: 'chore: release fetch-api' + title: 'chore: release fetch-api' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/README.md b/README.md index 28a347c..01b6391 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# lib-boilerplate +# fetch-api -[![GitHub Actions](https://github.com/un-ts/lib-boilerplate/workflows/CI/badge.svg)](https://github.com/un-ts/lib-boilerplate/actions/workflows/ci.yml) -[![Codecov](https://img.shields.io/codecov/c/github/un-ts/lib-boilerplate.svg)](https://codecov.io/gh/un-ts/lib-boilerplate) -[![type-coverage](https://img.shields.io/badge/dynamic/json.svg?label=type-coverage&prefix=%E2%89%A5&suffix=%&query=$.typeCoverage.atLeast&uri=https%3A%2F%2Fraw.githubusercontent.com%2Fun-ts%2Flib-boilerplate%2Fmain%2Fpackage.json)](https://github.com/plantain-00/type-coverage) -[![npm](https://img.shields.io/npm/v/lib-boilerplate.svg)](https://www.npmjs.com/package/lib-boilerplate) -[![GitHub Release](https://img.shields.io/github/release/un-ts/lib-boilerplate)](https://github.com/un-ts/lib-boilerplate/releases) +[![GitHub Actions](https://github.com/un-ts/fetch-api/workflows/CI/badge.svg)](https://github.com/un-ts/fetch-api/actions/workflows/ci.yml) +[![Codecov](https://img.shields.io/codecov/c/github/un-ts/fetch-api.svg)](https://codecov.io/gh/un-ts/fetch-api) +[![type-coverage](https://img.shields.io/badge/dynamic/json.svg?label=type-coverage&prefix=%E2%89%A5&suffix=%&query=$.typeCoverage.atLeast&uri=https%3A%2F%2Fraw.githubusercontent.com%2Fun-ts%2Ffetch-api%2Fmain%2Fpackage.json)](https://github.com/plantain-00/type-coverage) +[![npm](https://img.shields.io/npm/v/fetch-api.svg)](https://www.npmjs.com/package/fetch-api) +[![GitHub Release](https://img.shields.io/github/release/un-ts/fetch-api)](https://github.com/un-ts/fetch-api/releases) [![Conventional Commits](https://img.shields.io/badge/conventional%20commits-1.0.0-yellow.svg)](https://conventionalcommits.org) [![Renovate enabled](https://img.shields.io/badge/renovate-enabled-brightgreen.svg)](https://renovatebot.com) @@ -12,7 +12,7 @@ [![Code Style: Prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier) [![changesets](https://img.shields.io/badge/maintained%20with-changesets-176de3.svg)](https://github.com/changesets/changesets) -A simple library boilerplate. +A simple but elegant `fetch` API wrapper, use `fetch` like a charm ## TOC @@ -30,21 +30,51 @@ A simple library boilerplate. ```sh # pnpm -pnpm add lib-boilerplate +pnpm add fetch-api # yarn -yarn add lib-boilerplate +yarn add fetch-api # npm -npm i lib-boilerplate +npm i fetch-api ``` ### API -```js -import echo from 'lib-boilerplate' - -echo() +```ts +import { ApiMethod, createFetchApi, fetchApi, interceptors } from 'fetch-api' + +// plain url, GET method +await fetchApi('url') + +// with options, `body`, `query`, etc. +await fetchApi('url', { + method: ApiMethod.POST, // or 'POST' + // plain object or array, or BodyInit + body: {}, + // URLSearchParametersOptions + query: { + key: 'value', + }, + // json: boolean, // whether auto stringify body to json, default true for plain object or array, otherwise false + // type: 'arrayBuffer' | 'blob' | 'json' | 'text' | null, `null` means plain `Response` +}) + +const interceptor: ApiInterceptor = (req, next) => { + // do something with req + const res = await next(req) + // do something with res + return res +} + +// add interceptor +interceptors.use(interceptor) + +// remove interceptor +interceptors.eject(interceptor) + +// create a new isolated `fetchApi` with its own `interceptors` +const { fetchApi, interceptors } = createFetchApi() ``` ## Sponsors diff --git a/docs/index.html b/docs/index.html index 09735df..caaecf6 100644 --- a/docs/index.html +++ b/docs/index.html @@ -10,7 +10,7 @@ name="viewport" content="width=device-width, initial-scale=1.0" /> - lib-boilerplate + fetch-api
diff --git a/package.json b/package.json index 937c499..d45e2dc 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { - "name": "lib-boilerplate", + "name": "fetch-api", "version": "0.1.0", "type": "module", - "description": "A simple library boilerplate.", - "repository": "git+https://github.com/un-ts/lib-boilerplate.git", + "description": "A simple but elegant `fetch` API wrapper, use `fetch` like a charm", + "repository": "git+https://github.com/un-ts/fetch-api.git", "author": "JounQin (https://www.1stG.me) ", "funding": "https://opencollective.com/unts", "license": "MIT", @@ -49,9 +49,8 @@ "@types/node": "^20.8.10", "@types/react": "^18.2.36", "@types/react-dom": "^18.2.14", - "@types/web": "^0.0.119", "@vitejs/plugin-react-swc": "^3.4.1", - "@vitest/coverage-v8": "^0.34.6", + "@vitest/coverage-istanbul": "^0.34.6", "commitlint": "^18.2.0", "eslint": "^8.53.0", "github-markdown-css": "^5.4.0", diff --git a/src/index.ts b/src/index.ts index f3bea86..0c39293 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1 +1,147 @@ -export default () => 'Hello World!' +import type { URLSearchParametersOptions, ValueOf } from './types.js' +import { CONTENT_TYPE, isPlainObject, normalizeUrl } from './utils.js' + +export type * from './types.js' +export * from './utils.js' + +export const ApiMethod = { + GET: 'GET', + POST: 'POST', + PATCH: 'PATCH', + PUT: 'PUT', + DELETE: 'DELETE', +} as const + +export type ApiMethod = ValueOf + +export interface FetchApiOptions extends Omit { + method?: ApiMethod + body?: BodyInit | object + query?: URLSearchParametersOptions + json?: boolean + type?: 'arrayBuffer' | 'blob' | 'json' | 'text' | null +} + +export interface InterceptorRequest extends FetchApiOptions { + url: string +} + +export type ApiInterceptor = ( + request: InterceptorRequest, + next: (request: InterceptorRequest) => PromiseLike, +) => PromiseLike | Response + +export interface ResponseError extends Error { + data?: T | null + response?: Response | null +} + +export class ApiInterceptors { + readonly #interceptors: ApiInterceptor[] = [] + + get length() { + return this.#interceptors.length + } + + at(index: number) { + return this.#interceptors.at(index) + } + + use(...interceptors: ApiInterceptor[]) { + this.#interceptors.push(...interceptors) + return this + } + + eject(interceptor: ApiInterceptor) { + const index = this.#interceptors.indexOf(interceptor) + if (index > -1) { + this.#interceptors.splice(index, 1) + return true + } + return false + } +} + +export const createFetchApi = () => { + const interceptors = new ApiInterceptors() + + function fetchApi( + url: string, + options: FetchApiOptions & { type: null }, + ): Promise + function fetchApi( + url: string, + options: FetchApiOptions & { type: 'arraybuffer' }, + ): Promise + function fetchApi( + url: string, + options: FetchApiOptions & { type: 'blob' }, + ): Promise + function fetchApi( + url: string, + options: FetchApiOptions & { type: 'text' }, + ): Promise + function fetchApi( + url: string, + options?: FetchApiOptions & { type?: 'json' }, + ): Promise + // eslint-disable-next-line sonarjs/cognitive-complexity + async function fetchApi( + url: string, + { + method = ApiMethod.GET, + body, + headers, + json = body != null && (isPlainObject(body) || Array.isArray(body)), + type = 'json', + ...rest + }: FetchApiOptions = {}, + ) { + headers = new Headers(headers) + + if (json && !headers.has(CONTENT_TYPE)) { + headers.append(CONTENT_TYPE, 'application/json') + } + + let index = 0 + + const next = async (request: InterceptorRequest) => { + if (index < interceptors.length) { + return interceptors.at(index++)!(request, next) + } + const { body, url, query, ...rest } = request + const response = await fetch(normalizeUrl(url, query), { + ...rest, + body: json ? JSON.stringify(body) : (body as BodyInit), + }) + if (response.ok) { + return response + } + let data: unknown = null + if (type != null) { + try { + data = await response.clone()[type]() + } catch { + data = await response.clone().text() + } + } + throw Object.assign(new Error(response.statusText), { + data, + response, + }) + } + + const response = await next({ + url, + method, + body, + headers, + ...rest, + }) + return type == null ? response : response.clone()[type]() + } + + return { interceptors, fetchApi } +} + +export const { interceptors, fetchApi } = createFetchApi() diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..5e56569 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,13 @@ +export type Nullable = T | null | undefined + +export type ValueOf = T[keyof T] + +export type URLSearchParametersInit = ConstructorParameters< + typeof URLSearchParams + // eslint-disable-next-line @typescript-eslint/no-magic-numbers +>[0] + +export type URLSearchParametersOptions = + | Record> + | URLSearchParametersInit + | object diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..6e8e70f --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,44 @@ +import { + Nullable, + URLSearchParametersInit, + URLSearchParametersOptions, + ValueOf, +} from './types.js' + +export const CONTENT_TYPE = 'Content-Type' + +// eslint-disable-next-line @typescript-eslint/unbound-method +const { toString } = Object.prototype // type-coverage:ignore-line - TODO: report bug + +const objectTag = '[object Object]' + +export const isPlainObject = (value: unknown): value is T => + toString.call(value) === objectTag + +export const cleanNilValues = (input: T, empty?: boolean): T => { + if (!isPlainObject(input)) { + return input + } + + for (const _key of Object.keys(input)) { + const key = _key as keyof T + const value = input[key] as Nullable> + if (empty ? !value : value == null) { + delete input[key] + } else { + input[key] = cleanNilValues(value, empty) as (T & object)[keyof T] + } + } + + return input +} + +export const normalizeUrl = ( + url: string, + query?: URLSearchParametersOptions, +) => { + const search = new URLSearchParams( + cleanNilValues(query, true) as URLSearchParametersInit, + ).toString() + return search ? url + (url.includes('?') ? '&' : '?') + search : url +} diff --git a/test/basic.spec.ts b/test/basic.spec.ts index 482d0dc..79d923c 100644 --- a/test/basic.spec.ts +++ b/test/basic.spec.ts @@ -1,5 +1,58 @@ -import echo from 'lib-boilerplate' +import { type ApiInterceptor, fetchApi, interceptors } from 'fetch-api' -test('it should just work', () => { - expect(echo()).toBe('Hello World!') +test('it should just work', async () => { + expect( + await fetchApi<{ + id: number + userId: number + }>('https://jsonplaceholder.typicode.com/todos/1'), + ).toMatchInlineSnapshot(` + { + "completed": false, + "id": 1, + "title": "delectus aut autem", + "userId": 1, + } + `) +}) + +test('interceptors should just work', async () => { + const interceptor: ApiInterceptor = (req, next) => { + if (!/^https?:\/\//.test(req.url)) { + req.url = + 'https://jsonplaceholder.typicode.com' + + (req.url.startsWith('/') ? '' : '/') + + req.url + } + return next(req) + } + + // eslint-disable-next-line @typescript-eslint/no-floating-promises + expect(() => fetchApi('/todos/1')).rejects.toMatchInlineSnapshot( + '[TypeError: Failed to parse URL from /todos/1]', + ) + + interceptors.use(interceptor) + + expect( + await fetchApi<{ + id: number + userId: number + }>('todos/1'), + ).toMatchInlineSnapshot(` + { + "completed": false, + "id": 1, + "title": "delectus aut autem", + "userId": 1, + } + `) + + expect(interceptors.eject(interceptor)).toBe(true) + expect(interceptors.eject(interceptor)).toBe(false) + + // eslint-disable-next-line @typescript-eslint/no-floating-promises + expect(() => fetchApi('/todos/1')).rejects.toMatchInlineSnapshot( + '[TypeError: Failed to parse URL from /todos/1]', + ) }) diff --git a/tsconfig.json b/tsconfig.json index dd6cd35..4822b21 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,7 @@ { "extends": "@1stg/tsconfig/node16", "compilerOptions": { + "lib": ["DOM", "ESNext"], "module": "Node16", "rootDir": "." } diff --git a/vercel.json b/vercel.json index 47d9a4f..14f9d3f 100644 --- a/vercel.json +++ b/vercel.json @@ -1,7 +1,7 @@ { "version": 2, "alias": [ - "lib-boilerplate.vercel.app" + "ifetch.vercel.app" ], "github": { "silent": true diff --git a/vitest.config.ts b/vitest.config.ts index 3664c9b..94ce767 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -9,11 +9,12 @@ export default defineConfig({ ], resolve: { alias: { - 'lib-boilerplate': './src/index.ts', + 'fetch-api': './src/index.ts', }, }, test: { coverage: { + provider: 'istanbul', reporter: ['lcov', 'json', 'text'], }, }, diff --git a/yarn.lock b/yarn.lock index f20e690..d851c04 100644 --- a/yarn.lock +++ b/yarn.lock @@ -407,7 +407,7 @@ __metadata: languageName: node linkType: hard -"@babel/core@npm:^7.22.5": +"@babel/core@npm:^7.12.3, @babel/core@npm:^7.22.5": version: 7.23.2 resolution: "@babel/core@npm:7.23.2" dependencies: @@ -728,7 +728,7 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.22.15, @babel/parser@npm:^7.23.0": +"@babel/parser@npm:^7.14.7, @babel/parser@npm:^7.22.15, @babel/parser@npm:^7.23.0": version: 7.23.0 resolution: "@babel/parser@npm:7.23.0" bin: @@ -2089,13 +2089,6 @@ __metadata: languageName: node linkType: hard -"@bcoe/v8-coverage@npm:^0.2.3": - version: 0.2.3 - resolution: "@bcoe/v8-coverage@npm:0.2.3" - checksum: 1a1f0e356a3bb30b5f1ced6f79c413e6ebacf130421f15fac5fcd8be5ddf98aedb4404d7f5624e3285b700e041f9ef938321f3ca4d359d5b716f96afa120d88d - languageName: node - linkType: hard - "@bloomberg/record-tuple-polyfill@npm:^0.0.4": version: 0.0.4 resolution: "@bloomberg/record-tuple-polyfill@npm:0.0.4" @@ -3639,7 +3632,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.12, @jridgewell/trace-mapping@npm:^0.3.17, @jridgewell/trace-mapping@npm:^0.3.18, @jridgewell/trace-mapping@npm:^0.3.9": +"@jridgewell/trace-mapping@npm:^0.3.17, @jridgewell/trace-mapping@npm:^0.3.18, @jridgewell/trace-mapping@npm:^0.3.9": version: 0.3.20 resolution: "@jridgewell/trace-mapping@npm:0.3.20" dependencies: @@ -4803,13 +4796,6 @@ __metadata: languageName: node linkType: hard -"@types/istanbul-lib-coverage@npm:^2.0.1": - version: 2.0.5 - resolution: "@types/istanbul-lib-coverage@npm:2.0.5" - checksum: 978eaf327f9a238eb1e2828b93b4b48e288ffb88c4be81330c74477ab8b93fac41a8784260d72bdd9995535d70608f738199b6364fd3344842e924a3ec3301e7 - languageName: node - linkType: hard - "@types/json-schema@npm:^7.0.9": version: 7.0.14 resolution: "@types/json-schema@npm:7.0.14" @@ -5026,13 +5012,6 @@ __metadata: languageName: node linkType: hard -"@types/web@npm:^0.0.119": - version: 0.0.119 - resolution: "@types/web@npm:0.0.119" - checksum: abaabd19a59368939e5048590d6287bb5a9707031434ca11cdfa6f348ed42744f673f02cdca0de8c744898ffdc5d100df2e606abffaacb32c903b47a2ef8ac7e - languageName: node - linkType: hard - "@types/whatwg-mimetype@npm:3.0.1": version: 3.0.1 resolution: "@types/whatwg-mimetype@npm:3.0.1" @@ -5179,24 +5158,20 @@ __metadata: languageName: node linkType: hard -"@vitest/coverage-v8@npm:^0.34.6": +"@vitest/coverage-istanbul@npm:^0.34.6": version: 0.34.6 - resolution: "@vitest/coverage-v8@npm:0.34.6" + resolution: "@vitest/coverage-istanbul@npm:0.34.6" dependencies: - "@ampproject/remapping": "npm:^2.2.1" - "@bcoe/v8-coverage": "npm:^0.2.3" istanbul-lib-coverage: "npm:^3.2.0" + istanbul-lib-instrument: "npm:^6.0.0" istanbul-lib-report: "npm:^3.0.1" istanbul-lib-source-maps: "npm:^4.0.1" istanbul-reports: "npm:^3.1.5" - magic-string: "npm:^0.30.1" picocolors: "npm:^1.0.0" - std-env: "npm:^3.3.3" test-exclude: "npm:^6.0.0" - v8-to-istanbul: "npm:^9.1.0" peerDependencies: vitest: ">=0.32.0 <1" - checksum: f25afdc496d44b387752b88e82e4643557711f72d88d3da363785386cbd523af3f6049f5f91a3e6afc9c2417aa1d97e09801c0e5e62cb96cc9d419cc9629de2a + checksum: f86ea2b11842a9528e5483683735cc402342e0b98dce00d5cd7ff2bf1da542ec704dc3ba58184f9df96798d8b0c1c6d24d6d11fad4eaac9999487e45d5a3e8b0 languageName: node linkType: hard @@ -9504,6 +9479,45 @@ __metadata: languageName: node linkType: hard +"fetch-api@workspace:.": + version: 0.0.0-use.local + resolution: "fetch-api@workspace:." + dependencies: + "@1stg/app-config": "npm:^9.0.0" + "@1stg/lib-config": "npm:^12.0.0" + "@changesets/changelog-github": "npm:^0.4.8" + "@changesets/cli": "npm:^2.26.2" + "@mdx-js/rollup": "npm:^3.0.0" + "@pkgr/rollup": "npm:^4.1.3" + "@size-limit/preset-small-lib": "npm:^10.0.2" + "@types/mdx": "npm:^2.0.9" + "@types/node": "npm:^20.8.10" + "@types/react": "npm:^18.2.36" + "@types/react-dom": "npm:^18.2.14" + "@vitejs/plugin-react-swc": "npm:^3.4.1" + "@vitest/coverage-istanbul": "npm:^0.34.6" + commitlint: "npm:^18.2.0" + eslint: "npm:^8.53.0" + github-markdown-css: "npm:^5.4.0" + lint-staged: "npm:^13.3.0" + npm-run-all: "npm:^4.1.5" + react: "npm:^18.2.0" + react-dom: "npm:^18.2.0" + react-router-dom: "npm:^6.18.0" + rehype-slug: "npm:^6.0.0" + remark-gfm: "npm:^4.0.0" + simple-git-hooks: "npm:^2.9.0" + size-limit: "npm:^10.0.2" + stylelint: "npm:^15.11.0" + tslib: "npm:^2.6.2" + type-coverage: "npm:^2.27.0" + typescript: "npm:^5.2.2" + unplugin-auto-import: "npm:^0.16.7" + vite: "npm:^4.5.0" + vitest: "npm:^0.34.6" + languageName: unknown + linkType: soft + "figures@npm:^1.3.5": version: 1.7.0 resolution: "figures@npm:1.7.0" @@ -11620,6 +11634,19 @@ __metadata: languageName: node linkType: hard +"istanbul-lib-instrument@npm:^6.0.0": + version: 6.0.1 + resolution: "istanbul-lib-instrument@npm:6.0.1" + dependencies: + "@babel/core": "npm:^7.12.3" + "@babel/parser": "npm:^7.14.7" + "@istanbuljs/schema": "npm:^0.1.2" + istanbul-lib-coverage: "npm:^3.2.0" + semver: "npm:^7.5.4" + checksum: 95fd8c66e586840989cb3c7819c6da66c4742a6fedbf16b51a5c7f1898941ad07b79ddff020f479d3a1d76743ecdbf255d93c35221875687477d4b118026e7e7 + languageName: node + linkType: hard + "istanbul-lib-report@npm:^3.0.0, istanbul-lib-report@npm:^3.0.1": version: 3.0.1 resolution: "istanbul-lib-report@npm:3.0.1" @@ -12056,46 +12083,6 @@ __metadata: languageName: node linkType: hard -"lib-boilerplate@workspace:.": - version: 0.0.0-use.local - resolution: "lib-boilerplate@workspace:." - dependencies: - "@1stg/app-config": "npm:^9.0.0" - "@1stg/lib-config": "npm:^12.0.0" - "@changesets/changelog-github": "npm:^0.4.8" - "@changesets/cli": "npm:^2.26.2" - "@mdx-js/rollup": "npm:^3.0.0" - "@pkgr/rollup": "npm:^4.1.3" - "@size-limit/preset-small-lib": "npm:^10.0.2" - "@types/mdx": "npm:^2.0.9" - "@types/node": "npm:^20.8.10" - "@types/react": "npm:^18.2.36" - "@types/react-dom": "npm:^18.2.14" - "@types/web": "npm:^0.0.119" - "@vitejs/plugin-react-swc": "npm:^3.4.1" - "@vitest/coverage-v8": "npm:^0.34.6" - commitlint: "npm:^18.2.0" - eslint: "npm:^8.53.0" - github-markdown-css: "npm:^5.4.0" - lint-staged: "npm:^13.3.0" - npm-run-all: "npm:^4.1.5" - react: "npm:^18.2.0" - react-dom: "npm:^18.2.0" - react-router-dom: "npm:^6.18.0" - rehype-slug: "npm:^6.0.0" - remark-gfm: "npm:^4.0.0" - simple-git-hooks: "npm:^2.9.0" - size-limit: "npm:^10.0.2" - stylelint: "npm:^15.11.0" - tslib: "npm:^2.6.2" - type-coverage: "npm:^2.27.0" - typescript: "npm:^5.2.2" - unplugin-auto-import: "npm:^0.16.7" - vite: "npm:^4.5.0" - vitest: "npm:^0.34.6" - languageName: unknown - linkType: soft - "lib-upng@npm:3.0.0": version: 3.0.0 resolution: "lib-upng@npm:3.0.0" @@ -20905,17 +20892,6 @@ __metadata: languageName: node linkType: hard -"v8-to-istanbul@npm:^9.1.0": - version: 9.1.3 - resolution: "v8-to-istanbul@npm:9.1.3" - dependencies: - "@jridgewell/trace-mapping": "npm:^0.3.12" - "@types/istanbul-lib-coverage": "npm:^2.0.1" - convert-source-map: "npm:^2.0.0" - checksum: d6ce9f6d97c53a401098fe42018f32be81c99830bcf44ee2717332e20a7df3e364a3f322c10dab4ea94488e81dde462295149cdfb44f48e8ef2829e3afd09752 - languageName: node - linkType: hard - "validate-npm-package-license@npm:^3.0.1": version: 3.0.4 resolution: "validate-npm-package-license@npm:3.0.4"