Add @astrojs/webapi
package (#2729)
* chore: add @astrojs/webapi * chore: update package.json * fix: update file case * fix: remove lowercase file * chore: update tests to use mocha * chore: update LICENSE
This commit is contained in:
parent
10a9c3412b
commit
f18ee36dc0
70 changed files with 13171 additions and 19 deletions
|
@ -15,8 +15,5 @@
|
|||
"unocss": "^0.15.5",
|
||||
"vite-imagetools": "^4.0.1",
|
||||
"@astrojs/renderer-svelte": "^0.5.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astropub/webapi": "^0.10.13"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import { createServer } from 'http';
|
|||
import fs from 'fs';
|
||||
import mime from 'mime';
|
||||
import { loadApp } from 'astro/app/node';
|
||||
import { polyfill } from '@astropub/webapi';
|
||||
import { polyfill } from '@astrojs/webapi';
|
||||
import { apiHandler } from './api.mjs';
|
||||
|
||||
polyfill(globalThis);
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
"build": "turbo run build --no-deps --scope=astro --scope=create-astro --scope=\"@astrojs/*\"",
|
||||
"build:examples": "turbo run build --scope=\"@example/*\"",
|
||||
"dev": "turbo run dev --no-deps --no-cache --parallel --scope=astro --scope=create-astro --scope=\"@astrojs/*\"",
|
||||
"test": "turbo run test --scope=astro",
|
||||
"test": "turbo run test --scope=astro --scope=\"@astrojs/*\"",
|
||||
"test:match": "cd packages/astro && yarn run test:match",
|
||||
"test:templates": "turbo run test --scope=create-astro",
|
||||
"test:smoke": "node scripts/smoke/index.js",
|
||||
|
@ -36,7 +36,6 @@
|
|||
],
|
||||
"volta": {
|
||||
"node": "14.17.0",
|
||||
"npm": "7.11.2",
|
||||
"yarn": "1.22.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -66,7 +66,7 @@
|
|||
"@astrojs/renderer-react": "0.5.0",
|
||||
"@astrojs/renderer-svelte": "0.5.1",
|
||||
"@astrojs/renderer-vue": "0.4.0",
|
||||
"@astropub/webapi": "^0.10.1",
|
||||
"@astrojs/webapi": "^0.11.0",
|
||||
"@babel/core": "^7.15.8",
|
||||
"@babel/traverse": "^7.15.4",
|
||||
"@proload/core": "^0.2.2",
|
||||
|
|
|
@ -3,7 +3,7 @@ import type { LogOptions } from '../logger';
|
|||
|
||||
import fs from 'fs';
|
||||
import * as colors from 'kleur/colors';
|
||||
import { polyfill } from '@astropub/webapi';
|
||||
import { polyfill } from '@astrojs/webapi';
|
||||
import { performance } from 'perf_hooks';
|
||||
import * as vite from 'vite';
|
||||
import { createVite, ViteConfigWithSSR } from '../create-vite.js';
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { polyfill } from '@astropub/webapi';
|
||||
import { polyfill } from '@astrojs/webapi';
|
||||
import type { AddressInfo } from 'net';
|
||||
import { performance } from 'perf_hooks';
|
||||
import type { AstroConfig } from '../../@types/astro';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { execa } from 'execa';
|
||||
import { polyfill } from '@astropub/webapi';
|
||||
import { polyfill } from '@astrojs/webapi';
|
||||
import fs from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { loadConfig } from '../dist/core/config.js';
|
||||
|
|
37
packages/webapi/LICENSE
Normal file
37
packages/webapi/LICENSE
Normal file
|
@ -0,0 +1,37 @@
|
|||
MIT License Copyright (c) 2022 The Astro Technology Company
|
||||
|
||||
Permission is hereby granted, free of
|
||||
charge, to any person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
(including the next paragraph) shall be included in all copies or substantial
|
||||
portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
||||
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
---
|
||||
|
||||
Code from [@astrocommunity/webapi](https://www.npmjs.com/@astrocommunity/webapi) is licensed under the CC0-1.0 License.
|
||||
|
||||
Code from [abort-controller](https://www.npmjs.com/package/abort-controller) is licensed under the MIT License (MIT), Copyright Toru Nagashima.
|
||||
|
||||
Code from [event-target-shim](https://www.npmjs.com/package/event-target-shim) is licensed under the MIT License (MIT), Copyright Toru Nagashima.
|
||||
|
||||
Code from [fetch-blob](https://www.npmjs.com/package/fetch-blob) is licensed under the MIT License (MIT), Copyright Jimmy Wärting.
|
||||
|
||||
Code from [formdata-polyfill](https://www.npmjs.com/package/formdata-polyfill) is licensed under the MIT License (MIT), Copyright Jimmy Wärting.
|
||||
|
||||
Code from [node-fetch](https://www.npmjs.com/package/node-fetch) is licensed under the MIT License (MIT), Copyright Node Fetch Team.
|
||||
|
||||
Code from [web-streams-polyfill](https://www.npmjs.com/package/web-streams-polyfill) is licensed under the MIT License (MIT), Copyright Mattias Buelens and Diwank Singh Tomer.
|
179
packages/webapi/README.md
Normal file
179
packages/webapi/README.md
Normal file
|
@ -0,0 +1,179 @@
|
|||
# WebAPI
|
||||
|
||||
**WebAPI** lets you use Web APIs in Node v12, v14, and v16.
|
||||
|
||||
```shell
|
||||
npm install @astrojs/webapi
|
||||
```
|
||||
|
||||
```js
|
||||
import { polyfill } from '@astrojs/webapi'
|
||||
|
||||
polyfill(globalThis)
|
||||
|
||||
const t = new EventTarget()
|
||||
const e = new CustomEvent('hello')
|
||||
|
||||
t.addEventListener('hello', console.log)
|
||||
|
||||
t.dispatchEvent(e) // logs `e` event from `t`
|
||||
```
|
||||
|
||||
These APIs are combined from popular open source projects and configured to share implementation details. This allows their behavior to match browser expectations as well as reduce their combined memory footprint.
|
||||
|
||||
## Features
|
||||
|
||||
- [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController)
|
||||
- [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal)
|
||||
- [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob)
|
||||
- [ByteLengthQueuingStrategy](https://developer.mozilla.org/en-US/docs/Web/API/ByteLengthQueuingStrategy)
|
||||
- [CanvasRenderingContext2D](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D)
|
||||
- [CSSStyleSheet](https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet)
|
||||
- [CountQueuingStrategy](https://developer.mozilla.org/en-US/docs/Web/API/CountQueuingStrategy)
|
||||
- [CustomElementRegistry](https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry)
|
||||
- [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent)
|
||||
- [DOMException](https://developer.mozilla.org/en-US/docs/Web/API/DOMException)
|
||||
- [Document](https://developer.mozilla.org/en-US/docs/Web/API/Document)
|
||||
- [DocumentFragment](https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment)
|
||||
- [Element](https://developer.mozilla.org/en-US/docs/Web/API/Element)
|
||||
- [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event)
|
||||
- [EventTarget](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget)
|
||||
- [File](https://developer.mozilla.org/en-US/docs/Web/API/File)
|
||||
- [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData)
|
||||
- [HTMLDocument](https://developer.mozilla.org/en-US/docs/Web/API/HTMLDocument)
|
||||
- [HTMLElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement)
|
||||
- [HTMLBodyElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLBodyElement)
|
||||
- [HTMLCanvasElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement)
|
||||
- [HTMLDivElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement)
|
||||
- [HTMLHeadElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLHeadElement)
|
||||
- [HTMLHtmlElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLHtmlElement)
|
||||
- [HTMLImageElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement)
|
||||
- [HTMLSpanElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLSpanElement)
|
||||
- [HTMLStyleElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLStyleElement)
|
||||
- [HTMLTemplateElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLTemplateElement)
|
||||
- [HTMLUnknownElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLUnknownElement)
|
||||
- [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers)
|
||||
- [IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver)
|
||||
- [Image](https://developer.mozilla.org/en-US/docs/Web/API/Image)
|
||||
- [ImageData](https://developer.mozilla.org/en-US/docs/Web/API/ImageData)
|
||||
- [MediaQueryList](https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList)
|
||||
- [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver)
|
||||
- [Node](https://developer.mozilla.org/en-US/docs/Web/API/Node)
|
||||
- [NodeIterator](https://developer.mozilla.org/en-US/docs/Web/API/NodeIterator)
|
||||
- [OffscreenCanvas](https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas)
|
||||
- [ReadableByteStreamController](https://developer.mozilla.org/en-US/docs/Web/API/ReadableByteStreamController)
|
||||
- [ReadableStream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)
|
||||
- [ReadableStreamBYOBReader](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamBYOBReader)
|
||||
- [ReadableStreamBYOBRequest](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamBYOBRequest)
|
||||
- [ReadableStreamDefaultController](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultController)
|
||||
- [ReadableStreamDefaultReader](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultReader)
|
||||
- [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request)
|
||||
- [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response)
|
||||
- [ShadowRoot](https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot)
|
||||
- [Storage](https://developer.mozilla.org/en-US/docs/Web/API/Storage)
|
||||
- [StyleSheet](https://developer.mozilla.org/en-US/docs/Web/API/StyleSheet)
|
||||
- [TransformStream](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream)
|
||||
- [TreeWalker](https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker)
|
||||
- [WritableStream](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream)
|
||||
- [WritableStreamDefaultController](https://developer.mozilla.org/en-US/docs/Web/API/WritableStreamDefaultController)
|
||||
- [WritableStreamDefaultWriter](https://developer.mozilla.org/en-US/docs/Web/API/WritableStreamDefaultWriter)
|
||||
- [Window](https://developer.mozilla.org/en-US/docs/Web/API/Window)
|
||||
- [atob](https://developer.mozilla.org/en-US/docs/Web/API/atob)
|
||||
- [btoa](https://developer.mozilla.org/en-US/docs/Web/API/btoa)
|
||||
- [cancelAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/cancelAnimationFrame)
|
||||
- [cancelIdleCallback](https://developer.mozilla.org/en-US/docs/Web/API/cancelIdleCallback)
|
||||
- [clearTimeout](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout)
|
||||
- [fetch](https://developer.mozilla.org/en-US/docs/Web/API/fetch)
|
||||
- [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/localStorage)
|
||||
- [requestAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/requestAnimationFrame)
|
||||
- [requestIdleCallback](https://developer.mozilla.org/en-US/docs/Web/API/requestIdleCallback)
|
||||
- [setTimeout](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout)
|
||||
- [structuredClone](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone)
|
||||
- [Object.hasOwn](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn)
|
||||
- [Promise.any](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/any)
|
||||
- [Array.prototype.at](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/at)
|
||||
- [String.prototype.at](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/at)
|
||||
- [String.prototype.replaceAll](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replaceAll)
|
||||
- [TypedArray.prototype.at](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/at)
|
||||
- [URLPattern](https://developer.mozilla.org/en-US/docs/Web/API/URLPattern)
|
||||
|
||||
## Usage
|
||||
|
||||
You can use WebAPIs as individual exports.
|
||||
|
||||
```js
|
||||
import { AbortController, Blob, Event, EventTarget, File, fetch, Response } from '@astrojs/webapi'
|
||||
```
|
||||
|
||||
You can apply WebAPIs to an object, like `globalThis`.
|
||||
|
||||
```js
|
||||
import { polyfill } from '@astrojs/webapi'
|
||||
|
||||
polyfill(globalThis)
|
||||
```
|
||||
|
||||
## Polyfill Options
|
||||
|
||||
The `exclude` option receives a list of WebAPIs to exclude from polyfilling.
|
||||
|
||||
```js
|
||||
polyfill(globalThis, {
|
||||
// disables polyfills for setTimeout clearTimeout
|
||||
exclude: 'setTimeout clearTimeout',
|
||||
})
|
||||
```
|
||||
|
||||
The `exclude` option accepts shorthands to exclude multiple polyfills. These shorthands end with the plus sign (`+`).
|
||||
|
||||
```js
|
||||
polyfill(globalThis, {
|
||||
// disables polyfills for setTimeout clearTimeout
|
||||
exclude: 'Timeout+',
|
||||
})
|
||||
```
|
||||
|
||||
```js
|
||||
polyfill(globalThis, {
|
||||
// disables polyfills for Node, Window, Document, HTMLElement, etc.
|
||||
exclude: 'Node+',
|
||||
})
|
||||
```
|
||||
|
||||
```js
|
||||
polyfill(globalThis, {
|
||||
// disables polyfills for Event, EventTarget, Node, Window, Document, HTMLElement, etc.
|
||||
exclude: 'Event+',
|
||||
})
|
||||
```
|
||||
|
||||
| Shorthand | Excludes |
|
||||
|:-------------- |:-------- |
|
||||
| `Blob+` | `Blob`, `File` |
|
||||
| `Document+` | `Document`, `HTMLDocument` |
|
||||
| `Element+` | `Element`, and exclusions from `HTMLElement+` |
|
||||
| `Event+` | `Event`, `CustomEvent`, `EventTarget`, `AbortSignal`, `MediaQueryList`, `Window`, and exclusions from `Node+` |
|
||||
| `EventTarget+` | `Event`, `CustomEvent`, `EventTarget`, `AbortSignal`, `MediaQueryList`, `Window`, and exclusions from `Node+` |
|
||||
| `HTMLElement+` | `CustomElementsRegistry`, `HTMLElement`, `HTMLBodyElement`, `HTMLCanvasElement`, `HTMLDivElement`, `HTMLHeadElement`, `HTMLHtmlElement`, `HTMLImageElement`, `HTMLStyleElement`, `HTMLTemplateElement`, `HTMLUnknownElement`, `Image` |
|
||||
| `Node+` | `Node`, `DocumentFragment`, `ShadowRoot`, `Document`, `HTMLDocument`, and exclusions from `Element+` |
|
||||
| `StyleSheet+` | `StyleSheet`, `CSSStyleSheet` |
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Code original to this project is licensed under the CC0-1.0 License.
|
||||
|
||||
Code from [abort-controller](https://www.npmjs.com/package/abort-controller) is licensed under the MIT License (MIT), Copyright Toru Nagashima.
|
||||
|
||||
Code from [event-target-shim](https://www.npmjs.com/package/event-target-shim) is licensed under the MIT License (MIT), Copyright Toru Nagashima.
|
||||
|
||||
Code from [fetch-blob](https://www.npmjs.com/package/fetch-blob) is licensed under the MIT License (MIT), Copyright Jimmy Wärting.
|
||||
|
||||
Code from [formdata-polyfill](https://www.npmjs.com/package/formdata-polyfill) is licensed under the MIT License (MIT), Copyright Jimmy Wärting.
|
||||
|
||||
Code from [node-fetch](https://www.npmjs.com/package/node-fetch) is licensed under the MIT License (MIT), Copyright Node Fetch Team.
|
||||
|
||||
Code from [web-streams-polyfill](https://www.npmjs.com/package/web-streams-polyfill) is licensed under the MIT License (MIT), Copyright Mattias Buelens and Diwank Singh Tomer.
|
5
packages/webapi/apply.js
Normal file
5
packages/webapi/apply.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
import { polyfill } from './mod.js'
|
||||
|
||||
export * from './mod.js'
|
||||
|
||||
polyfill(globalThis)
|
12
packages/webapi/mod.d.ts
vendored
Normal file
12
packages/webapi/mod.d.ts
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
export { AbortController, AbortSignal, Blob, ByteLengthQueuingStrategy, CanvasRenderingContext2D, CharacterData, Comment, CountQueuingStrategy, CSSStyleSheet, CustomElementRegistry, CustomEvent, DOMException, Document, DocumentFragment, Element, Event, EventTarget, File, FormData, HTMLDocument, HTMLElement, HTMLBodyElement, HTMLCanvasElement, HTMLDivElement, HTMLHeadElement, HTMLHtmlElement, HTMLImageElement, HTMLSpanElement, HTMLStyleElement, HTMLTemplateElement, HTMLUnknownElement, Headers, IntersectionObserver, Image, ImageData, MediaQueryList, MutationObserver, Node, NodeFilter, NodeIterator, OffscreenCanvas, ReadableByteStreamController, ReadableStream, ReadableStreamBYOBReader, ReadableStreamBYOBRequest, ReadableStreamDefaultController, ReadableStreamDefaultReader, Request, ResizeObserver, Response, ShadowRoot, StyleSheet, Text, TransformStream, TreeWalker, URLPattern, WritableStream, WritableStreamDefaultController, WritableStreamDefaultWriter, Window, alert, atob, btoa, cancelAnimationFrame, cancelIdleCallback, clearTimeout, fetch, requestAnimationFrame, requestIdleCallback, setTimeout, structuredClone, } from './mod.js';
|
||||
export { pathToPosix } from './lib/utils';
|
||||
export declare const polyfill: {
|
||||
(target: any, options?: PolyfillOptions | undefined): any;
|
||||
internals(target: any, name: string): any;
|
||||
};
|
||||
interface PolyfillOptions {
|
||||
exclude?: string | string[];
|
||||
override?: Record<string, {
|
||||
(...args: any[]): any;
|
||||
}>;
|
||||
}
|
9465
packages/webapi/mod.js
Normal file
9465
packages/webapi/mod.js
Normal file
File diff suppressed because one or more lines are too long
1
packages/webapi/mod.js.map
Normal file
1
packages/webapi/mod.js.map
Normal file
File diff suppressed because one or more lines are too long
93
packages/webapi/package.json
Normal file
93
packages/webapi/package.json
Normal file
|
@ -0,0 +1,93 @@
|
|||
{
|
||||
"name": "@astrojs/webapi",
|
||||
"description": "Use Web APIs in Node",
|
||||
"version": "0.11.0",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./mod.js",
|
||||
"types": "./mod.d.ts"
|
||||
},
|
||||
"./apply": {
|
||||
"import": "./apply.js"
|
||||
}
|
||||
},
|
||||
"main": "mod.js",
|
||||
"types": "mod.d.ts",
|
||||
"files": [
|
||||
"apply.js",
|
||||
"mod.d.ts",
|
||||
"mod.js",
|
||||
"mod.js.map"
|
||||
],
|
||||
"keywords": [
|
||||
"astro",
|
||||
"api",
|
||||
"cancelAnimationFrame",
|
||||
"clearImmediate",
|
||||
"clearInterval",
|
||||
"fetch",
|
||||
"requestAnimationFrame",
|
||||
"setImmediate",
|
||||
"setInterval",
|
||||
"web"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/withastro/astro.git",
|
||||
"directory": "packages/webapi"
|
||||
},
|
||||
"author": "withastro",
|
||||
"license": "MIT",
|
||||
"contributors": [
|
||||
"Jonathan Neal (https://github.com/jonathantneal)",
|
||||
"Toru Nagashima (https://github.com/mysticatea)",
|
||||
"Jimmy Wärting (https://github.com/jimmywarting)",
|
||||
"David Frank (https://github.com/bitinn)",
|
||||
"Mattias Buelens (https://github.com/MattiasBuelens)",
|
||||
"Diwank Singh (https://github.com/creatorrr)"
|
||||
],
|
||||
"bugs": "https://github.com/withastro/astro/issues",
|
||||
"homepage": "https://github.com/withastro/astro/tree/main/packages/webapi#readme",
|
||||
"devDependencies": {
|
||||
"@types/mocha": "^9.0.0",
|
||||
"@rollup/plugin-alias": "^3.1.9",
|
||||
"@rollup/plugin-inject": "^4.0.4",
|
||||
"@rollup/plugin-node-resolve": "^13.1.3",
|
||||
"@rollup/plugin-typescript": "^8.3.0",
|
||||
"@ungap/structured-clone": "^0.3.4",
|
||||
"abort-controller": "^3.0.0",
|
||||
"event-target-shim": "^6.0.2",
|
||||
"fetch-blob": "^3.1.4",
|
||||
"formdata-polyfill": "^4.0.10",
|
||||
"magic-string": "^0.25.7",
|
||||
"node-fetch": "^3.2.0",
|
||||
"rollup": "^2.67.2",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"urlpattern-polyfill": "^1.0.0-rc5",
|
||||
"web-streams-polyfill": "^3.2.0",
|
||||
"mocha": "^9.1.3"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "node run/build.js",
|
||||
"release": "node run/build.js && npm publish --access public",
|
||||
"test": "mocha --parallel --timeout 15000"
|
||||
},
|
||||
"prettier": {
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "es5",
|
||||
"useTabs": true,
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
".stackblitzrc",
|
||||
"*.json"
|
||||
],
|
||||
"options": {
|
||||
"useTabs": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
190
packages/webapi/run/build.js
Normal file
190
packages/webapi/run/build.js
Normal file
|
@ -0,0 +1,190 @@
|
|||
import { rollup } from 'rollup'
|
||||
import { nodeResolve } from '@rollup/plugin-node-resolve'
|
||||
import { posix as path } from 'node:path'
|
||||
import { createRequire } from 'node:module'
|
||||
import { readFile as nodeReadFile, rename, rm, writeFile } from 'node:fs/promises'
|
||||
import { default as MagicString } from 'magic-string'
|
||||
import { default as alias } from '@rollup/plugin-alias'
|
||||
import { default as inject } from '@rollup/plugin-inject'
|
||||
import { default as typescript } from '@rollup/plugin-typescript'
|
||||
|
||||
const readFileCache = Object.create(null)
|
||||
const require = createRequire(import.meta.url)
|
||||
|
||||
const readFile = (/** @type {string} */ id) => readFileCache[id] || (readFileCache[id] = nodeReadFile(id, 'utf8'))
|
||||
|
||||
const pathToDOMException = path.resolve('src', 'lib', 'DOMException.js')
|
||||
const pathToEventTargetShim = path.join('..', '..', 'node_modules', 'event-target-shim', 'index.mjs')
|
||||
const pathToStructuredClone = path.join('..', '..', 'node_modules', '@ungap', 'structured-clone', 'esm', 'index.js')
|
||||
|
||||
const plugins = [
|
||||
typescript({
|
||||
tsconfig: './tsconfig.json',
|
||||
}),
|
||||
alias({
|
||||
entries: [
|
||||
{ find: '@ungap/structured-clone', replacement: pathToStructuredClone },
|
||||
{ find: 'event-target-shim', replacement: pathToEventTargetShim },
|
||||
{ find: 'event-target-shim/dist/event-target-shim.js', replacement: pathToEventTargetShim },
|
||||
{ find: 'event-target-shim/dist/event-target-shim.umd.js', replacement: pathToEventTargetShim },
|
||||
{ find: 'node-domexception', replacement: pathToDOMException },
|
||||
],
|
||||
}),
|
||||
nodeResolve({
|
||||
dedupe: [
|
||||
'net',
|
||||
'node:net'
|
||||
]
|
||||
}),
|
||||
inject({
|
||||
// import { Promise as P } from 'es6-promise'
|
||||
// P: [ 'es6-promise', 'Promise' ],
|
||||
|
||||
'AbortController': [ 'abort-controller/dist/abort-controller.mjs', 'AbortController' ],
|
||||
'Blob': [ 'fetch-blob/from.js', 'Blob' ],
|
||||
'DOMException': [pathToDOMException, 'DOMException'],
|
||||
'Document': [ './Document', 'Document' ],
|
||||
'Element': [ './Element', 'Element' ],
|
||||
'Event': [ 'event-target-shim', 'Event' ],
|
||||
'EventTarget': [ 'event-target-shim', 'EventTarget' ],
|
||||
'defineEventAttribute': [ 'event-target-shim', 'defineEventAttribute' ],
|
||||
'HTMLElement': ['./Element', 'HTMLElement'],
|
||||
'HTMLImageElement': ['./Element', 'HTMLImageElement'],
|
||||
'HTMLUnknownElement': ['./Element', 'HTMLUnknownElement'],
|
||||
'MediaQueryList': [ './MediaQueryList', 'MediaQueryList' ],
|
||||
'Node': [ './Node', 'Node' ],
|
||||
'ReadableStream': [ 'web-streams-polyfill/dist/ponyfill.es6.mjs', 'ReadableStream' ],
|
||||
'ShadowRoot': [ './Node', 'ShadowRoot' ],
|
||||
'Window': [ './Window', 'Window' ],
|
||||
'globalThis.ReadableStream': [ 'web-streams-polyfill/dist/ponyfill.es6.mjs', 'ReadableStream' ],
|
||||
}),
|
||||
{
|
||||
async load(id) {
|
||||
const pathToEsm = id
|
||||
const pathToMap = `${pathToEsm}.map`
|
||||
|
||||
const code = await readFile(pathToEsm, 'utf8')
|
||||
|
||||
const indexes = []
|
||||
|
||||
const replacements = [
|
||||
// remove unused imports
|
||||
[ /(^|\n)import\s+[^']+'node:(buffer|fs|path|worker_threads)'/g, `` ],
|
||||
[ /const \{ stat \} = fs/g, `` ],
|
||||
|
||||
// remove unused polyfill utils
|
||||
[ /\nif \(\s*typeof Global[\W\w]+?\n\}/g, `` ],
|
||||
[ /\nif \(\s*typeof window[\W\w]+?\n\}/g, `` ],
|
||||
[ /\nif \(!globalThis\.ReadableStream\) \{[\W\w]+?\n\}/g, `` ],
|
||||
[ /\nif \(typeof SymbolPolyfill[\W\w]+?\n\}/g, `` ],
|
||||
|
||||
// remove unused polyfills
|
||||
[ /\nconst globals = getGlobals\(\);/g, `` ],
|
||||
[ /\nconst queueMicrotask = [\W\w]+?\n\}\)\(\);/g, ``],
|
||||
[ /\nconst NativeDOMException =[^;]+;/g, `` ],
|
||||
[ /\nconst SymbolPolyfill\s*=[^;]+;/g, '\nconst SymbolPolyfill = Symbol;'],
|
||||
[ /\n(const|let) DOMException[^;]*;/g, `let DOMException$1=DOMException` ],
|
||||
[ /\nconst DOMException = globalThis.DOMException[\W\w]+?\}\)\(\)/g, `` ],
|
||||
[ /\nimport DOMException from 'node-domexception'/g, `` ],
|
||||
|
||||
// use shared AbortController methods
|
||||
[ / new DOMException\$1/g, `new DOMException` ],
|
||||
[ / from 'net'/g, `from 'node:net'` ],
|
||||
[ / throw createInvalidStateError/g, `throw new DOMException` ],
|
||||
[ /= createAbortController/g, `= new AbortController` ],
|
||||
[ /\nconst queueMicrotask = [\W\w]+?\n\}\)\(\)\;/g, `` ],
|
||||
|
||||
// remove Body.prototype.buffer deprecation notice
|
||||
[ /\nBody\.prototype\.buffer[^\n]+/g, `` ],
|
||||
|
||||
// remove Body.prototype.data deprecation notice
|
||||
[ /\n data: \{get: deprecate[\W\w]+?\)\}/g, `` ],
|
||||
]
|
||||
|
||||
for (const [replacee, replacer] of replacements) {
|
||||
replacee.index = 0
|
||||
|
||||
let replaced = null
|
||||
|
||||
while ((replaced = replacee.exec(code)) !== null) {
|
||||
const leadIndex = replaced.index
|
||||
const tailIndex = replaced.index + replaced[0].length
|
||||
|
||||
indexes.unshift([ leadIndex, tailIndex, replacer ])
|
||||
}
|
||||
}
|
||||
|
||||
if (indexes.length) {
|
||||
const magicString = new MagicString(code)
|
||||
|
||||
indexes.sort(
|
||||
([leadOfA], [leadOfB]) => leadOfA - leadOfB
|
||||
)
|
||||
|
||||
for (const [leadIndex, tailindex, replacer] of indexes) {
|
||||
magicString.overwrite(leadIndex, tailindex, replacer)
|
||||
}
|
||||
|
||||
const magicMap = magicString.generateMap({ source: pathToEsm, file: pathToMap, includeContent: true })
|
||||
|
||||
const modifiedEsm = magicString.toString()
|
||||
const modifiedMap = magicMap.toString()
|
||||
|
||||
return { code: modifiedEsm, map: modifiedMap }
|
||||
}
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
async function build() {
|
||||
const configs = [
|
||||
{
|
||||
inputOptions: {
|
||||
input: 'src/polyfill.ts',
|
||||
plugins: plugins,
|
||||
onwarn(warning, warn) {
|
||||
if (warning.code !== 'UNRESOLVED_IMPORT') warn(warning)
|
||||
},
|
||||
},
|
||||
outputOptions: {
|
||||
inlineDynamicImports: true,
|
||||
file: 'mod.js',
|
||||
format: 'esm',
|
||||
sourcemap: true,
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
for (const config of configs) {
|
||||
const bundle = await rollup(config.inputOptions)
|
||||
|
||||
// or write the bundle to disk
|
||||
await bundle.write(config.outputOptions)
|
||||
|
||||
// closes the bundle
|
||||
await bundle.close()
|
||||
|
||||
// delete the lib directory
|
||||
await rm('lib', { force: true, recursive: true })
|
||||
await rm('exclusions.d.ts', { force: true, recursive: true })
|
||||
await rm('exclusions.d.ts.map', { force: true, recursive: true })
|
||||
await rm('inheritence.d.ts', { force: true, recursive: true })
|
||||
await rm('inheritence.d.ts.map', { force: true, recursive: true })
|
||||
await rm('polyfill.d.ts.map', { force: true, recursive: true })
|
||||
await rm('polyfill.js.map', { force: true, recursive: true })
|
||||
await rm('polyfill.js', { force: true, recursive: true })
|
||||
await rm('ponyfill.d.ts', { force: true, recursive: true })
|
||||
await rm('ponyfill.d.ts.map', { force: true, recursive: true })
|
||||
await rm('ponyfill.js.map', { force: true, recursive: true })
|
||||
await rm('ponyfill.js', { force: true, recursive: true })
|
||||
|
||||
await rename('polyfill.d.ts', 'mod.d.ts')
|
||||
|
||||
const modDTS = await readFile('./mod.d.ts')
|
||||
|
||||
writeFile('mod.d.ts', modDTS.replace('\n//# sourceMappingURL=polyfill.d.ts.map', '').replace('ponyfill.js', 'mod.js'))
|
||||
writeFile('apply.js', `import { polyfill } from './mod.js'\n\nexport * from './mod.js'\n\npolyfill(globalThis)\n`)
|
||||
}
|
||||
}
|
||||
|
||||
build()
|
28
packages/webapi/run/test.setup.js
Normal file
28
packages/webapi/run/test.setup.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { fileURLToPath } from 'url'
|
||||
|
||||
export { strict as assert } from 'assert'
|
||||
|
||||
export const pathFrom = (...args) => fileURLToPath(args.reduce((url, bit) => new URL(bit, url), new URL('file:')))
|
||||
|
||||
export const test = async (setup) => {
|
||||
console.log(`Testing Node ${process.version}:`)
|
||||
console.log('')
|
||||
|
||||
for (const test of setup()) {
|
||||
try {
|
||||
console.log(`- ${test.name}`)
|
||||
|
||||
await test.test()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
console.log('')
|
||||
console.log('Pass!')
|
||||
console.log('')
|
||||
|
||||
process.exit(0)
|
||||
}
|
17
packages/webapi/src/exclusions.ts
Normal file
17
packages/webapi/src/exclusions.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
const exclusionsForHTMLElement = [ 'CustomElementsRegistry', 'HTMLElement', 'HTMLBodyElement', 'HTMLCanvasElement', 'HTMLDivElement', 'HTMLHeadElement', 'HTMLHtmlElement', 'HTMLImageElement', 'HTMLStyleElement', 'HTMLTemplateElement', 'HTMLUnknownElement', 'Image' ]
|
||||
const exclusionsForElement = [ 'Element', ...exclusionsForHTMLElement ] as const
|
||||
const exclusionsForDocument = [ 'CustomElementsRegistry', 'Document', 'HTMLDocument', 'document', 'customElements' ] as const
|
||||
const exclusionsForNode = [ 'Node', 'DocumentFragment', 'ShadowRoot', ...exclusionsForDocument, ...exclusionsForElement ] as const
|
||||
const exclusionsForEventTarget = [ 'AbortSignal', 'Event', 'CustomEvent', 'EventTarget', 'OffscreenCanvas', 'MediaQueryList', 'Window', ...exclusionsForNode ] as const
|
||||
const exclusionsForEvent = [ 'AbortSignal', 'Event', 'CustomEvent', 'EventTarget', 'MediaQueryList', 'OffscreenCanvas', 'Window', ...exclusionsForNode ] as const
|
||||
|
||||
export const exclusions = {
|
||||
'Blob+': [ 'Blob', 'File' ],
|
||||
'Document+': exclusionsForDocument,
|
||||
'Element+': exclusionsForElement,
|
||||
'Event+': exclusionsForEvent,
|
||||
'EventTarget+': exclusionsForEventTarget,
|
||||
'HTMLElement+': exclusionsForHTMLElement,
|
||||
'Node+': exclusionsForNode,
|
||||
'StyleSheet+': [ 'StyleSheet', 'CSSStyleSheet' ],
|
||||
}
|
27
packages/webapi/src/inheritence.ts
Normal file
27
packages/webapi/src/inheritence.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
export const inheritence = {
|
||||
CSSStyleSheet: 'StyleSheet',
|
||||
CustomEvent: 'Event',
|
||||
DOMException: 'Error',
|
||||
Document: 'Node',
|
||||
DocumentFragment: 'Node',
|
||||
Element: 'Node',
|
||||
File: 'Blob',
|
||||
HTMLDocument: 'Document',
|
||||
HTMLElement: 'Element',
|
||||
HTMLBodyElement: 'HTMLElement',
|
||||
HTMLCanvasElement: 'HTMLElement',
|
||||
HTMLDivElement: 'HTMLElement',
|
||||
HTMLHeadElement: 'HTMLElement',
|
||||
HTMLHtmlElement: 'HTMLElement',
|
||||
HTMLImageElement: 'HTMLElement',
|
||||
HTMLSpanElement: 'HTMLElement',
|
||||
HTMLStyleElement: 'HTMLElement',
|
||||
HTMLTemplateElement: 'HTMLElement',
|
||||
HTMLUnknownElement: 'HTMLElement',
|
||||
Image: 'HTMLElement',
|
||||
MediaQueryList: 'EventTarget',
|
||||
Node: 'EventTarget',
|
||||
OffscreenCanvas: 'EventTarget',
|
||||
ShadowRoot: 'DocumentFragment',
|
||||
Window: 'EventTarget',
|
||||
} as const
|
3
packages/webapi/src/lib/Alert.ts
Normal file
3
packages/webapi/src/lib/Alert.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export function alert(...messages: any[]) {
|
||||
console.log(...messages)
|
||||
}
|
35
packages/webapi/src/lib/AnimationFrame.ts
Normal file
35
packages/webapi/src/lib/AnimationFrame.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
import { setTimeout as nodeSetTimeout, clearTimeout as nodeClearTimeout } from 'node:timers'
|
||||
import * as _ from './utils.js'
|
||||
|
||||
const INTERNAL = { tick: 0, pool: new Map }
|
||||
|
||||
export function requestAnimationFrame<TArgs extends any[], TFunc extends (...args: TArgs) => any>(callback: TFunc): number {
|
||||
if (!INTERNAL.pool.size) {
|
||||
nodeSetTimeout(() => {
|
||||
const next = _.__performance_now()
|
||||
|
||||
for (const func of INTERNAL.pool.values()) {
|
||||
func(next)
|
||||
}
|
||||
|
||||
INTERNAL.pool.clear()
|
||||
}, 1000 / 16)
|
||||
}
|
||||
|
||||
const func = _.__function_bind(callback, undefined)
|
||||
const tick = ++INTERNAL.tick
|
||||
|
||||
INTERNAL.pool.set(tick, func)
|
||||
|
||||
return tick
|
||||
}
|
||||
|
||||
export function cancelAnimationFrame(requestId: number): void {
|
||||
const timeout = INTERNAL.pool.get(requestId)
|
||||
|
||||
if (timeout) {
|
||||
nodeClearTimeout(timeout)
|
||||
|
||||
INTERNAL.pool.delete(requestId)
|
||||
}
|
||||
}
|
7
packages/webapi/src/lib/Base64.ts
Normal file
7
packages/webapi/src/lib/Base64.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
export function atob(data: string): string {
|
||||
return Buffer.from(data, 'base64').toString('binary')
|
||||
}
|
||||
|
||||
export function btoa(data: string): string {
|
||||
return Buffer.from(data, 'binary').toString('base64')
|
||||
}
|
182
packages/webapi/src/lib/CanvasRenderingContext2D.ts
Normal file
182
packages/webapi/src/lib/CanvasRenderingContext2D.ts
Normal file
|
@ -0,0 +1,182 @@
|
|||
import type { HTMLCanvasElement } from './HTMLCanvasElement'
|
||||
import type { OffscreenCanvas } from './OffscreenCanvas'
|
||||
|
||||
import * as _ from './utils'
|
||||
import { ImageData } from './ImageData'
|
||||
|
||||
export class CanvasRenderingContext2D {
|
||||
get canvas(): HTMLCanvasElement | OffscreenCanvas | null {
|
||||
return _.internalsOf(this, 'CanvasRenderingContext2D', 'canvas').canvas
|
||||
}
|
||||
|
||||
get direction(): 'ltr' | 'rtl' | 'inherit' {
|
||||
return _.internalsOf(this, 'CanvasRenderingContext2D', 'direction').direction
|
||||
}
|
||||
|
||||
get fillStyle(): string {
|
||||
return _.internalsOf(this, 'CanvasRenderingContext2D', 'fillStyle').fillStyle
|
||||
}
|
||||
|
||||
get filter(): string {
|
||||
return _.internalsOf(this, 'CanvasRenderingContext2D', 'filter').filter
|
||||
}
|
||||
|
||||
get globalAlpha(): number {
|
||||
return _.internalsOf(this, 'CanvasRenderingContext2D', 'globalAlpha').globalAlpha
|
||||
}
|
||||
|
||||
get globalCompositeOperation(): string {
|
||||
return _.internalsOf(this, 'CanvasRenderingContext2D', 'globalCompositeOperation').globalCompositeOperation
|
||||
}
|
||||
|
||||
get font(): string {
|
||||
return _.internalsOf(this, 'CanvasRenderingContext2D', 'font').font
|
||||
}
|
||||
|
||||
get imageSmoothingEnabled(): boolean {
|
||||
return _.internalsOf(this, 'CanvasRenderingContext2D', 'imageSmoothingEnabled').imageSmoothingEnabled
|
||||
}
|
||||
|
||||
get imageSmoothingQuality(): 'low' | 'medium' | 'high' {
|
||||
return _.internalsOf(this, 'CanvasRenderingContext2D', 'imageSmoothingQuality').imageSmoothingQuality
|
||||
}
|
||||
|
||||
get lineCap(): 'butt' | 'round' | 'square' {
|
||||
return _.internalsOf(this, 'CanvasRenderingContext2D', 'lineCap').lineCap
|
||||
}
|
||||
|
||||
get lineDashOffset(): number {
|
||||
return _.internalsOf(this, 'CanvasRenderingContext2D', 'lineDashOffset').lineDashOffset
|
||||
}
|
||||
|
||||
get lineJoin(): 'bevel' | 'round' | 'miter' {
|
||||
return _.internalsOf(this, 'CanvasRenderingContext2D', 'lineJoin').lineJoin
|
||||
}
|
||||
|
||||
get lineWidth(): number {
|
||||
return _.internalsOf(this, 'CanvasRenderingContext2D', 'lineWidth').lineWidth
|
||||
}
|
||||
|
||||
get miterLimit(): number {
|
||||
return _.internalsOf(this, 'CanvasRenderingContext2D', 'miterLimit').miterLimit
|
||||
}
|
||||
|
||||
get strokeStyle(): string {
|
||||
return _.internalsOf(this, 'CanvasRenderingContext2D', 'strokeStyle').strokeStyle
|
||||
}
|
||||
|
||||
get shadowOffsetX(): number {
|
||||
return _.internalsOf(this, 'CanvasRenderingContext2D', 'shadowOffsetX').shadowOffsetX
|
||||
}
|
||||
|
||||
get shadowOffsetY(): number {
|
||||
return _.internalsOf(this, 'CanvasRenderingContext2D', 'shadowOffsetY').shadowOffsetY
|
||||
}
|
||||
|
||||
get shadowBlur(): number {
|
||||
return _.internalsOf(this, 'CanvasRenderingContext2D', 'shadowBlur').shadowBlur
|
||||
}
|
||||
|
||||
get shadowColor(): string {
|
||||
return _.internalsOf(this, 'CanvasRenderingContext2D', 'shadowColor').shadowColor
|
||||
}
|
||||
|
||||
get textAlign(): 'left' | 'right' | 'center' | 'start' | 'end' {
|
||||
return _.internalsOf(this, 'CanvasRenderingContext2D', 'textAlign').textAlign
|
||||
}
|
||||
|
||||
get textBaseline(): 'top' | 'hanging' | 'middle' | 'alphabetic' | 'ideographic' | 'bottom' {
|
||||
return _.internalsOf(this, 'CanvasRenderingContext2D', 'textBaseline').textBaseline
|
||||
}
|
||||
|
||||
arc() {}
|
||||
arcTo() {}
|
||||
beginPath() {}
|
||||
bezierCurveTo() {}
|
||||
clearRect() {}
|
||||
clip() {}
|
||||
closePath() {}
|
||||
|
||||
createImageData(width: number, height: number): void
|
||||
createImageData(imagedata: ImageData): void
|
||||
|
||||
createImageData(arg0: number | ImageData, arg1?: void | number) {
|
||||
/** Whether ImageData is provided. */
|
||||
const hasData = _.__object_isPrototypeOf(ImageData.prototype, arg0)
|
||||
|
||||
const w = hasData ? (arg0 as ImageData).width : arg0 as number
|
||||
const h = hasData ? (arg0 as ImageData).height : arg1 as number
|
||||
const d = hasData ? (arg0 as ImageData).data : new Uint8ClampedArray(w * h * 4)
|
||||
|
||||
return new ImageData(d, w, h)
|
||||
}
|
||||
|
||||
createLinearGradient() {}
|
||||
createPattern() {}
|
||||
createRadialGradient() {}
|
||||
drawFocusIfNeeded() {}
|
||||
drawImage() {}
|
||||
ellipse() {}
|
||||
fill() {}
|
||||
fillRect() {}
|
||||
fillText() {}
|
||||
getContextAttributes() {}
|
||||
getImageData() {}
|
||||
getLineDash() {}
|
||||
getTransform() {}
|
||||
isPointInPath() {}
|
||||
isPointInStroke() {}
|
||||
lineTo() {}
|
||||
measureText() {}
|
||||
moveTo() {}
|
||||
putImageData() {}
|
||||
quadraticCurveTo() {}
|
||||
rect() {}
|
||||
resetTransform() {}
|
||||
restore() {}
|
||||
rotate() {}
|
||||
save() {}
|
||||
scale() {}
|
||||
setLineDash() {}
|
||||
setTransform() {}
|
||||
stroke() {}
|
||||
strokeRect() {}
|
||||
strokeText() {}
|
||||
transform() {}
|
||||
translate() {}
|
||||
}
|
||||
|
||||
_.allowStringTag(CanvasRenderingContext2D)
|
||||
|
||||
export const __createCanvasRenderingContext2D = (canvas: EventTarget): CanvasRenderingContext2D => {
|
||||
const renderingContext2D = Object.create(CanvasRenderingContext2D.prototype) as CanvasRenderingContext2D
|
||||
|
||||
_.INTERNALS.set(renderingContext2D, {
|
||||
canvas,
|
||||
direction: 'inherit',
|
||||
fillStyle: '#000',
|
||||
filter: 'none',
|
||||
font: '10px sans-serif',
|
||||
globalAlpha: 0,
|
||||
globalCompositeOperation: 'source-over',
|
||||
imageSmoothingEnabled: false,
|
||||
imageSmoothingQuality: 'high',
|
||||
lineCap: 'butt',
|
||||
lineDashOffset: 0.0,
|
||||
lineJoin: 'miter',
|
||||
lineWidth: 1.0,
|
||||
miterLimit: 10.0,
|
||||
shadowBlur: 0,
|
||||
shadowColor: '#000',
|
||||
shadowOffsetX: 0,
|
||||
shadowOffsetY: 0,
|
||||
strokeStyle: '#000',
|
||||
textAlign: 'start',
|
||||
textBaseline: 'alphabetic',
|
||||
})
|
||||
|
||||
return renderingContext2D
|
||||
}
|
||||
|
||||
/** Returns whether the value is an instance of ImageData. */
|
||||
const isImageData = <T>(value: T) => (Object(value).data instanceof Uint8ClampedArray) as T extends ImageData ? true : false
|
36
packages/webapi/src/lib/CharacterData.ts
Normal file
36
packages/webapi/src/lib/CharacterData.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
import * as _ from './utils'
|
||||
|
||||
export class CharacterData extends Node {
|
||||
constructor(data: string) {
|
||||
_.INTERNALS.set(super(), {
|
||||
data: String(data),
|
||||
} as CharacterDataInternals)
|
||||
}
|
||||
get data(): string {
|
||||
return _.internalsOf<CharacterDataInternals>(this, 'CharacterData', 'data').data
|
||||
}
|
||||
|
||||
get textContent(): string {
|
||||
return _.internalsOf<CharacterDataInternals>(this, 'CharacterData', 'textContent').data
|
||||
}
|
||||
}
|
||||
|
||||
export class Comment extends CharacterData {}
|
||||
|
||||
export class Text extends CharacterData {
|
||||
get assignedSlot(): HTMLSlotElement | null {
|
||||
return null
|
||||
}
|
||||
|
||||
get wholeText(): string {
|
||||
return _.internalsOf<CharacterDataInternals>(this, 'CharacterData', 'textContent').data
|
||||
}
|
||||
}
|
||||
|
||||
_.allowStringTag(CharacterData)
|
||||
_.allowStringTag(Text)
|
||||
_.allowStringTag(Comment)
|
||||
|
||||
interface CharacterDataInternals {
|
||||
data: string
|
||||
}
|
52
packages/webapi/src/lib/ContextEvent.ts
Normal file
52
packages/webapi/src/lib/ContextEvent.ts
Normal file
|
@ -0,0 +1,52 @@
|
|||
import { Event } from 'event-target-shim'
|
||||
|
||||
/** An event fired by a context requester to signal it desires a named context. */
|
||||
export class ContextEvent<T = unknown> extends Event<'context-request'> {
|
||||
constructor(init: ContextEventInit<T>) {
|
||||
super('context-request', { bubbles: true, composed: true })
|
||||
|
||||
init = Object(init) as Required<ContextEventInit<T>>
|
||||
|
||||
this.context = init.context
|
||||
}
|
||||
|
||||
context!: Context<T>
|
||||
multiple!: boolean
|
||||
callback!: ContextCallback<Context<T>>
|
||||
}
|
||||
|
||||
interface ContextEventInit<T = unknown> {
|
||||
context: Context<T>
|
||||
multiple?: boolean
|
||||
callback: ContextCallback<Context<T>>
|
||||
}
|
||||
|
||||
/** A Context object defines an optional initial value for a Context, as well as a name identifier for debugging purposes. */
|
||||
export type Context<T = unknown> = {
|
||||
name: string
|
||||
initialValue?: T
|
||||
}
|
||||
|
||||
/** A helper type which can extract a Context value type from a Context type. */
|
||||
export type ContextType<T extends Context> = T extends Context<infer Y> ? Y : never
|
||||
|
||||
/** A function which creates a Context value object */
|
||||
export function createContext<T>(name: string, initialValue?: T): Readonly<Context<T>> {
|
||||
return {
|
||||
name,
|
||||
initialValue,
|
||||
}
|
||||
}
|
||||
|
||||
/** A callback which is provided by a context requester and is called with the value satisfying the request. */
|
||||
export type ContextCallback<ValueType> = (
|
||||
value: ValueType,
|
||||
dispose?: () => void
|
||||
) => void
|
||||
|
||||
declare global {
|
||||
interface HTMLElementEventMap {
|
||||
/** A 'context-request' event can be emitted by any element which desires a context value to be injected by an external provider. */
|
||||
'context-request': ContextEvent
|
||||
}
|
||||
}
|
58
packages/webapi/src/lib/CustomElementRegistry.ts
Normal file
58
packages/webapi/src/lib/CustomElementRegistry.ts
Normal file
|
@ -0,0 +1,58 @@
|
|||
import * as _ from './utils'
|
||||
|
||||
export class CustomElementRegistry {
|
||||
/** Defines a new custom element using the given tag name and HTMLElement constructor. */
|
||||
define(name: string, constructor: Function, options?: ElementDefinitionOptions) {
|
||||
const internals = _.internalsOf<CustomElementRegistryInternals>(this, 'CustomElementRegistry', 'define')
|
||||
|
||||
name = String(name)
|
||||
|
||||
if (/[A-Z]/.test(name)) throw new SyntaxError('Custom element name cannot contain an uppercase ASCII letter')
|
||||
if (!/^[a-z]/.test(name)) throw new SyntaxError('Custom element name must have a lowercase ASCII letter as its first character')
|
||||
if (!/-/.test(name)) throw new SyntaxError('Custom element name must contain a hyphen')
|
||||
|
||||
internals.constructorByName.set(name, constructor)
|
||||
internals.nameByConstructor.set(constructor, name)
|
||||
|
||||
void options
|
||||
}
|
||||
|
||||
/** Returns the constructor associated with the given tag name. */
|
||||
get(name: string) {
|
||||
const internals = _.internalsOf<CustomElementRegistryInternals>(this, 'CustomElementRegistry', 'get')
|
||||
|
||||
name = String(name).toLowerCase()
|
||||
|
||||
return internals.constructorByName.get(name)
|
||||
}
|
||||
|
||||
getName(constructor: Function) {
|
||||
const internals = _.internalsOf<CustomElementRegistryInternals>(this, 'CustomElementRegistry', 'getName')
|
||||
|
||||
return internals.nameByConstructor.get(constructor)
|
||||
}
|
||||
}
|
||||
|
||||
_.allowStringTag(CustomElementRegistry)
|
||||
|
||||
interface CustomElementRegistryInternals {
|
||||
constructorByName: Map<string, Function>;
|
||||
nameByConstructor: Map<Function, string>;
|
||||
}
|
||||
|
||||
interface ElementDefinitionOptions {
|
||||
extends?: string | undefined;
|
||||
}
|
||||
|
||||
export const initCustomElementRegistry = (target: Record<any, any>, exclude: Set<string>) => {
|
||||
if (exclude.has('customElements')) return
|
||||
|
||||
const CustomElementRegistry = target.CustomElementRegistry || globalThis.CustomElementRegistry
|
||||
|
||||
const customElements: CustomElementRegistry = target.customElements = Object.create(CustomElementRegistry.prototype)
|
||||
|
||||
_.INTERNALS.set(customElements, {
|
||||
constructorByName: new Map,
|
||||
nameByConstructor: new Map,
|
||||
} as CustomElementRegistryInternals)
|
||||
}
|
24
packages/webapi/src/lib/CustomEvent.ts
Normal file
24
packages/webapi/src/lib/CustomEvent.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
import * as _ from './utils'
|
||||
import { Event } from 'event-target-shim'
|
||||
|
||||
class CustomEvent<TEventType extends string = string> extends Event<TEventType> {
|
||||
constructor(type: TEventType, params?: CustomEventInit) {
|
||||
params = Object(params) as Required<CustomEventInit>
|
||||
|
||||
super(type, params)
|
||||
|
||||
if ('detail' in params) this.detail = params.detail
|
||||
}
|
||||
|
||||
detail!: any
|
||||
}
|
||||
|
||||
_.allowStringTag(CustomEvent)
|
||||
|
||||
export { CustomEvent }
|
||||
|
||||
interface CustomEventInit {
|
||||
bubbles?: boolean
|
||||
cancelable?: false
|
||||
detail?: any
|
||||
}
|
40
packages/webapi/src/lib/DOMException.ts
Normal file
40
packages/webapi/src/lib/DOMException.ts
Normal file
|
@ -0,0 +1,40 @@
|
|||
import * as _ from './utils'
|
||||
|
||||
export class DOMException extends Error {
|
||||
constructor(message = '', name = 'Error') {
|
||||
super(message)
|
||||
|
||||
this.code = 0
|
||||
this.name = name
|
||||
}
|
||||
|
||||
code!: number
|
||||
|
||||
static INDEX_SIZE_ERR = 1
|
||||
static DOMSTRING_SIZE_ERR = 2
|
||||
static HIERARCHY_REQUEST_ERR = 3
|
||||
static WRONG_DOCUMENT_ERR = 4
|
||||
static INVALID_CHARACTER_ERR = 5
|
||||
static NO_DATA_ALLOWED_ERR = 6
|
||||
static NO_MODIFICATION_ALLOWED_ERR = 7
|
||||
static NOT_FOUND_ERR = 8
|
||||
static NOT_SUPPORTED_ERR = 9
|
||||
static INUSE_ATTRIBUTE_ERR = 10
|
||||
static INVALID_STATE_ERR = 11
|
||||
static SYNTAX_ERR = 12
|
||||
static INVALID_MODIFICATION_ERR = 13
|
||||
static NAMESPACE_ERR = 14
|
||||
static INVALID_ACCESS_ERR = 15
|
||||
static VALIDATION_ERR = 16
|
||||
static TYPE_MISMATCH_ERR = 17
|
||||
static SECURITY_ERR = 18
|
||||
static NETWORK_ERR = 19
|
||||
static ABORT_ERR = 20
|
||||
static URL_MISMATCH_ERR = 21
|
||||
static QUOTA_EXCEEDED_ERR = 22
|
||||
static TIMEOUT_ERR = 23
|
||||
static INVALID_NODE_TYPE_ERR = 24
|
||||
static DATA_CLONE_ERR = 25
|
||||
}
|
||||
|
||||
_.allowStringTag(DOMException)
|
159
packages/webapi/src/lib/Document.ts
Normal file
159
packages/webapi/src/lib/Document.ts
Normal file
|
@ -0,0 +1,159 @@
|
|||
import * as _ from './utils'
|
||||
import { Text } from './CharacterData'
|
||||
import { TreeWalker } from './TreeWalker'
|
||||
|
||||
export class Document extends Node {
|
||||
createElement(name: string) {
|
||||
const internals = _.internalsOf<DocumentInternals>(this, 'Document', 'createElement')
|
||||
|
||||
const customElementInternals: CustomElementRegistryInternals = _.INTERNALS.get(internals.target.customElements)
|
||||
|
||||
name = String(name).toLowerCase()
|
||||
|
||||
const TypeOfHTMLElement = internals.constructorByName.get(name) || (customElementInternals && customElementInternals.constructorByName.get(name)) || HTMLUnknownElement
|
||||
|
||||
const element = Object.setPrototypeOf(new EventTarget(), TypeOfHTMLElement.prototype) as HTMLElement
|
||||
|
||||
_.INTERNALS.set(element, {
|
||||
attributes: {},
|
||||
localName: name,
|
||||
ownerDocument: this,
|
||||
shadowInit: null as unknown as ShadowRootInit,
|
||||
shadowRoot: null as unknown as ShadowRoot,
|
||||
} as ElementInternals)
|
||||
|
||||
return element
|
||||
}
|
||||
|
||||
createNodeIterator(root: Node, whatToShow: number = NodeFilter.SHOW_ALL, filter?: NodeIteratorInternals['filter']) {
|
||||
const target = Object.create(NodeIterator.prototype)
|
||||
|
||||
_.INTERNALS.set(target, { filter, pointerBeforeReferenceNode: false, referenceNode: root, root, whatToShow } as NodeIteratorInternals)
|
||||
|
||||
return target
|
||||
}
|
||||
|
||||
createTextNode(data: string) {
|
||||
return new Text(data)
|
||||
}
|
||||
|
||||
createTreeWalker(root: Node, whatToShow: number = NodeFilter.SHOW_ALL, filter?: NodeFilter, expandEntityReferences?: boolean) {
|
||||
const target = Object.create(TreeWalker.prototype)
|
||||
|
||||
_.INTERNALS.set(target, { filter, currentNode: root, root, whatToShow } as TreeWalkerInternals)
|
||||
|
||||
return target
|
||||
}
|
||||
|
||||
get adoptedStyleSheets(): StyleSheet[] {
|
||||
return []
|
||||
}
|
||||
|
||||
get styleSheets(): StyleSheet[] {
|
||||
return []
|
||||
}
|
||||
|
||||
body!: HTMLBodyElement
|
||||
documentElement!: HTMLHtmlElement
|
||||
head!: HTMLHeadElement
|
||||
}
|
||||
|
||||
export class HTMLDocument extends Document {}
|
||||
|
||||
_.allowStringTag(Document)
|
||||
_.allowStringTag(HTMLDocument)
|
||||
|
||||
export const initDocument = (target: Target, exclude: Set<string>) => {
|
||||
if (exclude.has('document')) return
|
||||
|
||||
const EventTarget = target.EventTarget || globalThis.EventTarget
|
||||
const HTMLDocument = target.HTMLDocument || globalThis.HTMLDocument
|
||||
|
||||
const document: HTMLDocument = target.document = Object.setPrototypeOf(new EventTarget(), HTMLDocument.prototype)
|
||||
|
||||
_.INTERNALS.set(document, {
|
||||
target,
|
||||
constructorByName: new Map<string, Function>([
|
||||
['body', target.HTMLBodyElement],
|
||||
['canvas', target.HTMLCanvasElement],
|
||||
['div', target.HTMLDivElement],
|
||||
['head', target.HTMLHeadElement],
|
||||
['html', target.HTMLHtmlElement],
|
||||
['img', target.HTMLImageElement],
|
||||
['span', target.HTMLSpanElement],
|
||||
['style', target.HTMLStyleElement],
|
||||
]),
|
||||
nameByConstructor: new Map,
|
||||
} as DocumentInternals)
|
||||
|
||||
const initElement = (name: string, Class: Function) => {
|
||||
const target = Object.setPrototypeOf(new EventTarget(), Class.prototype)
|
||||
|
||||
_.INTERNALS.set(target, {
|
||||
attributes: {},
|
||||
localName: name,
|
||||
ownerDocument: document,
|
||||
shadowRoot: null as unknown as ShadowRoot,
|
||||
shadowInit: null as unknown as ShadowRootInit,
|
||||
} as ElementInternals)
|
||||
|
||||
return target
|
||||
}
|
||||
|
||||
document.body = initElement('body', target.HTMLBodyElement) as HTMLBodyElement
|
||||
document.head = initElement('head', target.HTMLHeadElement) as HTMLHeadElement
|
||||
document.documentElement = initElement('html', target.HTMLHtmlElement) as HTMLHtmlElement
|
||||
}
|
||||
|
||||
interface DocumentInternals {
|
||||
body: HTMLBodyElement
|
||||
documentElement: HTMLHtmlElement
|
||||
head: HTMLHeadElement
|
||||
constructorByName: Map<string, Function>
|
||||
nameByConstructor: Map<Function, string>
|
||||
target: Target
|
||||
}
|
||||
|
||||
interface CustomElementRegistryInternals {
|
||||
constructorByName: Map<string, Function>
|
||||
nameByConstructor: Map<Function, string>
|
||||
}
|
||||
|
||||
interface ElementInternals {
|
||||
attributes: { [name: string]: string },
|
||||
localName: string
|
||||
ownerDocument: Document
|
||||
shadowRoot: ShadowRoot
|
||||
shadowInit: ShadowRootInit
|
||||
}
|
||||
|
||||
interface ShadowRootInit extends Record<any, any> {
|
||||
mode?: string
|
||||
}
|
||||
|
||||
interface Target extends Record<any, any> {
|
||||
HTMLBodyElement: typeof HTMLBodyElement
|
||||
HTMLDivElement: typeof HTMLDivElement
|
||||
HTMLElement: typeof HTMLElement
|
||||
HTMLHeadElement: typeof HTMLHeadElement
|
||||
HTMLHtmlElement: typeof HTMLHtmlElement
|
||||
HTMLSpanElement: typeof HTMLSpanElement
|
||||
HTMLStyleElement: typeof HTMLStyleElement
|
||||
customElements: CustomElementRegistry
|
||||
document: DocumentInternals
|
||||
}
|
||||
|
||||
interface NodeIteratorInternals {
|
||||
filter: NodeFilter
|
||||
pointerBeforeReferenceNode: boolean
|
||||
referenceNode: Node
|
||||
root: Node
|
||||
whatToShow: number
|
||||
}
|
||||
|
||||
interface TreeWalkerInternals {
|
||||
filter: NodeFilter
|
||||
currentNode: Node
|
||||
root: Node
|
||||
whatToShow: number
|
||||
}
|
118
packages/webapi/src/lib/Element.ts
Normal file
118
packages/webapi/src/lib/Element.ts
Normal file
|
@ -0,0 +1,118 @@
|
|||
import * as _ from './utils'
|
||||
|
||||
export class Element extends Node {
|
||||
hasAttribute(name: string): boolean {
|
||||
void name
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
getAttribute(name: string): string | null {
|
||||
return null
|
||||
}
|
||||
|
||||
setAttribute(name: string, value: string): void {
|
||||
void name
|
||||
void value
|
||||
}
|
||||
|
||||
removeAttribute(name: string): void {
|
||||
void name
|
||||
}
|
||||
|
||||
attachShadow(init: Partial<ShadowRootInit>) {
|
||||
if (arguments.length < 1) throw new TypeError(`Failed to execute 'attachShadow' on 'Element': 1 argument required, but only 0 present.`)
|
||||
|
||||
if (init !== Object(init)) throw new TypeError(`Failed to execute 'attachShadow' on 'Element': The provided value is not of type 'ShadowRootInit'.`)
|
||||
|
||||
if (init.mode !== 'open' && init.mode !== 'closed') throw new TypeError(`Failed to execute 'attachShadow' on 'Element': Failed to read the 'mode' property from 'ShadowRootInit': The provided value '${init.mode}' is not a valid enum value of type ShadowRootMode.`)
|
||||
|
||||
const internals = _.internalsOf<ElementInternals>(this, 'Element', 'attachShadow')
|
||||
|
||||
if (internals.shadowRoot) throw new Error('The operation is not supported.')
|
||||
|
||||
internals.shadowInit = internals.shadowInit || {
|
||||
mode: init.mode,
|
||||
delegatesFocus: Boolean(init.delegatesFocus),
|
||||
}
|
||||
|
||||
internals.shadowRoot = internals.shadowRoot || (/^open$/.test(internals.shadowInit.mode as string) ? Object.setPrototypeOf(new EventTarget(), ShadowRoot.prototype) as ShadowRoot : null)
|
||||
|
||||
return internals.shadowRoot
|
||||
}
|
||||
|
||||
get assignedSlot(): HTMLSlotElement | null {
|
||||
return null
|
||||
}
|
||||
|
||||
get innerHTML(): string {
|
||||
_.internalsOf<ElementInternals>(this, 'Element', 'innerHTML')
|
||||
|
||||
return ''
|
||||
}
|
||||
|
||||
set innerHTML(value) {
|
||||
_.internalsOf<ElementInternals>(this, 'Element', 'innerHTML')
|
||||
|
||||
void value
|
||||
}
|
||||
|
||||
get shadowRoot(): ShadowRoot | null {
|
||||
const internals = _.internalsOf<ElementInternals>(this, 'Element', 'shadowRoot')
|
||||
|
||||
return Object(internals.shadowInit).mode === 'open' ? internals.shadowRoot : null
|
||||
}
|
||||
|
||||
get localName(): string {
|
||||
return _.internalsOf<ElementInternals>(this, 'Element', 'localName').localName as string
|
||||
}
|
||||
|
||||
get nodeName(): string {
|
||||
return (_.internalsOf<ElementInternals>(this, 'Element', 'nodeName').localName as string).toUpperCase()
|
||||
}
|
||||
|
||||
get tagName(): string {
|
||||
return (_.internalsOf<ElementInternals>(this, 'Element', 'tagName').localName as string).toUpperCase()
|
||||
}
|
||||
}
|
||||
|
||||
export class HTMLElement extends Element {}
|
||||
|
||||
export class HTMLBodyElement extends HTMLElement {}
|
||||
|
||||
export class HTMLDivElement extends HTMLElement {}
|
||||
|
||||
export class HTMLHeadElement extends HTMLElement {}
|
||||
|
||||
export class HTMLHtmlElement extends HTMLElement {}
|
||||
|
||||
export class HTMLSpanElement extends HTMLElement {}
|
||||
|
||||
export class HTMLStyleElement extends HTMLElement {}
|
||||
|
||||
export class HTMLTemplateElement extends HTMLElement {}
|
||||
|
||||
export class HTMLUnknownElement extends HTMLElement {}
|
||||
|
||||
_.allowStringTag(Element)
|
||||
_.allowStringTag(HTMLElement)
|
||||
_.allowStringTag(HTMLBodyElement)
|
||||
_.allowStringTag(HTMLDivElement)
|
||||
_.allowStringTag(HTMLHeadElement)
|
||||
_.allowStringTag(HTMLHtmlElement)
|
||||
_.allowStringTag(HTMLSpanElement)
|
||||
_.allowStringTag(HTMLStyleElement)
|
||||
_.allowStringTag(HTMLTemplateElement)
|
||||
_.allowStringTag(HTMLUnknownElement)
|
||||
|
||||
export interface ElementInternals {
|
||||
attributes: { [name: string]: string },
|
||||
localName?: string
|
||||
shadowRoot: ShadowRoot | null
|
||||
shadowInit: ShadowRootInit | void
|
||||
}
|
||||
|
||||
export interface ShadowRootInit {
|
||||
mode: 'open' | 'closed'
|
||||
delegatesFocus: boolean
|
||||
}
|
57
packages/webapi/src/lib/HTMLCanvasElement.ts
Normal file
57
packages/webapi/src/lib/HTMLCanvasElement.ts
Normal file
|
@ -0,0 +1,57 @@
|
|||
import type { CanvasRenderingContext2D } from './CanvasRenderingContext2D'
|
||||
|
||||
import * as _ from './utils'
|
||||
import { __createCanvasRenderingContext2D } from './CanvasRenderingContext2D'
|
||||
|
||||
export class HTMLCanvasElement extends HTMLElement {
|
||||
get height(): number {
|
||||
return _.internalsOf(this, 'HTMLCanvasElement', 'height').height
|
||||
}
|
||||
|
||||
set height(value) {
|
||||
_.internalsOf(this, 'HTMLCanvasElement', 'height').height = Number(value) || 0
|
||||
}
|
||||
|
||||
get width(): number {
|
||||
return _.internalsOf(this, 'HTMLCanvasElement', 'width').width
|
||||
}
|
||||
|
||||
set width(value) {
|
||||
_.internalsOf(this, 'HTMLCanvasElement', 'width').width = Number(value) || 0
|
||||
}
|
||||
|
||||
captureStream(): null {
|
||||
return null
|
||||
}
|
||||
|
||||
getContext(contextType: PredefinedContextId): CanvasRenderingContext2D | null {
|
||||
const internals = _.internalsOf<HTMLCanvasElementInternals>(this, 'HTMLCanvasElement', 'getContext')
|
||||
|
||||
switch (contextType) {
|
||||
case '2d':
|
||||
if (internals.renderingContext2D) return internals.renderingContext2D
|
||||
|
||||
internals.renderingContext2D = __createCanvasRenderingContext2D(this)
|
||||
|
||||
return internals.renderingContext2D
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
toBlob() {}
|
||||
|
||||
toDataURL() {}
|
||||
|
||||
transferControlToOffscreen() {}
|
||||
}
|
||||
|
||||
_.allowStringTag(HTMLCanvasElement)
|
||||
|
||||
interface HTMLCanvasElementInternals {
|
||||
width: number
|
||||
height: number
|
||||
renderingContext2D: CanvasRenderingContext2D
|
||||
}
|
||||
|
||||
type PredefinedContextId = '2d' | 'bitmaprenderer' | 'webgl' | 'webgl2' | 'webgpu'
|
16
packages/webapi/src/lib/HTMLImageElement.ts
Normal file
16
packages/webapi/src/lib/HTMLImageElement.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import * as _ from './utils'
|
||||
import { HTMLElement } from './Element'
|
||||
|
||||
export class HTMLImageElement extends HTMLElement {
|
||||
get src(): string {
|
||||
return _.internalsOf(this, 'HTMLImageElement', 'src').src
|
||||
}
|
||||
|
||||
set src(value) {
|
||||
const internals = _.internalsOf(this, 'HTMLImageElement', 'src')
|
||||
|
||||
internals.src = String(value)
|
||||
}
|
||||
}
|
||||
|
||||
_.allowStringTag(HTMLImageElement)
|
35
packages/webapi/src/lib/IdleCallback.ts
Normal file
35
packages/webapi/src/lib/IdleCallback.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
import { setTimeout as nodeSetTimeout, clearTimeout as nodeClearTimeout } from 'node:timers'
|
||||
import * as _ from './utils.js'
|
||||
|
||||
const INTERNAL = { tick: 0, pool: new Map }
|
||||
|
||||
export function requestIdleCallback<TArgs extends any[], TFunc extends (...args: TArgs) => any>(callback: TFunc): number {
|
||||
if (!INTERNAL.pool.size) {
|
||||
nodeSetTimeout(() => {
|
||||
const next = _.__performance_now()
|
||||
|
||||
for (const func of INTERNAL.pool.values()) {
|
||||
func(next)
|
||||
}
|
||||
|
||||
INTERNAL.pool.clear()
|
||||
}, 1000 / 16)
|
||||
}
|
||||
|
||||
const func = _.__function_bind(callback, undefined)
|
||||
const tick = ++INTERNAL.tick
|
||||
|
||||
INTERNAL.pool.set(tick, func)
|
||||
|
||||
return tick
|
||||
}
|
||||
|
||||
export function cancelIdleCallback(requestId: number): void {
|
||||
const timeout = INTERNAL.pool.get(requestId)
|
||||
|
||||
if (timeout) {
|
||||
nodeClearTimeout(timeout)
|
||||
|
||||
INTERNAL.pool.delete(requestId)
|
||||
}
|
||||
}
|
15
packages/webapi/src/lib/Image.ts
Normal file
15
packages/webapi/src/lib/Image.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
import * as _ from './utils'
|
||||
import { HTMLImageElement } from './HTMLImageElement'
|
||||
|
||||
export function Image() {
|
||||
// @ts-ignore
|
||||
_.INTERNALS.set(this, {
|
||||
attributes: {},
|
||||
localName: 'img',
|
||||
innerHTML: '',
|
||||
shadowRoot: null,
|
||||
shadowInit: null,
|
||||
})
|
||||
}
|
||||
|
||||
Image.prototype = HTMLImageElement.prototype
|
75
packages/webapi/src/lib/ImageData.ts
Normal file
75
packages/webapi/src/lib/ImageData.ts
Normal file
|
@ -0,0 +1,75 @@
|
|||
import * as _ from './utils'
|
||||
|
||||
export class ImageData {
|
||||
constructor(width: number, height: number);
|
||||
constructor(width: number, height: number, settings: ImageDataSettings);
|
||||
constructor(data: Uint8ClampedArray, width: number);
|
||||
constructor(data: Uint8ClampedArray, width: number, height: number);
|
||||
constructor(data: Uint8ClampedArray, width: number, height: number, settings: ImageDataSettings);
|
||||
|
||||
constructor(arg0: number | Uint8ClampedArray, arg1: number, ...args: [] | [number] | [ImageDataSettings] | [number, ImageDataSettings]) {
|
||||
if (arguments.length < 2) throw new TypeError(`Failed to construct 'ImageData': 2 arguments required.`)
|
||||
|
||||
/** Whether Uint8ClampedArray data is provided. */
|
||||
const hasData = _.__object_isPrototypeOf(Uint8ClampedArray.prototype, arg0)
|
||||
|
||||
/** Image data, either provided or calculated. */
|
||||
const d = hasData ? arg0 as Uint8ClampedArray : new Uint8ClampedArray(asNumber(arg0, 'width') * asNumber(arg1, 'height') * 4)
|
||||
|
||||
/** Image width. */
|
||||
const w = asNumber(hasData ? arg1 : arg0, 'width')
|
||||
|
||||
/** Image height. */
|
||||
const h = d.length / w / 4
|
||||
|
||||
/** Image color space. */
|
||||
const c = String(Object(hasData ? args[1] : args[0]).colorSpace || 'srgb') as PredefinedColorSpace
|
||||
|
||||
// throw if a provided height does not match the calculated height
|
||||
if (args.length && asNumber(args[0], 'height') !== h) throw new DOMException('height is not equal to (4 * width * height)', 'IndexSizeError')
|
||||
|
||||
// throw if a provided colorspace does not match a known colorspace
|
||||
if (c !== 'srgb' && c !== 'rec2020' && c !== 'display-p3') throw new TypeError('colorSpace is not known value')
|
||||
|
||||
Object.defineProperty(this, 'data', { configurable: true, enumerable: true, value: d })
|
||||
|
||||
_.INTERNALS.set(this, { width: w, height: h, colorSpace: c } as ImageDataInternals)
|
||||
}
|
||||
|
||||
get data(): Uint8ClampedArray {
|
||||
_.internalsOf<ImageDataInternals>(this, 'ImageData', 'data')
|
||||
|
||||
return (Object.getOwnPropertyDescriptor(this, 'data') as { value: Uint8ClampedArray }).value
|
||||
}
|
||||
|
||||
get width(): ImageDataInternals['width'] {
|
||||
return _.internalsOf<ImageDataInternals>(this, 'ImageData', 'width').width
|
||||
}
|
||||
|
||||
get height(): ImageDataInternals['height'] {
|
||||
return _.internalsOf<ImageDataInternals>(this, 'ImageData', 'height').height
|
||||
}
|
||||
}
|
||||
|
||||
_.allowStringTag(ImageData)
|
||||
|
||||
/** Returns a coerced number, optionally throwing if the number is zero-ish. */
|
||||
const asNumber = (value: any, axis: string): number => {
|
||||
value = Number(value) || 0
|
||||
|
||||
if (value === 0) throw new TypeError(`The source ${axis} is zero or not a number.`)
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
interface ImageDataInternals {
|
||||
colorSpace: PredefinedColorSpace
|
||||
height: number
|
||||
width: number
|
||||
}
|
||||
|
||||
interface ImageDataSettings {
|
||||
colorSpace?: PredefinedColorSpace
|
||||
}
|
||||
|
||||
type PredefinedColorSpace = 'srgb' | 'rec2020' | 'display-p3'
|
37
packages/webapi/src/lib/MediaQueryList.ts
Normal file
37
packages/webapi/src/lib/MediaQueryList.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
import * as _ from './utils'
|
||||
|
||||
export class MediaQueryList extends EventTarget {
|
||||
get matches(): boolean {
|
||||
return _.internalsOf(this, 'MediaQueryList', 'matches').matches
|
||||
}
|
||||
|
||||
get media(): string {
|
||||
return _.internalsOf(this, 'MediaQueryList', 'media').media
|
||||
}
|
||||
}
|
||||
|
||||
_.allowStringTag(MediaQueryList)
|
||||
|
||||
export const initMediaQueryList = (target: Target, exclude: Set<string>) => {
|
||||
if (exclude.has('MediaQueryList') || exclude.has('matchMedia')) return
|
||||
|
||||
const EventTarget = target.EventTarget || globalThis.EventTarget
|
||||
const MediaQueryList = target.MediaQueryList || globalThis.MediaQueryList
|
||||
|
||||
target.matchMedia = function matchMedia(media: string) {
|
||||
const mql = Object.setPrototypeOf(new EventTarget(), MediaQueryList.prototype) as MediaQueryList
|
||||
|
||||
_.INTERNALS.set(mql, {
|
||||
matches: false,
|
||||
media,
|
||||
})
|
||||
|
||||
return mql
|
||||
}
|
||||
}
|
||||
|
||||
interface Target extends Record<any, any> {
|
||||
matchMedia: {
|
||||
(media: string): MediaQueryList
|
||||
}
|
||||
}
|
166
packages/webapi/src/lib/Node.ts
Normal file
166
packages/webapi/src/lib/Node.ts
Normal file
|
@ -0,0 +1,166 @@
|
|||
import * as _ from './utils'
|
||||
|
||||
export class Node extends EventTarget {
|
||||
append(...nodesOrDOMStrings: NodeOrString[]): void {
|
||||
void nodesOrDOMStrings
|
||||
}
|
||||
|
||||
appendChild(childNode: Node): Node {
|
||||
return childNode
|
||||
}
|
||||
|
||||
after(...nodesOrDOMStrings: NodeOrString[]): void {
|
||||
void nodesOrDOMStrings
|
||||
}
|
||||
|
||||
before(...nodesOrDOMStrings: NodeOrString[]): void {
|
||||
void nodesOrDOMStrings
|
||||
}
|
||||
|
||||
prepend(...nodesOrDOMStrings: NodeOrString[]): void {
|
||||
void nodesOrDOMStrings
|
||||
}
|
||||
|
||||
replaceChild(newChild: Node, oldChild: Node): Node {
|
||||
void newChild
|
||||
|
||||
return oldChild
|
||||
}
|
||||
|
||||
removeChild(childNode: Node): Node {
|
||||
return childNode
|
||||
}
|
||||
|
||||
get attributes(): object {
|
||||
return {}
|
||||
}
|
||||
|
||||
get childNodes(): Node[] {
|
||||
return []
|
||||
}
|
||||
|
||||
get children(): Element[] {
|
||||
return []
|
||||
}
|
||||
|
||||
get ownerDocument(): Node | null {
|
||||
return null
|
||||
}
|
||||
|
||||
get nodeValue(): string {
|
||||
return ''
|
||||
}
|
||||
|
||||
set nodeValue(value: string) {
|
||||
void value
|
||||
}
|
||||
|
||||
get textContent(): string {
|
||||
return ''
|
||||
}
|
||||
|
||||
set textContent(value: string) {
|
||||
void value
|
||||
}
|
||||
|
||||
get previousElementSibling(): Node | null {
|
||||
return null
|
||||
}
|
||||
|
||||
get nextElementSibling(): Node | null {
|
||||
return null
|
||||
}
|
||||
|
||||
[Symbol.for('nodejs.util.inspect.custom')](depth: number, options: Record<string, any>) {
|
||||
return `${this.constructor.name}`;
|
||||
}
|
||||
}
|
||||
|
||||
export class DocumentFragment extends Node {}
|
||||
|
||||
export class ShadowRoot extends DocumentFragment {
|
||||
get innerHTML() {
|
||||
return ''
|
||||
}
|
||||
|
||||
set innerHTML(value: string) {
|
||||
void value
|
||||
}
|
||||
}
|
||||
|
||||
export const NodeFilter = Object.assign({
|
||||
NodeFilter() {
|
||||
throw new TypeError('Illegal constructor')
|
||||
}
|
||||
}.NodeFilter, {
|
||||
FILTER_ACCEPT: 1,
|
||||
FILTER_REJECT: 2,
|
||||
FILTER_SKIP: 3,
|
||||
SHOW_ALL: 4294967295,
|
||||
SHOW_ELEMENT: 1,
|
||||
SHOW_ATTRIBUTE: 2,
|
||||
SHOW_TEXT: 4,
|
||||
SHOW_CDATA_SECTION: 8,
|
||||
SHOW_ENTITY_REFERENCE: 16,
|
||||
SHOW_ENTITY: 32,
|
||||
SHOW_PROCESSING_INSTRUCTION: 64,
|
||||
SHOW_COMMENT: 128,
|
||||
SHOW_DOCUMENT: 256,
|
||||
SHOW_DOCUMENT_TYPE: 512,
|
||||
SHOW_DOCUMENT_FRAGMENT: 1024,
|
||||
SHOW_NOTATION: 2048,
|
||||
})
|
||||
|
||||
export class NodeIterator {
|
||||
nextNode(): Node | null {
|
||||
return null
|
||||
}
|
||||
|
||||
previousNode(): Node | null {
|
||||
return null
|
||||
}
|
||||
|
||||
get filter(): NodeFilter {
|
||||
const internals = _.internalsOf<NodeIteratorInternals>(this, 'NodeIterator', 'filter')
|
||||
return internals.filter
|
||||
}
|
||||
|
||||
get pointerBeforeReferenceNode(): boolean {
|
||||
const internals = _.internalsOf<NodeIteratorInternals>(this, 'NodeIterator', 'pointerBeforeReferenceNode')
|
||||
return internals.pointerBeforeReferenceNode
|
||||
}
|
||||
|
||||
get referenceNode(): Node {
|
||||
const internals = _.internalsOf<NodeIteratorInternals>(this, 'NodeIterator', 'referenceNode')
|
||||
return internals.referenceNode
|
||||
}
|
||||
|
||||
get root(): Node {
|
||||
const internals = _.internalsOf<NodeIteratorInternals>(this, 'NodeIterator', 'root')
|
||||
return internals.root
|
||||
}
|
||||
|
||||
get whatToShow(): number {
|
||||
const internals = _.internalsOf<NodeIteratorInternals>(this, 'NodeIterator', 'whatToShow')
|
||||
return internals.whatToShow
|
||||
}
|
||||
}
|
||||
|
||||
_.allowStringTag(Node)
|
||||
_.allowStringTag(NodeIterator)
|
||||
_.allowStringTag(DocumentFragment)
|
||||
_.allowStringTag(ShadowRoot)
|
||||
|
||||
type NodeOrString = string | Node
|
||||
|
||||
export interface NodeFilter {
|
||||
acceptNode(node: Node): number
|
||||
}
|
||||
|
||||
export interface NodeIteratorInternals {
|
||||
filter: NodeFilter
|
||||
pointerBeforeReferenceNode: boolean
|
||||
referenceNode: Node
|
||||
root: Node
|
||||
whatToShow: number
|
||||
}
|
20
packages/webapi/src/lib/Object.ts
Normal file
20
packages/webapi/src/lib/Object.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import * as _ from './utils'
|
||||
|
||||
export const hasOwn = {
|
||||
hasOwn(instance: object, property: any) {
|
||||
return _.__object_hasOwnProperty(instance, property)
|
||||
}
|
||||
}.hasOwn
|
||||
|
||||
export const initObject = (target: any, exclude: Set<string>) => {
|
||||
if (exclude.has('Object') || exclude.has('object') || exclude.has('hasOwn')) return
|
||||
|
||||
const Class = target.Object || globalThis.Object
|
||||
|
||||
Object.defineProperty(Class, 'hasOwn', {
|
||||
value: hasOwn,
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
})
|
||||
}
|
41
packages/webapi/src/lib/Observer.ts
Normal file
41
packages/webapi/src/lib/Observer.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
import * as _ from './utils'
|
||||
|
||||
export class IntersectionObserver {
|
||||
disconnect() {}
|
||||
|
||||
observe() {}
|
||||
|
||||
takeRecords() {
|
||||
return []
|
||||
}
|
||||
|
||||
unobserve() {}
|
||||
}
|
||||
|
||||
export class MutationObserver {
|
||||
disconnect() {}
|
||||
|
||||
observe() {}
|
||||
|
||||
takeRecords() {
|
||||
return []
|
||||
}
|
||||
|
||||
unobserve() {}
|
||||
}
|
||||
|
||||
export class ResizeObserver {
|
||||
disconnect() {}
|
||||
|
||||
observe() {}
|
||||
|
||||
takeRecords() {
|
||||
return []
|
||||
}
|
||||
|
||||
unobserve() {}
|
||||
}
|
||||
|
||||
_.allowStringTag(MutationObserver)
|
||||
_.allowStringTag(IntersectionObserver)
|
||||
_.allowStringTag(ResizeObserver)
|
80
packages/webapi/src/lib/OffscreenCanvas.ts
Normal file
80
packages/webapi/src/lib/OffscreenCanvas.ts
Normal file
|
@ -0,0 +1,80 @@
|
|||
import type { CanvasRenderingContext2D } from './CanvasRenderingContext2D'
|
||||
|
||||
import * as _ from './utils'
|
||||
import { __createCanvasRenderingContext2D } from './CanvasRenderingContext2D'
|
||||
|
||||
export class OffscreenCanvas extends EventTarget {
|
||||
constructor(width: number, height: number) {
|
||||
super()
|
||||
|
||||
if (arguments.length < 2) throw new TypeError(`Failed to construct 'OffscreenCanvas': 2 arguments required.`)
|
||||
|
||||
width = Number(width) || 0
|
||||
height = Number(height) || 0
|
||||
|
||||
_.INTERNALS.set(this, { width, height } as OffscreenCanvasInternals)
|
||||
}
|
||||
|
||||
get height(): number {
|
||||
return _.internalsOf(this, 'OffscreenCanvas', 'height').height
|
||||
}
|
||||
|
||||
set height(value) {
|
||||
_.internalsOf(this, 'OffscreenCanvas', 'height').height = Number(value) || 0
|
||||
}
|
||||
|
||||
get width(): number {
|
||||
return _.internalsOf(this, 'OffscreenCanvas', 'width').width
|
||||
}
|
||||
|
||||
set width(value) {
|
||||
_.internalsOf(this, 'OffscreenCanvas', 'width').width = Number(value) || 0
|
||||
}
|
||||
|
||||
getContext(contextType: PredefinedContextId): CanvasRenderingContext2D | null {
|
||||
const internals = _.internalsOf<OffscreenCanvasInternals>(this, 'HTMLCanvasElement', 'getContext')
|
||||
|
||||
switch (contextType) {
|
||||
case '2d':
|
||||
if (internals.renderingContext2D) return internals.renderingContext2D
|
||||
|
||||
internals.renderingContext2D = __createCanvasRenderingContext2D(this)
|
||||
|
||||
return internals.renderingContext2D
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
convertToBlob(options: Partial<ConvertToBlobOptions>) {
|
||||
options = Object(options)
|
||||
|
||||
const quality = Number(options.quality) || 0
|
||||
const type = getImageType(String(options.type).trim().toLowerCase())
|
||||
|
||||
void quality
|
||||
|
||||
return Promise.resolve(
|
||||
new Blob([], { type })
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
_.allowStringTag(OffscreenCanvas)
|
||||
|
||||
const getImageType = (type: string): PredefinedImageType => type === 'image/avif' || type === 'image/jpeg' || type === 'image/png' || type === 'image/webp' ? type : 'image/png'
|
||||
|
||||
interface OffscreenCanvasInternals {
|
||||
height: number
|
||||
renderingContext2D: CanvasRenderingContext2D
|
||||
width: number
|
||||
}
|
||||
|
||||
interface ConvertToBlobOptions {
|
||||
quality: number
|
||||
type: PredefinedImageType
|
||||
}
|
||||
|
||||
type PredefinedContextId = '2d' | 'bitmaprenderer' | 'webgl' | 'webgl2' | 'webgpu'
|
||||
|
||||
type PredefinedImageType = 'image/avif' | 'image/jpeg' | 'image/png' | 'image/webp'
|
29
packages/webapi/src/lib/Promise.ts
Normal file
29
packages/webapi/src/lib/Promise.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
export const any = {
|
||||
async any <T>(
|
||||
iterable: Iterable<T | PromiseLike<T>>
|
||||
): Promise<T> {
|
||||
return Promise.all(
|
||||
[...iterable].map(promise => {
|
||||
return new Promise((resolve, reject) =>
|
||||
Promise.resolve(promise).then(reject, resolve)
|
||||
)
|
||||
})
|
||||
).then(
|
||||
errors => Promise.reject(errors),
|
||||
value => Promise.resolve<T>(value)
|
||||
)
|
||||
}
|
||||
}.any
|
||||
|
||||
export const initPromise = (target: any, exclude: Set<string>) => {
|
||||
if (exclude.has('Promise') || exclude.has('any')) return
|
||||
|
||||
const Class = target.Promise || globalThis.Promise
|
||||
|
||||
if (!Class.any) Object.defineProperty(Class, 'any', {
|
||||
value: any,
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
})
|
||||
}
|
32
packages/webapi/src/lib/RelativeIndexingMethod.ts
Normal file
32
packages/webapi/src/lib/RelativeIndexingMethod.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array | BigInt64Array | BigUint64Array
|
||||
|
||||
export const at = {
|
||||
at<T extends Array<any> | string | TypedArray>(this: T, index: number) {
|
||||
index = Math.trunc(index) || 0
|
||||
|
||||
if (index < 0) index += this.length;
|
||||
|
||||
if (index < 0 || index >= this.length) return undefined;
|
||||
|
||||
return this[index];
|
||||
}
|
||||
}.at
|
||||
|
||||
export const initRelativeIndexingMethod = (target: any, exclude: Set<string>) => {
|
||||
if (exclude.has('at')) return
|
||||
|
||||
const Classes = []
|
||||
|
||||
if (!exclude.has('TypedArray')) Classes.push(Object.getPrototypeOf(target.Int8Array || globalThis.Int8Array))
|
||||
if (!exclude.has('Array')) Classes.push(target.Array || globalThis.Array)
|
||||
if (!exclude.has('String')) Classes.push(target.String || globalThis.String)
|
||||
|
||||
for (const Class of Classes) {
|
||||
if (!Class.prototype.at) Object.defineProperty(Class.prototype, 'at', {
|
||||
value: at,
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
})
|
||||
}
|
||||
}
|
51
packages/webapi/src/lib/Storage.ts
Normal file
51
packages/webapi/src/lib/Storage.ts
Normal file
|
@ -0,0 +1,51 @@
|
|||
import * as _ from './utils'
|
||||
|
||||
export class Storage {
|
||||
clear(): void {
|
||||
_.internalsOf<StorageInternals>(this, 'Storage', 'clear').storage.clear()
|
||||
}
|
||||
|
||||
getItem(key: string): string | null {
|
||||
return getStringOrNull(
|
||||
_.internalsOf<StorageInternals>(this, 'Storage', 'getItem').storage.get(String(key))
|
||||
)
|
||||
}
|
||||
|
||||
key(index: number): string | null {
|
||||
return getStringOrNull([ ..._.internalsOf<StorageInternals>(this, 'Storage', 'key').storage.keys() ][Number(index) || 0])
|
||||
}
|
||||
|
||||
removeItem(key: string): void {
|
||||
_.internalsOf<StorageInternals>(this, 'Storage', 'getItem').storage.delete(String(key))
|
||||
}
|
||||
|
||||
setItem(key: string, value: any): void {
|
||||
_.internalsOf<StorageInternals>(this, 'Storage', 'getItem').storage.set(String(key), String(value))
|
||||
}
|
||||
|
||||
get length() {
|
||||
return _.internalsOf<StorageInternals>(this, 'Storage', 'size').storage.size
|
||||
}
|
||||
}
|
||||
|
||||
const getStringOrNull = (value: string | void) => typeof value === 'string' ? value : null
|
||||
|
||||
export const initStorage = (target: Target, exclude: Set<string>) => {
|
||||
if (exclude.has('Storage') || exclude.has('localStorage')) return
|
||||
|
||||
target.localStorage = Object.create(Storage.prototype)
|
||||
|
||||
const storageInternals = new Map<string, string>()
|
||||
|
||||
_.INTERNALS.set(target.localStorage, {
|
||||
storage: storageInternals
|
||||
} as StorageInternals)
|
||||
}
|
||||
|
||||
interface StorageInternals {
|
||||
storage: Map<string, string>
|
||||
}
|
||||
|
||||
interface Target {
|
||||
localStorage: Storage
|
||||
}
|
22
packages/webapi/src/lib/String.ts
Normal file
22
packages/webapi/src/lib/String.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import * as _ from './utils'
|
||||
|
||||
export const replaceAll = {
|
||||
replaceAll(this: string, searchValue: RegExp | string, replaceValue: string | ((substring: string, ...args: any[]) => string)) {
|
||||
return _.__object_isPrototypeOf(RegExp.prototype, searchValue)
|
||||
? this.replace(searchValue as RegExp, replaceValue as string)
|
||||
: this.replace(new RegExp(_.__string_escapeRegExp(searchValue as string), 'g'), replaceValue as string)
|
||||
}
|
||||
}.replaceAll
|
||||
|
||||
export const initString = (target: any, exclude: Set<string>) => {
|
||||
if (exclude.has('String') || exclude.has('replaceAll')) return
|
||||
|
||||
const Class = target.String || globalThis.String
|
||||
|
||||
if (!Class.prototype.replaceAll) Object.defineProperty(Class.prototype, 'replaceAll', {
|
||||
value: replaceAll,
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
})
|
||||
}
|
24
packages/webapi/src/lib/StyleSheet.ts
Normal file
24
packages/webapi/src/lib/StyleSheet.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
import * as _ from './utils'
|
||||
|
||||
export class StyleSheet {}
|
||||
|
||||
export class CSSStyleSheet extends StyleSheet {
|
||||
async replace(text: string) {
|
||||
void text
|
||||
|
||||
return new CSSStyleSheet()
|
||||
}
|
||||
|
||||
replaceSync(text: string) {
|
||||
void text
|
||||
|
||||
return new CSSStyleSheet()
|
||||
}
|
||||
|
||||
get cssRules() {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
_.allowStringTag(StyleSheet)
|
||||
_.allowStringTag(CSSStyleSheet)
|
24
packages/webapi/src/lib/Timeout.ts
Normal file
24
packages/webapi/src/lib/Timeout.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
import { setTimeout as nodeSetTimeout, clearTimeout as nodeClearTimeout } from 'node:timers'
|
||||
import * as _ from './utils.js'
|
||||
|
||||
const INTERNAL = { tick: 0, pool: new Map }
|
||||
|
||||
export function setTimeout<TArgs extends any[], TFunc extends (...args: TArgs) => any>(callback: TFunc, delay = 0, ...args: TArgs): number {
|
||||
const func = _.__function_bind(callback, globalThis)
|
||||
const tick = ++INTERNAL.tick
|
||||
const timeout = nodeSetTimeout(func, delay, ...args)
|
||||
|
||||
INTERNAL.pool.set(tick, timeout)
|
||||
|
||||
return tick
|
||||
}
|
||||
|
||||
export function clearTimeout(timeoutId: number): void {
|
||||
const timeout = INTERNAL.pool.get(timeoutId)
|
||||
|
||||
if (timeout) {
|
||||
nodeClearTimeout(timeout)
|
||||
|
||||
INTERNAL.pool.delete(timeoutId)
|
||||
}
|
||||
}
|
55
packages/webapi/src/lib/TreeWalker.ts
Normal file
55
packages/webapi/src/lib/TreeWalker.ts
Normal file
|
@ -0,0 +1,55 @@
|
|||
import * as _ from './utils'
|
||||
|
||||
export class TreeWalker {
|
||||
parentNode(): Node | null {
|
||||
return null
|
||||
}
|
||||
|
||||
firstChild(): Node | null {
|
||||
return null
|
||||
}
|
||||
|
||||
lastChild(): Node | null {
|
||||
return null
|
||||
}
|
||||
|
||||
previousSibling(): Node | null {
|
||||
return null
|
||||
}
|
||||
|
||||
nextSibling(): Node | null {
|
||||
return null
|
||||
}
|
||||
|
||||
previousNode(): Node | null {
|
||||
return null
|
||||
}
|
||||
|
||||
nextNode(): Node | null {
|
||||
return null
|
||||
}
|
||||
|
||||
get currentNode(): Node {
|
||||
const internals = _.internalsOf<TreeWalkerInternals>(this, 'TreeWalker', 'currentNode')
|
||||
return internals.currentNode
|
||||
}
|
||||
|
||||
get root(): Node {
|
||||
const internals = _.internalsOf<TreeWalkerInternals>(this, 'TreeWalker', 'root')
|
||||
return internals.root
|
||||
}
|
||||
|
||||
get whatToShow(): number {
|
||||
const internals = _.internalsOf<TreeWalkerInternals>(this, 'TreeWalker', 'whatToShow')
|
||||
return internals.whatToShow
|
||||
}
|
||||
}
|
||||
|
||||
_.allowStringTag(TreeWalker)
|
||||
|
||||
export interface TreeWalkerInternals {
|
||||
filter: NodeFilter
|
||||
currentNode: Node
|
||||
root: Node
|
||||
whatToShow: number
|
||||
}
|
49
packages/webapi/src/lib/Window.ts
Normal file
49
packages/webapi/src/lib/Window.ts
Normal file
|
@ -0,0 +1,49 @@
|
|||
import * as _ from './utils'
|
||||
|
||||
export class Window extends EventTarget {
|
||||
get self(): this {
|
||||
return this
|
||||
}
|
||||
|
||||
get top(): this {
|
||||
return this
|
||||
}
|
||||
|
||||
get window(): this {
|
||||
return this
|
||||
}
|
||||
|
||||
get innerHeight(): number {
|
||||
return 0
|
||||
}
|
||||
|
||||
get innerWidth(): number {
|
||||
return 0
|
||||
}
|
||||
|
||||
get scrollX(): number {
|
||||
return 0
|
||||
}
|
||||
|
||||
get scrollY(): number {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
_.allowStringTag(Window)
|
||||
|
||||
export const initWindow = (target: Target, exclude: Set<string>) => {
|
||||
if (exclude.has('Window') || exclude.has('window')) return
|
||||
|
||||
target.window = target
|
||||
}
|
||||
|
||||
export interface WindowInternals {
|
||||
document: null
|
||||
location: URL
|
||||
window: this
|
||||
}
|
||||
|
||||
interface Target extends Record<any, any> {
|
||||
window: this
|
||||
}
|
75
packages/webapi/src/lib/fetch.ts
Normal file
75
packages/webapi/src/lib/fetch.ts
Normal file
|
@ -0,0 +1,75 @@
|
|||
import { default as nodeFetch, Headers, Request, Response } from 'node-fetch/src/index.js'
|
||||
import Stream from 'node:stream'
|
||||
import * as _ from './utils'
|
||||
|
||||
export { Headers, Request, Response }
|
||||
|
||||
export const fetch = {
|
||||
fetch(resource: string | URL | Request, init?: Partial<FetchInit>): Promise<Response> {
|
||||
const resourceURL = new URL(
|
||||
_.__object_isPrototypeOf(Request.prototype, resource)
|
||||
? (resource as Request).url
|
||||
: _.pathToPosix(resource),
|
||||
typeof Object(globalThis.process).cwd === 'function' ? 'file:' + _.pathToPosix(process.cwd()) + '/' : 'file:'
|
||||
)
|
||||
|
||||
if (resourceURL.protocol.toLowerCase() === 'file:') {
|
||||
return import('node:fs').then(
|
||||
fs => {
|
||||
try {
|
||||
const stats = fs.statSync(resourceURL)
|
||||
const body = fs.createReadStream(resourceURL)
|
||||
|
||||
return new Response(
|
||||
body,
|
||||
{
|
||||
status: 200,
|
||||
statusText: '',
|
||||
headers: {
|
||||
'content-length': String(stats.size),
|
||||
'date': new Date().toUTCString(),
|
||||
'last-modified': new Date(stats.mtimeMs).toUTCString(),
|
||||
}
|
||||
}
|
||||
)
|
||||
} catch (error) {
|
||||
const body = new Stream.Readable()
|
||||
|
||||
body._read = () => {}
|
||||
body.push(null)
|
||||
|
||||
return new Response(
|
||||
body,
|
||||
{
|
||||
status: 404,
|
||||
statusText: '',
|
||||
headers: {
|
||||
'date': new Date().toUTCString(),
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
} else {
|
||||
return nodeFetch(resource, init)
|
||||
}
|
||||
}
|
||||
}.fetch
|
||||
|
||||
type USVString = ({} & string)
|
||||
|
||||
interface FetchInit {
|
||||
body: Blob | BufferSource | FormData | URLSearchParams | ReadableStream | USVString
|
||||
cache: 'default' | 'no-store' | 'reload' | 'no-cache' | 'force-cache' | 'only-if-cached'
|
||||
credentials: 'omit' | 'same-origin' | 'include'
|
||||
headers: Headers | Record<string, string>
|
||||
method: 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'CONNECT' | 'OPTIONS' | 'TRACE' | 'PATCH' | USVString
|
||||
mode: 'cors' | 'no-cors' | 'same-origin' | USVString
|
||||
redirect: 'follow' | 'manual' | 'error'
|
||||
referrer: USVString
|
||||
referrerPolicy: 'no-referrer' | 'no-referrer-when-downgrade' | 'same-origin' | 'origin' | 'strict-origin' | 'origin-when-cross-origin' | 'strict-origin-when-cross-origin' | 'unsafe-url'
|
||||
integrity: USVString
|
||||
keepalive: boolean
|
||||
signal: AbortSignal
|
||||
}
|
4
packages/webapi/src/lib/structuredClone.ts
Normal file
4
packages/webapi/src/lib/structuredClone.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
import { deserialize } from '@ungap/structured-clone/esm/deserialize.js';
|
||||
import { serialize } from '@ungap/structured-clone/esm/serialize.js';
|
||||
|
||||
export default (any: any, options: any) => deserialize(serialize(any, options))
|
61
packages/webapi/src/lib/utils.ts
Normal file
61
packages/webapi/src/lib/utils.ts
Normal file
|
@ -0,0 +1,61 @@
|
|||
import { performance } from 'node:perf_hooks'
|
||||
|
||||
/** Returns the milliseconds elapsed since January 1, 1970 00:00:00 UTC. */
|
||||
export const __date_now = Date.now
|
||||
|
||||
/** Returns the function bound to the given object. */
|
||||
export const __function_bind = Function.bind.bind(Function.call as unknown as any) as <TArgs extends any[], TFunc extends (...args: TArgs) => any>(callback: TFunc, thisArg: unknown, ...args: TArgs) => TFunc
|
||||
|
||||
/** Returns the function called with the specified values. */
|
||||
export const __function_call = Function.call.bind(Function.call as unknown as any) as <TArgs extends any, TFunc extends (...args: TArgs[]) => any>(callback: TFunc, thisArg: unknown, ...args: TArgs[]) => ReturnType<TFunc>
|
||||
|
||||
/** Returns an object with the specified prototype. */
|
||||
export const __object_create = Object.create as { <T extends any = any>(value: T): any extends T ? Record<any, any> : T }
|
||||
|
||||
/** Returns whether an object has a property with the specified name. */
|
||||
export const __object_hasOwnProperty = Function.call.bind(Object.prototype.hasOwnProperty) as { <T1 extends object, T2>(object: T1, key: T2): T2 extends keyof T1 ? true : false }
|
||||
|
||||
/** Returns a string representation of an object. */
|
||||
export const __object_toString = Function.call.bind(Object.prototype.toString) as { (value: any): string }
|
||||
|
||||
/** Returns whether the object prototype exists in another object. */
|
||||
export const __object_isPrototypeOf = Function.call.bind(Object.prototype.isPrototypeOf) as { <T1 extends object, T2>(p: T1, v: T2): T2 extends T1 ? true : false }
|
||||
|
||||
/** Current high resolution millisecond timestamp. */
|
||||
export const __performance_now = performance.now as () => number
|
||||
|
||||
/** Returns the string escaped for use inside regular expressions. */
|
||||
export const __string_escapeRegExp = (value: string) => value.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&')
|
||||
|
||||
// @ts-ignore
|
||||
export const INTERNALS = new WeakMap<unknown, any>()
|
||||
|
||||
export const internalsOf = <T extends object>(target: T | object, className: string, propName: string): T => {
|
||||
const internals: T = INTERNALS.get(target)
|
||||
|
||||
if (!internals) throw new TypeError(`${className}.${propName} can only be used on instances of ${className}`)
|
||||
|
||||
return internals
|
||||
}
|
||||
|
||||
export const allowStringTag = (value: any) => value.prototype[Symbol.toStringTag] = value.name
|
||||
|
||||
/** Returns any kind of path as a posix path. */
|
||||
export const pathToPosix = (pathname: any) => String(
|
||||
pathname == null ? '' : pathname
|
||||
).replace(
|
||||
// convert slashes
|
||||
/\\+/g, '/'
|
||||
).replace(
|
||||
// prefix a slash to drive letters
|
||||
/^(?=[A-Za-z]:\/)/, '/'
|
||||
).replace(
|
||||
// encode path characters
|
||||
/%/g, '%25'
|
||||
).replace(
|
||||
/\n/g, '%0A'
|
||||
).replace(
|
||||
/\r/g, '%0D'
|
||||
).replace(
|
||||
/\t/g, '%09'
|
||||
)
|
338
packages/webapi/src/polyfill.ts
Normal file
338
packages/webapi/src/polyfill.ts
Normal file
|
@ -0,0 +1,338 @@
|
|||
import {
|
||||
AbortController,
|
||||
AbortSignal,
|
||||
Blob,
|
||||
ByteLengthQueuingStrategy,
|
||||
CanvasRenderingContext2D,
|
||||
CharacterData,
|
||||
Comment,
|
||||
CountQueuingStrategy,
|
||||
CSSStyleSheet,
|
||||
CustomElementRegistry,
|
||||
CustomEvent,
|
||||
DOMException,
|
||||
Document,
|
||||
DocumentFragment,
|
||||
Element,
|
||||
Event,
|
||||
EventTarget,
|
||||
File,
|
||||
FormData,
|
||||
HTMLDocument,
|
||||
HTMLElement,
|
||||
HTMLBodyElement,
|
||||
HTMLCanvasElement,
|
||||
HTMLDivElement,
|
||||
HTMLHeadElement,
|
||||
HTMLHtmlElement,
|
||||
HTMLImageElement,
|
||||
HTMLSpanElement,
|
||||
HTMLStyleElement,
|
||||
HTMLTemplateElement,
|
||||
HTMLUnknownElement,
|
||||
Headers,
|
||||
IntersectionObserver,
|
||||
Image,
|
||||
ImageData,
|
||||
MediaQueryList,
|
||||
MutationObserver,
|
||||
Node,
|
||||
NodeFilter,
|
||||
NodeIterator,
|
||||
OffscreenCanvas,
|
||||
ReadableByteStreamController,
|
||||
ReadableStream,
|
||||
ReadableStreamBYOBReader,
|
||||
ReadableStreamBYOBRequest,
|
||||
ReadableStreamDefaultController,
|
||||
ReadableStreamDefaultReader,
|
||||
Request,
|
||||
ResizeObserver,
|
||||
Response,
|
||||
ShadowRoot,
|
||||
Storage,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TransformStream,
|
||||
TreeWalker,
|
||||
URLPattern,
|
||||
WritableStream,
|
||||
WritableStreamDefaultController,
|
||||
WritableStreamDefaultWriter,
|
||||
Window,
|
||||
|
||||
alert,
|
||||
atob,
|
||||
btoa,
|
||||
cancelAnimationFrame,
|
||||
cancelIdleCallback,
|
||||
clearTimeout,
|
||||
fetch,
|
||||
requestAnimationFrame,
|
||||
requestIdleCallback,
|
||||
setTimeout,
|
||||
structuredClone,
|
||||
|
||||
initCustomElementRegistry,
|
||||
initDocument,
|
||||
initMediaQueryList,
|
||||
initObject,
|
||||
initPromise,
|
||||
initRelativeIndexingMethod,
|
||||
initStorage,
|
||||
initString,
|
||||
initWindow,
|
||||
} from './ponyfill'
|
||||
|
||||
import { exclusions } from './exclusions'
|
||||
import { inheritence } from './inheritence'
|
||||
|
||||
export {
|
||||
AbortController,
|
||||
AbortSignal,
|
||||
Blob,
|
||||
ByteLengthQueuingStrategy,
|
||||
CanvasRenderingContext2D,
|
||||
CharacterData,
|
||||
Comment,
|
||||
CountQueuingStrategy,
|
||||
CSSStyleSheet,
|
||||
CustomElementRegistry,
|
||||
CustomEvent,
|
||||
DOMException,
|
||||
Document,
|
||||
DocumentFragment,
|
||||
Element,
|
||||
Event,
|
||||
EventTarget,
|
||||
File,
|
||||
FormData,
|
||||
HTMLDocument,
|
||||
HTMLElement,
|
||||
HTMLBodyElement,
|
||||
HTMLCanvasElement,
|
||||
HTMLDivElement,
|
||||
HTMLHeadElement,
|
||||
HTMLHtmlElement,
|
||||
HTMLImageElement,
|
||||
HTMLSpanElement,
|
||||
HTMLStyleElement,
|
||||
HTMLTemplateElement,
|
||||
HTMLUnknownElement,
|
||||
Headers,
|
||||
IntersectionObserver,
|
||||
Image,
|
||||
ImageData,
|
||||
MediaQueryList,
|
||||
MutationObserver,
|
||||
Node,
|
||||
NodeFilter,
|
||||
NodeIterator,
|
||||
OffscreenCanvas,
|
||||
ReadableByteStreamController,
|
||||
ReadableStream,
|
||||
ReadableStreamBYOBReader,
|
||||
ReadableStreamBYOBRequest,
|
||||
ReadableStreamDefaultController,
|
||||
ReadableStreamDefaultReader,
|
||||
Request,
|
||||
ResizeObserver,
|
||||
Response,
|
||||
ShadowRoot,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TransformStream,
|
||||
TreeWalker,
|
||||
URLPattern,
|
||||
WritableStream,
|
||||
WritableStreamDefaultController,
|
||||
WritableStreamDefaultWriter,
|
||||
Window,
|
||||
|
||||
alert,
|
||||
atob,
|
||||
btoa,
|
||||
cancelAnimationFrame,
|
||||
cancelIdleCallback,
|
||||
clearTimeout,
|
||||
fetch,
|
||||
requestAnimationFrame,
|
||||
requestIdleCallback,
|
||||
setTimeout,
|
||||
structuredClone,
|
||||
} from './ponyfill.js'
|
||||
|
||||
export { pathToPosix } from './lib/utils'
|
||||
|
||||
export const polyfill = (target: any, options?: PolyfillOptions) => {
|
||||
const webAPIs = {
|
||||
AbortController,
|
||||
AbortSignal,
|
||||
Blob,
|
||||
ByteLengthQueuingStrategy,
|
||||
CanvasRenderingContext2D,
|
||||
CharacterData,
|
||||
Comment,
|
||||
CountQueuingStrategy,
|
||||
CSSStyleSheet,
|
||||
CustomElementRegistry,
|
||||
CustomEvent,
|
||||
Document,
|
||||
DocumentFragment,
|
||||
DOMException,
|
||||
Element,
|
||||
Event,
|
||||
EventTarget,
|
||||
File,
|
||||
FormData,
|
||||
HTMLDocument,
|
||||
HTMLElement,
|
||||
HTMLBodyElement,
|
||||
HTMLCanvasElement,
|
||||
HTMLDivElement,
|
||||
HTMLHeadElement,
|
||||
HTMLHtmlElement,
|
||||
HTMLImageElement,
|
||||
HTMLSpanElement,
|
||||
HTMLStyleElement,
|
||||
HTMLTemplateElement,
|
||||
HTMLUnknownElement,
|
||||
Headers,
|
||||
IntersectionObserver,
|
||||
Image,
|
||||
ImageData,
|
||||
MediaQueryList,
|
||||
MutationObserver,
|
||||
Node,
|
||||
NodeFilter,
|
||||
NodeIterator,
|
||||
OffscreenCanvas,
|
||||
ReadableByteStreamController,
|
||||
ReadableStream,
|
||||
ReadableStreamBYOBReader,
|
||||
ReadableStreamBYOBRequest,
|
||||
ReadableStreamDefaultController,
|
||||
ReadableStreamDefaultReader,
|
||||
Request,
|
||||
ResizeObserver,
|
||||
Response,
|
||||
ShadowRoot,
|
||||
Storage,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TransformStream,
|
||||
TreeWalker,
|
||||
URLPattern,
|
||||
WritableStream,
|
||||
WritableStreamDefaultController,
|
||||
WritableStreamDefaultWriter,
|
||||
Window,
|
||||
|
||||
alert,
|
||||
atob,
|
||||
btoa,
|
||||
cancelAnimationFrame,
|
||||
cancelIdleCallback,
|
||||
clearTimeout,
|
||||
fetch,
|
||||
requestAnimationFrame,
|
||||
requestIdleCallback,
|
||||
setTimeout,
|
||||
structuredClone,
|
||||
}
|
||||
|
||||
// initialize exclude options
|
||||
const excludeOptions = new Set(
|
||||
typeof Object(options).exclude === 'string'
|
||||
? String(Object(options).exclude).trim().split(/\s+/)
|
||||
: Array.isArray(Object(options).exclude)
|
||||
? Object(options).exclude.reduce(
|
||||
(array: string[], entry: unknown) => array.splice(array.length, 0, ...(typeof entry === 'string' ? entry.trim().split(/\s+/) : [])) && array,
|
||||
[]
|
||||
)
|
||||
: []
|
||||
) as Set<string>
|
||||
|
||||
// expand exclude options using exclusion shorthands
|
||||
for (const excludeOption of excludeOptions) {
|
||||
if (excludeOption in exclusions) {
|
||||
for (const exclusion of exclusions[excludeOption as keyof typeof exclusions]) {
|
||||
excludeOptions.add(exclusion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// apply each WebAPI
|
||||
for (const name of Object.keys(webAPIs)) {
|
||||
// skip WebAPIs that are excluded
|
||||
if (excludeOptions.has(name)) continue
|
||||
|
||||
// skip WebAPIs that are built-in
|
||||
if (Object.hasOwnProperty.call(target, name)) continue
|
||||
|
||||
// define WebAPIs on the target
|
||||
Object.defineProperty(target, name, { configurable: true, enumerable: true, writable: true, value: webAPIs[name as keyof typeof webAPIs] })
|
||||
}
|
||||
|
||||
// ensure WebAPIs correctly inherit other WebAPIs
|
||||
for (const name of Object.keys(webAPIs)) {
|
||||
// skip WebAPIs that are excluded
|
||||
if (excludeOptions.has(name)) continue
|
||||
|
||||
// skip WebAPIs that do not extend other WebAPIs
|
||||
if (!Object.hasOwnProperty.call(inheritence, name)) continue
|
||||
|
||||
const Class = target[name]
|
||||
const Super = target[inheritence[name as keyof typeof inheritence]]
|
||||
|
||||
// skip WebAPIs that are not available
|
||||
if (!Class || !Super) continue
|
||||
|
||||
// skip WebAPIs that are already inherited correctly
|
||||
if (Object.getPrototypeOf(Class.prototype) === Super.prototype) continue
|
||||
|
||||
// define WebAPIs inheritence
|
||||
Object.setPrototypeOf(Class.prototype, Super.prototype)
|
||||
}
|
||||
|
||||
if (!excludeOptions.has('HTMLDocument') && !excludeOptions.has('HTMLElement')) {
|
||||
initDocument(target, excludeOptions)
|
||||
|
||||
if (!excludeOptions.has('CustomElementRegistry')) {
|
||||
initCustomElementRegistry(target, excludeOptions)
|
||||
}
|
||||
}
|
||||
|
||||
initObject(target, excludeOptions)
|
||||
initMediaQueryList(target, excludeOptions)
|
||||
initPromise(target, excludeOptions)
|
||||
initRelativeIndexingMethod(target, excludeOptions)
|
||||
initStorage(target, excludeOptions)
|
||||
initString(target, excludeOptions)
|
||||
initWindow(target, excludeOptions)
|
||||
|
||||
return target
|
||||
}
|
||||
|
||||
polyfill.internals = (target: any, name: string) => {
|
||||
const init = {
|
||||
CustomElementRegistry: initCustomElementRegistry,
|
||||
Document: initDocument,
|
||||
MediaQueryList: initMediaQueryList,
|
||||
Object: initObject,
|
||||
Promise: initPromise,
|
||||
RelativeIndexingMethod: initRelativeIndexingMethod,
|
||||
Storage: initStorage,
|
||||
String: initString,
|
||||
Window: initWindow,
|
||||
}
|
||||
|
||||
init[name as keyof typeof init](target, new Set<string>())
|
||||
|
||||
return target
|
||||
}
|
||||
|
||||
interface PolyfillOptions {
|
||||
exclude?: string | string[]
|
||||
override?: Record<string, { (...args: any[]): any }>
|
||||
}
|
127
packages/webapi/src/ponyfill.ts
Normal file
127
packages/webapi/src/ponyfill.ts
Normal file
|
@ -0,0 +1,127 @@
|
|||
// @ts-check
|
||||
|
||||
import { AbortController, AbortSignal } from 'abort-controller/dist/abort-controller.mjs'
|
||||
import { requestAnimationFrame, cancelAnimationFrame } from './lib/AnimationFrame'
|
||||
import { atob, btoa } from './lib/Base64'
|
||||
import { CharacterData, Comment, Text } from './lib/CharacterData'
|
||||
import { File, Blob } from 'fetch-blob/from.js'
|
||||
import { CustomEvent } from './lib/CustomEvent'
|
||||
import { DOMException } from './lib/DOMException'
|
||||
import { TreeWalker } from './lib/TreeWalker'
|
||||
import { cancelIdleCallback, requestIdleCallback } from './lib/IdleCallback'
|
||||
import { Event, EventTarget } from 'event-target-shim'
|
||||
import { fetch, Headers, Request, Response } from './lib/fetch'
|
||||
import { FormData } from 'formdata-polyfill/esm.min.js'
|
||||
import { ByteLengthQueuingStrategy, CountQueuingStrategy, ReadableByteStreamController, ReadableStream, ReadableStreamBYOBReader, ReadableStreamBYOBRequest, ReadableStreamDefaultController, ReadableStreamDefaultReader, TransformStream, WritableStream, WritableStreamDefaultController, WritableStreamDefaultWriter } from 'web-streams-polyfill/dist/ponyfill.es6.mjs'
|
||||
import { URLPattern } from 'urlpattern-polyfill'
|
||||
import { setTimeout, clearTimeout } from './lib/Timeout'
|
||||
import structuredClone from './lib/structuredClone'
|
||||
|
||||
import { CanvasRenderingContext2D } from './lib/CanvasRenderingContext2D'
|
||||
import { CSSStyleSheet, StyleSheet } from './lib/StyleSheet'
|
||||
import { CustomElementRegistry, initCustomElementRegistry } from './lib/CustomElementRegistry'
|
||||
import { Document, HTMLDocument, initDocument } from './lib/Document'
|
||||
import { DocumentFragment, Node, NodeFilter, NodeIterator, ShadowRoot } from './lib/Node'
|
||||
import { Element, HTMLElement, HTMLBodyElement, HTMLDivElement, HTMLHeadElement, HTMLHtmlElement, HTMLSpanElement, HTMLStyleElement, HTMLTemplateElement, HTMLUnknownElement } from './lib/Element'
|
||||
import { HTMLCanvasElement } from './lib/HTMLCanvasElement'
|
||||
import { HTMLImageElement } from './lib/HTMLImageElement'
|
||||
import { Image } from './lib/Image'
|
||||
import { ImageData } from './lib/ImageData'
|
||||
import { IntersectionObserver, MutationObserver, ResizeObserver } from './lib/Observer'
|
||||
import { MediaQueryList, initMediaQueryList } from './lib/MediaQueryList'
|
||||
import { OffscreenCanvas } from './lib/OffscreenCanvas'
|
||||
import { Storage, initStorage } from './lib/Storage'
|
||||
import { Window, initWindow } from './lib/Window'
|
||||
|
||||
import { alert } from './lib/Alert'
|
||||
|
||||
import { initObject } from './lib/Object'
|
||||
import { initPromise } from './lib/Promise'
|
||||
import { initRelativeIndexingMethod } from './lib/RelativeIndexingMethod'
|
||||
import { initString } from './lib/String'
|
||||
|
||||
export {
|
||||
AbortController,
|
||||
AbortSignal,
|
||||
Blob,
|
||||
ByteLengthQueuingStrategy,
|
||||
CanvasRenderingContext2D,
|
||||
CharacterData,
|
||||
Comment,
|
||||
CountQueuingStrategy,
|
||||
CSSStyleSheet,
|
||||
CustomElementRegistry,
|
||||
CustomEvent,
|
||||
DOMException,
|
||||
Document,
|
||||
DocumentFragment,
|
||||
Element,
|
||||
Event,
|
||||
EventTarget,
|
||||
File,
|
||||
FormData,
|
||||
Headers,
|
||||
HTMLBodyElement,
|
||||
HTMLCanvasElement,
|
||||
HTMLDivElement,
|
||||
HTMLDocument,
|
||||
HTMLElement,
|
||||
HTMLHeadElement,
|
||||
HTMLHtmlElement,
|
||||
HTMLImageElement,
|
||||
HTMLSpanElement,
|
||||
HTMLStyleElement,
|
||||
HTMLTemplateElement,
|
||||
HTMLUnknownElement,
|
||||
Image,
|
||||
ImageData,
|
||||
IntersectionObserver,
|
||||
MediaQueryList,
|
||||
MutationObserver,
|
||||
Node,
|
||||
NodeFilter,
|
||||
NodeIterator,
|
||||
OffscreenCanvas,
|
||||
ReadableByteStreamController,
|
||||
ReadableStream,
|
||||
ReadableStreamBYOBReader,
|
||||
ReadableStreamBYOBRequest,
|
||||
ReadableStreamDefaultController,
|
||||
ReadableStreamDefaultReader,
|
||||
Request,
|
||||
ResizeObserver,
|
||||
Response,
|
||||
ShadowRoot,
|
||||
Storage,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TransformStream,
|
||||
TreeWalker,
|
||||
URLPattern,
|
||||
WritableStream,
|
||||
WritableStreamDefaultController,
|
||||
WritableStreamDefaultWriter,
|
||||
Window,
|
||||
|
||||
alert,
|
||||
atob,
|
||||
btoa,
|
||||
cancelAnimationFrame,
|
||||
cancelIdleCallback,
|
||||
clearTimeout,
|
||||
fetch,
|
||||
requestAnimationFrame,
|
||||
requestIdleCallback,
|
||||
setTimeout,
|
||||
structuredClone,
|
||||
|
||||
initCustomElementRegistry,
|
||||
initDocument,
|
||||
initMediaQueryList,
|
||||
initObject,
|
||||
initPromise,
|
||||
initRelativeIndexingMethod,
|
||||
initStorage,
|
||||
initString,
|
||||
initWindow,
|
||||
}
|
6
packages/webapi/src/types.d.ts
vendored
Normal file
6
packages/webapi/src/types.d.ts
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
declare module '@ungap/structured-clone/esm/index.js'
|
||||
declare module '@ungap/structured-clone/esm/deserialize.js'
|
||||
declare module '@ungap/structured-clone/esm/serialize.js'
|
||||
declare module 'abort-controller/dist/abort-controller.mjs'
|
||||
declare module 'node-fetch/src/index.js'
|
||||
declare module 'web-streams-polyfill/dist/ponyfill.es6.mjs'
|
48
packages/webapi/test/base64.js
Normal file
48
packages/webapi/test/base64.js
Normal file
|
@ -0,0 +1,48 @@
|
|||
import { assert, test } from '../run/test.setup.js'
|
||||
import { polyfill } from '../mod.js'
|
||||
|
||||
test(() => {
|
||||
return [
|
||||
{
|
||||
name: 'Supports Base64 Methods',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
assert.equal('atob' in target, true)
|
||||
assert.equal('btoa' in target, true)
|
||||
assert.equal(typeof target['atob'], 'function')
|
||||
assert.equal(typeof target['btoa'], 'function')
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Supports atob(data)',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
const a = 'SGVsbG8sIHdvcmxk'
|
||||
const b = target.atob(a)
|
||||
|
||||
assert.equal(a, 'SGVsbG8sIHdvcmxk')
|
||||
assert.equal(b, 'Hello, world')
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Supports btoa(data)',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
const b = 'Hello, world'
|
||||
const a = target.btoa(b)
|
||||
|
||||
assert.equal(a, 'SGVsbG8sIHdvcmxk')
|
||||
assert.equal(b, 'Hello, world')
|
||||
},
|
||||
},
|
||||
]
|
||||
})
|
156
packages/webapi/test/basic.js
Normal file
156
packages/webapi/test/basic.js
Normal file
|
@ -0,0 +1,156 @@
|
|||
import { assert, test } from '../run/test.setup.js'
|
||||
import { polyfill } from '../mod.js'
|
||||
|
||||
test(() => {
|
||||
polyfill(globalThis)
|
||||
|
||||
return [
|
||||
{
|
||||
name: 'Globals exist',
|
||||
test() {
|
||||
const webAPIs = [ 'AbortController', 'AbortSignal', 'Blob', 'ByteLengthQueuingStrategy', 'CSSStyleSheet', 'CountQueuingStrategy', 'CustomElementRegistry', 'CustomEvent', 'DOMException', 'Document', 'DocumentFragment', 'Element', 'Event', 'EventTarget', 'File', 'FormData', 'HTMLDocument', 'HTMLElement', 'HTMLDivElement', 'HTMLHeadElement', 'HTMLHtmlElement', 'HTMLImageElement', 'HTMLStyleElement', 'HTMLTemplateElement', 'HTMLUnknownElement', 'Headers', 'IntersectionObserver', 'Image', 'MediaQueryList', 'MutationObserver', 'Node', 'ReadableByteStreamController', 'ReadableStream', 'ReadableStreamBYOBReader', 'ReadableStreamBYOBRequest', 'ReadableStreamDefaultController', 'ReadableStreamDefaultReader', 'Request', 'Response', 'ShadowRoot', 'StyleSheet', 'TransformStream', 'WritableStream', 'WritableStreamDefaultController', 'WritableStreamDefaultWriter', 'Window', 'cancelAnimationFrame', 'cancelIdleCallback', 'clearTimeout', 'fetch', 'requestAnimationFrame', 'requestIdleCallback', 'setTimeout' ]
|
||||
|
||||
for (const name of webAPIs) {
|
||||
assert.equal(typeof globalThis[name], 'function')
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Constructs an Event',
|
||||
test() {
|
||||
const e = new Event('test')
|
||||
|
||||
assert.equal(e.type, 'test')
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Constructs an EventTarget',
|
||||
test() {
|
||||
const t = new EventTarget()
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Dispatches an Event on an EventTarget',
|
||||
test() {
|
||||
const t = new EventTarget()
|
||||
|
||||
let pass = false
|
||||
|
||||
t.addEventListener('test', (event) => {
|
||||
pass = true
|
||||
})
|
||||
|
||||
const e = new Event('test')
|
||||
|
||||
t.dispatchEvent(e)
|
||||
|
||||
assert.equal(pass, true)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Classes extend as expected',
|
||||
test() {
|
||||
assert.equal(HTMLElement.prototype instanceof Element, true)
|
||||
assert.equal(Element.prototype instanceof Node, true)
|
||||
assert.equal(Node.prototype instanceof EventTarget, true)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'DOM Methods have no effect',
|
||||
test() {
|
||||
const element = document.createElement('div')
|
||||
|
||||
assert.equal(element.innerHTML, '')
|
||||
element.innerHTML = 'frozen'
|
||||
assert.equal(element.innerHTML, '')
|
||||
|
||||
assert.equal(element.textContent, '')
|
||||
element.textContent = 'frozen'
|
||||
assert.equal(element.textContent, '')
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'globalThis.window === globalThis',
|
||||
test() {
|
||||
assert.equal(globalThis.window, globalThis)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Relative Indexing Method (String#at)',
|
||||
test() {
|
||||
assert.equal(typeof String.prototype.at, 'function')
|
||||
assert.equal(String.prototype.at.length, 1)
|
||||
|
||||
const example = 'The quick brown fox jumps over the lazy dog.'
|
||||
|
||||
assert.equal(example.at(2), 'e')
|
||||
assert.equal(example.at(-2), 'g')
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Relative Indexing Method (Array#at)',
|
||||
test() {
|
||||
assert.equal(typeof Array.prototype.at, 'function')
|
||||
assert.equal(Array.prototype.at.length, 1)
|
||||
|
||||
const example = [1, 3, 5, 7, 9]
|
||||
|
||||
assert.equal(example.at(1), 3)
|
||||
assert.equal(example.at(-1), 9)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Relative Indexing Method (TypedArray#at)',
|
||||
test() {
|
||||
assert.equal(typeof Int8Array.prototype.at, 'function')
|
||||
assert.equal(Int8Array.prototype.at.length, 1)
|
||||
|
||||
const example = new Int8Array([1, 3, 5, 7, 9])
|
||||
|
||||
assert.equal(example.at(1), 3)
|
||||
assert.equal(example.at(-1), 9)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Object.hasOwn',
|
||||
test() {
|
||||
assert.equal(typeof Object.hasOwn, 'function')
|
||||
assert.equal(Object.hasOwn.length, 2)
|
||||
|
||||
const example = {}
|
||||
|
||||
assert.equal(Object.hasOwn(example, 'prop'), false)
|
||||
|
||||
example.prop = 'exists'
|
||||
|
||||
assert.equal(Object.hasOwn(example, 'prop'), true)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Promise.any',
|
||||
test() {
|
||||
assert.equal(typeof Promise.any, 'function')
|
||||
assert.equal(Promise.any.length, 1)
|
||||
|
||||
Promise.any([Promise.resolve(42), Promise.reject(-1), Promise.reject(Infinity)]).then(
|
||||
result => {
|
||||
assert.equal(result, 42)
|
||||
}
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'String#replaceAll',
|
||||
test() {
|
||||
assert.equal(typeof String.prototype.replaceAll, 'function')
|
||||
assert.equal(String.prototype.replaceAll.length, 2)
|
||||
|
||||
const t1 = 'Of all the sorcerers in Harry Potter, Halo is my favorite sorcerer.'
|
||||
const t2 = t1.replaceAll('sorcerer', 'philosopher')
|
||||
const t3 = 'Of all the philosophers in Harry Potter, Halo is my favorite philosopher.'
|
||||
|
||||
assert.equal(t2, t3)
|
||||
},
|
||||
},
|
||||
]
|
||||
})
|
59
packages/webapi/test/characterdata.js
Normal file
59
packages/webapi/test/characterdata.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
import { assert, test } from '../run/test.setup.js'
|
||||
import { polyfill } from '../mod.js'
|
||||
|
||||
test(() => {
|
||||
return [
|
||||
{
|
||||
name: 'Includes CharacterData functionality',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
assert.equal(Reflect.has(target, 'CharacterData'), true)
|
||||
assert.equal(Reflect.has(target, 'Text'), true)
|
||||
assert.equal(Reflect.has(target, 'Comment'), true)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Throws new CharacterData',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Supports new Comment',
|
||||
test() {
|
||||
const target = polyfill({})
|
||||
|
||||
assert.doesNotThrow(() => {
|
||||
new target.Comment()
|
||||
})
|
||||
|
||||
assert.equal(new target.Comment().constructor.name, 'Comment')
|
||||
assert.equal(Object.prototype.toString.call(new target.Comment()), '[object Comment]')
|
||||
|
||||
assert.equal(new target.Comment('hello').data, 'hello')
|
||||
assert.equal(new target.Comment('hello').textContent, 'hello')
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Supports new Text',
|
||||
test() {
|
||||
const target = polyfill({})
|
||||
|
||||
assert.doesNotThrow(() => {
|
||||
new target.Text()
|
||||
})
|
||||
|
||||
assert.equal(new target.Text().constructor.name, 'Text')
|
||||
assert.equal(Object.prototype.toString.call(new target.Text()), '[object Text]')
|
||||
|
||||
assert.equal(new target.Text('hello').data, 'hello')
|
||||
assert.equal(new target.Text('hello').textContent, 'hello')
|
||||
},
|
||||
},
|
||||
]
|
||||
})
|
87
packages/webapi/test/elements.js
Normal file
87
packages/webapi/test/elements.js
Normal file
|
@ -0,0 +1,87 @@
|
|||
import { assert, test } from '../run/test.setup.js'
|
||||
import { polyfill } from '../mod.js'
|
||||
|
||||
test(() => {
|
||||
return [
|
||||
{
|
||||
name: 'Includes Custom Element functionality',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
assert.equal(Reflect.has(target, 'CustomElementRegistry'), true)
|
||||
assert.equal(Reflect.has(target, 'customElements'), true)
|
||||
assert.equal(Reflect.has(target, 'HTMLElement'), true)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Supports Custom Element creation',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
const CustomElement = class HTMLCustomElement extends target.HTMLElement {}
|
||||
|
||||
target.customElements.define('custom-element', CustomElement)
|
||||
|
||||
assert.equal(target.customElements.get('custom-element'), CustomElement)
|
||||
assert.equal(target.customElements.getName(CustomElement), 'custom-element')
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Supports Custom Elements created from Document',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
assert.equal(target.document.body.localName, 'body')
|
||||
assert.equal(target.document.body.tagName, 'BODY')
|
||||
|
||||
assert.equal(target.document.createElement('custom-element').constructor.name, 'HTMLUnknownElement')
|
||||
|
||||
const CustomElement = class HTMLCustomElement extends target.HTMLElement {}
|
||||
|
||||
target.customElements.define('custom-element', CustomElement)
|
||||
|
||||
assert.equal(target.document.createElement('custom-element').constructor.name, 'HTMLCustomElement')
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Supports Custom Elements with properties',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
const testSymbol = Symbol.for('webapi.test')
|
||||
|
||||
const CustomElement = class HTMLCustomElement extends target.HTMLElement {
|
||||
otherMethod = () => testSymbol
|
||||
|
||||
method() {
|
||||
return this.otherMethod()
|
||||
}
|
||||
|
||||
static method() {
|
||||
return this.otherMethod()
|
||||
}
|
||||
|
||||
static otherMethod() {
|
||||
return testSymbol
|
||||
}
|
||||
}
|
||||
|
||||
target.customElements.define('custom-element', CustomElement)
|
||||
|
||||
assert.equal(CustomElement.method(), testSymbol)
|
||||
|
||||
const customElement = new CustomElement()
|
||||
|
||||
assert.equal(customElement.method(), testSymbol)
|
||||
},
|
||||
},
|
||||
]
|
||||
})
|
140
packages/webapi/test/fetch.js
Normal file
140
packages/webapi/test/fetch.js
Normal file
|
@ -0,0 +1,140 @@
|
|||
import { assert, test } from '../run/test.setup.js'
|
||||
import { polyfill } from '../mod.js'
|
||||
|
||||
test(() => {
|
||||
return [
|
||||
{
|
||||
name: 'Fetch functionality',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
assert.equal(Reflect.has(target, 'fetch'), true)
|
||||
assert.equal(typeof target.fetch, 'function')
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Fetch with https',
|
||||
async test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
const { fetch } = target
|
||||
|
||||
const response = await fetch('https://api.openbrewerydb.org/breweries')
|
||||
|
||||
assert.equal(response.constructor, target.Response)
|
||||
|
||||
const json = await response.json()
|
||||
|
||||
assert.equal(Array.isArray(json), true)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Fetch with file',
|
||||
async test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
const { fetch } = target
|
||||
|
||||
const url = new URL('../package.json', import.meta.url)
|
||||
|
||||
const response = await fetch(url)
|
||||
|
||||
assert.equal(response.constructor, target.Response)
|
||||
|
||||
assert.equal(response.status, 200)
|
||||
assert.equal(response.statusText, '')
|
||||
assert.equal(response.headers.has('date'), true)
|
||||
assert.equal(response.headers.has('content-length'), true)
|
||||
assert.equal(response.headers.has('last-modified'), true)
|
||||
|
||||
const json = await response.json()
|
||||
|
||||
assert.equal(json.name, '@astrojs/webapi')
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Fetch with missing file',
|
||||
async test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
const { fetch } = target
|
||||
|
||||
const url = new URL('../missing.json', import.meta.url)
|
||||
|
||||
const response = await fetch(url)
|
||||
|
||||
assert.equal(response.constructor, target.Response)
|
||||
|
||||
assert.equal(response.status, 404)
|
||||
assert.equal(response.statusText, '')
|
||||
assert.equal(response.headers.has('date'), true)
|
||||
assert.equal(response.headers.has('content-length'), false)
|
||||
assert.equal(response.headers.has('last-modified'), false)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Fetch with (file) Request',
|
||||
async test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
const { Request, fetch } = target
|
||||
|
||||
const request = new Request(new URL('../package.json', import.meta.url))
|
||||
|
||||
const response = await fetch(request)
|
||||
|
||||
assert.equal(response.constructor, target.Response)
|
||||
|
||||
const json = await response.json()
|
||||
|
||||
assert.equal(json.name, '@astrojs/webapi')
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Fetch with relative file',
|
||||
async test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
const { fetch } = target
|
||||
|
||||
const response = await fetch('package.json')
|
||||
|
||||
const json = await response.json()
|
||||
|
||||
assert.equal(json.name, '@astrojs/webapi')
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Fetch with data',
|
||||
async test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
const { fetch } = target
|
||||
|
||||
const jsonURI = `data:application/json,${encodeURIComponent(JSON.stringify({
|
||||
name: '@astrojs/webapi'
|
||||
}))}`
|
||||
|
||||
const response = await fetch(jsonURI)
|
||||
|
||||
const json = await response.json()
|
||||
|
||||
assert.equal(json.name, '@astrojs/webapi')
|
||||
},
|
||||
},
|
||||
]
|
||||
})
|
84
packages/webapi/test/imagedata.js
Normal file
84
packages/webapi/test/imagedata.js
Normal file
|
@ -0,0 +1,84 @@
|
|||
import { assert, test } from '../run/test.setup.js'
|
||||
import { polyfill } from '../mod.js'
|
||||
|
||||
test(() => {
|
||||
return [
|
||||
{
|
||||
name: 'Supports ImageData',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
assert.equal('ImageData' in target, true)
|
||||
assert.equal(typeof target['ImageData'], 'function')
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Supports new (data: Uint8ClampedArray, width: number, height: number): ImageData',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
const w = 640
|
||||
const h = 480
|
||||
const d = new Uint8ClampedArray(w * h * 4)
|
||||
|
||||
const id = new target.ImageData(d, w, h)
|
||||
|
||||
assert.equal(id.data, d)
|
||||
assert.equal(id.width, w)
|
||||
assert.equal(id.height, h)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Supports new (data: Uint8ClampedArray, width: number): ImageData',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
const w = 640
|
||||
const h = 480
|
||||
const d = new Uint8ClampedArray(w * h * 4)
|
||||
|
||||
const id = new target.ImageData(d, w)
|
||||
|
||||
assert.equal(id.data, d)
|
||||
assert.equal(id.width, w)
|
||||
assert.equal(id.height, h)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Supports new (width: number, height: number): ImageData',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
const w = 640
|
||||
const h = 480
|
||||
|
||||
const id = new target.ImageData(w, h)
|
||||
|
||||
assert.equal(id.data.length, w * h * 4)
|
||||
assert.equal(id.width, w)
|
||||
assert.equal(id.height, h)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Supports Object.keys(new ImageData(640, 480))',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
const keys = Object.keys(new target.ImageData(640, 480))
|
||||
|
||||
assert.equal(keys.length, 1)
|
||||
assert.equal(keys[0], 'data')
|
||||
},
|
||||
},
|
||||
]
|
||||
})
|
29
packages/webapi/test/internals.js
Normal file
29
packages/webapi/test/internals.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
import { assert, test } from '../run/test.setup.js'
|
||||
import { polyfill } from '../mod.js'
|
||||
|
||||
test(() => {
|
||||
return [
|
||||
{
|
||||
name: 'Includes polyfill.internals functionality',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target, { exclude: 'window document' })
|
||||
|
||||
const pseudo = { ...target }
|
||||
|
||||
assert.equal(Reflect.has(pseudo, 'document'), false)
|
||||
|
||||
const CustomElement = class extends pseudo.HTMLElement {}
|
||||
|
||||
pseudo.customElements.define('custom-element', CustomElement)
|
||||
|
||||
polyfill.internals(pseudo, 'Document')
|
||||
|
||||
assert.equal(Reflect.has(pseudo, 'document'), true)
|
||||
|
||||
assert.equal(CustomElement.prototype.isPrototypeOf(pseudo.document.createElement('custom-element')), true)
|
||||
},
|
||||
}
|
||||
]
|
||||
})
|
31
packages/webapi/test/media.js
Normal file
31
packages/webapi/test/media.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
import { assert, test } from '../run/test.setup.js'
|
||||
import { polyfill } from '../mod.js'
|
||||
|
||||
test(() => {
|
||||
return [
|
||||
{
|
||||
name: 'Includes MediaQueryList functionality',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
assert.equal(Reflect.has(target, 'MediaQueryList'), true)
|
||||
assert.equal(Reflect.has(target, 'matchMedia'), true)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Supports matchMedia creation',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
const mql = target.matchMedia('(min-width: 640px)')
|
||||
|
||||
assert.equal(mql.matches, false)
|
||||
assert.equal(mql.media, '(min-width: 640px)')
|
||||
},
|
||||
},
|
||||
]
|
||||
})
|
57
packages/webapi/test/offscreencanvas.js
Normal file
57
packages/webapi/test/offscreencanvas.js
Normal file
|
@ -0,0 +1,57 @@
|
|||
import { assert, test } from '../run/test.setup.js'
|
||||
import { polyfill } from '../mod.js'
|
||||
|
||||
test(() => {
|
||||
return [
|
||||
{
|
||||
name: 'Supports OffscreenCanvas',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
assert.equal('OffscreenCanvas' in target, true)
|
||||
assert.equal(typeof target['OffscreenCanvas'], 'function')
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Supports new (width: number, height: number): OffscreenCanvas',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
const w = 640
|
||||
const h = 480
|
||||
|
||||
const canvas = new target.OffscreenCanvas(w, h)
|
||||
|
||||
assert.equal(canvas.width, w)
|
||||
assert.equal(canvas.height, h)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Supports OffscreenCanvas#getContext',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
const w = 640
|
||||
const h = 480
|
||||
|
||||
const canvas = new target.OffscreenCanvas(w, h)
|
||||
|
||||
const context = canvas.getContext('2d')
|
||||
|
||||
assert.equal(context.canvas, canvas)
|
||||
|
||||
const imageData = context.createImageData(w, h)
|
||||
|
||||
assert.equal(imageData.width, w)
|
||||
assert.equal(imageData.height, h)
|
||||
assert.equal(imageData.data.length, w * h * 4)
|
||||
},
|
||||
},
|
||||
]
|
||||
})
|
53
packages/webapi/test/options.js
Normal file
53
packages/webapi/test/options.js
Normal file
|
@ -0,0 +1,53 @@
|
|||
import { assert, test } from '../run/test.setup.js'
|
||||
import { polyfill } from '../mod.js'
|
||||
|
||||
test(() => {
|
||||
return [
|
||||
{
|
||||
name: 'Can exclude HTMLElement+',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target, {
|
||||
exclude: 'HTMLElement+'
|
||||
})
|
||||
|
||||
assert.equal(Reflect.has(target, 'Event'), true)
|
||||
assert.equal(Reflect.has(target, 'EventTarget'), true)
|
||||
assert.equal(Reflect.has(target, 'Element'), true)
|
||||
assert.equal(Reflect.has(target, 'HTMLElement'), false)
|
||||
assert.equal(Reflect.has(target, 'HTMLDivElement'), false)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Can exclude Event+',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target, {
|
||||
exclude: 'Event+'
|
||||
})
|
||||
|
||||
assert.equal(Reflect.has(target, 'Event'), false)
|
||||
assert.equal(Reflect.has(target, 'EventTarget'), false)
|
||||
assert.equal(Reflect.has(target, 'Element'), false)
|
||||
assert.equal(Reflect.has(target, 'HTMLElement'), false)
|
||||
assert.equal(Reflect.has(target, 'HTMLDivElement'), false)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Can exclude document',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target, {
|
||||
exclude: 'document'
|
||||
})
|
||||
|
||||
assert.equal(Reflect.has(target, 'Document'), true)
|
||||
assert.equal(Reflect.has(target, 'HTMLDocument'), true)
|
||||
assert.equal(Reflect.has(target, 'document'), false)
|
||||
},
|
||||
},
|
||||
]
|
||||
})
|
45
packages/webapi/test/storage.js
Normal file
45
packages/webapi/test/storage.js
Normal file
|
@ -0,0 +1,45 @@
|
|||
import { assert, test } from '../run/test.setup.js'
|
||||
import { polyfill } from '../mod.js'
|
||||
|
||||
test(() => {
|
||||
return [
|
||||
{
|
||||
name: 'Includes Storage functionality',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
assert.equal(Reflect.has(target, 'Storage'), true)
|
||||
assert.equal(Reflect.has(target, 'localStorage'), true)
|
||||
assert.equal(typeof target.Storage, 'function')
|
||||
assert.equal(typeof target.localStorage, 'object')
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Supports Storage methods',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
assert.equal(target.localStorage.setItem('hello', 'world'), undefined)
|
||||
assert.equal(target.localStorage.getItem('hello'), 'world')
|
||||
assert.equal(target.localStorage.key(0), 'hello')
|
||||
assert.equal(target.localStorage.key(1), null)
|
||||
assert.equal(target.localStorage.length, 1)
|
||||
assert.equal(target.localStorage.setItem('world', 'hello'), undefined)
|
||||
assert.equal(target.localStorage.key(1), 'world')
|
||||
assert.equal(target.localStorage.key(2), null)
|
||||
assert.equal(target.localStorage.length, 2)
|
||||
assert.equal(target.localStorage.removeItem('hello'), undefined)
|
||||
assert.equal(target.localStorage.key(0), 'world')
|
||||
assert.equal(target.localStorage.key(1), null)
|
||||
assert.equal(target.localStorage.length, 1)
|
||||
assert.equal(target.localStorage.clear(), undefined)
|
||||
assert.equal(target.localStorage.key(0), null)
|
||||
assert.equal(target.localStorage.length, 0)
|
||||
},
|
||||
},
|
||||
]
|
||||
})
|
40
packages/webapi/test/structuredclone.js
Normal file
40
packages/webapi/test/structuredclone.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
import { assert, test } from '../run/test.setup.js'
|
||||
import { polyfill } from '../mod.js'
|
||||
|
||||
test(() => {
|
||||
return [
|
||||
{
|
||||
name: 'Includes structuredClone',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
assert.equal(Reflect.has(target, 'structuredClone'), true)
|
||||
assert.equal(typeof target.structuredClone, 'function')
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Supports structuredClone usage',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
const obj = {
|
||||
foo: "bar",
|
||||
baz: {
|
||||
qux: "quux",
|
||||
},
|
||||
}
|
||||
|
||||
const clone = target.structuredClone(obj)
|
||||
|
||||
assert.notEqual(obj, clone)
|
||||
assert.notEqual(obj.baz, clone.baz)
|
||||
|
||||
assert.equal(obj.baz.qux, clone.baz.qux)
|
||||
},
|
||||
},
|
||||
]
|
||||
})
|
31
packages/webapi/test/urlpattern.js
Normal file
31
packages/webapi/test/urlpattern.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
import { assert, test } from '../run/test.setup.js'
|
||||
import { polyfill } from '../mod.js'
|
||||
|
||||
test(() => {
|
||||
return [
|
||||
{
|
||||
name: 'Includes URLPattern',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
assert.equal(Reflect.has(target, 'URLPattern'), true)
|
||||
assert.equal(typeof target.URLPattern, 'function')
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Supports URLPattern usage',
|
||||
test() {
|
||||
const target = {}
|
||||
|
||||
polyfill(target)
|
||||
|
||||
const pattern = new target.URLPattern({ pathname: '/hello/:name' })
|
||||
const match = pattern.exec('https://example.com/hello/Deno')
|
||||
|
||||
assert.deepEqual(match.pathname.groups, { name: 'Deno' })
|
||||
},
|
||||
},
|
||||
]
|
||||
})
|
15
packages/webapi/tsconfig.json
Normal file
15
packages/webapi/tsconfig.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"include": ["src/*"],
|
||||
"exclude": ["node_modules"],
|
||||
"compilerOptions": {
|
||||
"target": "ES2021",
|
||||
"module": "ES2020",
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"declaration": true,
|
||||
"declarationDir": ".",
|
||||
"strict": true,
|
||||
"sourceMap": true,
|
||||
"declarationMap": true
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
// @ts-check
|
||||
|
||||
import { execa } from 'execa';
|
||||
import { polyfill } from '@astropub/webapi';
|
||||
import { polyfill } from '@astrojs/webapi';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { promises as fs } from 'node:fs';
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// @ts-check
|
||||
|
||||
import { execa } from 'execa';
|
||||
import { polyfill } from '@astropub/webapi';
|
||||
import { polyfill } from '@astrojs/webapi';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { promises as fs } from 'node:fs';
|
||||
|
||||
|
|
88
yarn.lock
88
yarn.lock
|
@ -162,11 +162,6 @@
|
|||
vscode-languageserver-types "^3.16.0"
|
||||
vscode-uri "^3.0.2"
|
||||
|
||||
"@astropub/webapi@^0.10.1", "@astropub/webapi@^0.10.13":
|
||||
version "0.10.14"
|
||||
resolved "https://registry.yarnpkg.com/@astropub/webapi/-/webapi-0.10.14.tgz#f3e118718d1353170ec9ea0adc4a725796717a77"
|
||||
integrity sha512-/o0XdOZLSD3PcZEMm/gRGx5XTFmMzJOCgbBYw//cmHWwpLn6H+9xWBe68r9ToUQ1Ns4GVkfwZlyKVMBNTTXn/g==
|
||||
|
||||
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.16.7":
|
||||
version "7.16.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789"
|
||||
|
@ -1618,6 +1613,13 @@
|
|||
dependencies:
|
||||
tsm "^2.1.4"
|
||||
|
||||
"@rollup/plugin-alias@^3.1.9":
|
||||
version "3.1.9"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/plugin-alias/-/plugin-alias-3.1.9.tgz#a5d267548fe48441f34be8323fb64d1d4a1b3fdf"
|
||||
integrity sha512-QI5fsEvm9bDzt32k39wpOwZhVzRcL5ydcffUHMyLVaVaLeC70I8TJZ17F1z1eMoLu4E/UOcH9BWVkKpIKdrfiw==
|
||||
dependencies:
|
||||
slash "^3.0.0"
|
||||
|
||||
"@rollup/plugin-babel@^5.2.0":
|
||||
version "5.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz#04bc0608f4aa4b2e4b1aebf284344d0f68fda283"
|
||||
|
@ -1626,6 +1628,15 @@
|
|||
"@babel/helper-module-imports" "^7.10.4"
|
||||
"@rollup/pluginutils" "^3.1.0"
|
||||
|
||||
"@rollup/plugin-inject@^4.0.4":
|
||||
version "4.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/plugin-inject/-/plugin-inject-4.0.4.tgz#fbeee66e9a700782c4f65c8b0edbafe58678fbc2"
|
||||
integrity sha512-4pbcU4J/nS+zuHk+c+OL3WtmEQhqxlZ9uqfjQMQDOHOPld7PsCd8k5LWs8h5wjwJN7MgnAn768F2sDxEP4eNFQ==
|
||||
dependencies:
|
||||
"@rollup/pluginutils" "^3.1.0"
|
||||
estree-walker "^2.0.1"
|
||||
magic-string "^0.25.7"
|
||||
|
||||
"@rollup/plugin-node-resolve@^11.2.1":
|
||||
version "11.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz#82aa59397a29cd4e13248b106e6a4a1880362a60"
|
||||
|
@ -1638,6 +1649,18 @@
|
|||
is-module "^1.0.0"
|
||||
resolve "^1.19.0"
|
||||
|
||||
"@rollup/plugin-node-resolve@^13.1.3":
|
||||
version "13.1.3"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.1.3.tgz#2ed277fb3ad98745424c1d2ba152484508a92d79"
|
||||
integrity sha512-BdxNk+LtmElRo5d06MGY4zoepyrXX1tkzX2hrnPEZ53k78GuOMWLqmJDGIIOPwVRIFZrLQOo+Yr6KtCuLIA0AQ==
|
||||
dependencies:
|
||||
"@rollup/pluginutils" "^3.1.0"
|
||||
"@types/resolve" "1.17.1"
|
||||
builtin-modules "^3.1.0"
|
||||
deepmerge "^4.2.2"
|
||||
is-module "^1.0.0"
|
||||
resolve "^1.19.0"
|
||||
|
||||
"@rollup/plugin-replace@^2.4.1":
|
||||
version "2.4.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz#a2d539314fbc77c244858faa523012825068510a"
|
||||
|
@ -1646,6 +1669,14 @@
|
|||
"@rollup/pluginutils" "^3.1.0"
|
||||
magic-string "^0.25.7"
|
||||
|
||||
"@rollup/plugin-typescript@^8.3.0":
|
||||
version "8.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/plugin-typescript/-/plugin-typescript-8.3.1.tgz#b7dc75ed6b4876e260b9e80624fab23bc98e4ac1"
|
||||
integrity sha512-84rExe3ICUBXzqNX48WZV2Jp3OddjTMX97O2Py6D1KJaGSwWp0mDHXj+bCGNJqWHIEKDIT2U0sDjhP4czKi6cA==
|
||||
dependencies:
|
||||
"@rollup/pluginutils" "^3.1.0"
|
||||
resolve "^1.17.0"
|
||||
|
||||
"@rollup/pluginutils@^3.1.0":
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b"
|
||||
|
@ -2075,6 +2106,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44"
|
||||
integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==
|
||||
|
||||
"@ungap/structured-clone@^0.3.4":
|
||||
version "0.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-0.3.4.tgz#f6d804e185591373992781361e4aa5bb81ffba35"
|
||||
integrity sha512-TSVh8CpnwNAsPC5wXcIyh92Bv1gq6E9cNDeeLu7Z4h8V4/qWtXJp7y42qljRkqcpmsve1iozwv1wr+3BNdILCg==
|
||||
|
||||
"@unocss/cli@0.15.6":
|
||||
version "0.15.6"
|
||||
resolved "https://registry.yarnpkg.com/@unocss/cli/-/cli-0.15.6.tgz#68b56455a3a9c9700dcd46a87c5ba40a9dd62111"
|
||||
|
@ -2280,6 +2316,13 @@
|
|||
resolved "https://registry.yarnpkg.com/@webcomponents/template-shadowroot/-/template-shadowroot-0.1.0.tgz#adb3438d0d9a18e8fced08abc253f56b7eadab00"
|
||||
integrity sha512-ry84Vft6xtRBbd4M/ptRodbOLodV5AD15TYhyRghCRgIcJJKmYmJ2v2BaaWxygENwh6Uq3zTfGPmlckKT/GXsQ==
|
||||
|
||||
abort-controller@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392"
|
||||
integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==
|
||||
dependencies:
|
||||
event-target-shim "^5.0.0"
|
||||
|
||||
acorn-jsx@^5.3.1:
|
||||
version "5.3.2"
|
||||
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
|
||||
|
@ -3904,6 +3947,16 @@ etag@~1.8.1:
|
|||
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
|
||||
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
|
||||
|
||||
event-target-shim@^5.0.0:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789"
|
||||
integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==
|
||||
|
||||
event-target-shim@^6.0.2:
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-6.0.2.tgz#ea5348c3618ee8b62ff1d344f01908ee2b8a2b71"
|
||||
integrity sha512-8q3LsZjRezbFZ2PN+uP+Q7pnHUMmAOziU2vA2OwoFaKIXxlxl38IylhSSgUorWu/rf4er67w0ikBqjBFk/pomA==
|
||||
|
||||
execa@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
|
||||
|
@ -6097,6 +6150,15 @@ node-fetch@^2.5.0, node-fetch@^2.6.0, node-fetch@^2.6.7:
|
|||
dependencies:
|
||||
whatwg-url "^5.0.0"
|
||||
|
||||
node-fetch@^3.2.0:
|
||||
version "3.2.2"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.2.2.tgz#16d33fbe32ca7c6ca1ca8ba5dfea1dd885c59f04"
|
||||
integrity sha512-Cwhq1JFIoon15wcIkFzubVNFE5GvXGV82pKf4knXXjvGmn7RJKcypeuqcVNZMGDZsAFWyIRya/anwAJr7TWJ7w==
|
||||
dependencies:
|
||||
data-uri-to-buffer "^4.0.0"
|
||||
fetch-blob "^3.1.4"
|
||||
formdata-polyfill "^4.0.10"
|
||||
|
||||
node-releases@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.2.tgz#7139fe71e2f4f11b47d4d2986aaf8c48699e0c01"
|
||||
|
@ -7039,7 +7101,7 @@ rimraf@^3.0.2:
|
|||
dependencies:
|
||||
glob "^7.1.3"
|
||||
|
||||
rollup-plugin-terser@^7.0.0:
|
||||
rollup-plugin-terser@^7.0.0, rollup-plugin-terser@^7.0.2:
|
||||
version "7.0.2"
|
||||
resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz#e8fbba4869981b2dc35ae7e8a502d5c6c04d324d"
|
||||
integrity sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==
|
||||
|
@ -7056,6 +7118,13 @@ rollup@^2.43.1, rollup@^2.59.0, rollup@^2.60.0, rollup@^2.64.0:
|
|||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
rollup@^2.67.2:
|
||||
version "2.70.0"
|
||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.70.0.tgz#17a92e5938e92a251b962352e904c9f558230ec7"
|
||||
integrity sha512-iEzYw+syFxQ0X9RefVwhr8BA2TNJsTaX8L8dhyeyMECDbmiba+8UQzcu+xZdji0+JQ+s7kouQnw+9Oz5M19XKA==
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
run-parallel@^1.1.9:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
|
||||
|
@ -8263,6 +8332,11 @@ uri-js@^4.2.2:
|
|||
dependencies:
|
||||
punycode "^2.1.0"
|
||||
|
||||
urlpattern-polyfill@^1.0.0-rc5:
|
||||
version "1.0.0-rc5"
|
||||
resolved "https://registry.yarnpkg.com/urlpattern-polyfill/-/urlpattern-polyfill-1.0.0-rc5.tgz#ce23d459d51950fb78939a892621242852e2f2f8"
|
||||
integrity sha512-OxVmQLKMQbDZX1m8Ljuf26rzMUJ7lm3cnBAicqrB0qmo1qb/koH7EXayeHiZdiyc6Z0OnaHETW2JCoVHgTnGGA==
|
||||
|
||||
util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
|
@ -8486,7 +8560,7 @@ web-namespaces@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-2.0.1.tgz#1010ff7c650eccb2592cebeeaf9a1b253fd40692"
|
||||
integrity sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==
|
||||
|
||||
web-streams-polyfill@^3.0.3:
|
||||
web-streams-polyfill@^3.0.3, web-streams-polyfill@^3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz#a6b74026b38e4885869fb5c589e90b95ccfc7965"
|
||||
integrity sha512-EqPmREeOzttaLRm5HS7io98goBgZ7IVz79aDvqjD0kYXLtFZTc0T/U6wHTPKyIjb+MdN7DFIIX6hgdBEpWmfPA==
|
||||
|
|
Loading…
Reference in a new issue