-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 65d1510
Showing
17 changed files
with
625 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
node_modules | ||
package-lock.json | ||
mod.js* | ||
yarn.lock | ||
*.log* | ||
.* | ||
!.gitignore |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# WebAPI | ||
|
||
**WebAPI** lets you use Web APIs in Node. | ||
|
||
```shell | ||
npm install @astropub/webapi | ||
``` | ||
|
||
|
||
|
||
## Usage | ||
|
||
**WebAPI** lets you use Web APIs in Node. | ||
|
||
As individual exports. | ||
|
||
```js | ||
import { AbortController, Blob, Event, EventTarget, File, fetch, Response } from '@astropub/webapi' | ||
``` | ||
|
||
Polyfilling `globalThis`. | ||
|
||
```js | ||
import { polyfill } from '@astropub/webapi' | ||
|
||
polyfill(globalThis) | ||
``` | ||
|
||
--- | ||
|
||
|
||
|
||
## License | ||
|
||
Licensed under the CC0-1.0 License. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
import { rollup } from 'rollup' | ||
import { nodeResolve } from '@rollup/plugin-node-resolve' | ||
import { default as MagicString } from 'magic-string' | ||
import { readFile as nodeReadFile } from 'node:fs/promises' | ||
import { default as inject } from '@rollup/plugin-inject' | ||
|
||
const readFileCache = Object.create(null) | ||
|
||
const readFile = (/** @type {string} */ id) => readFileCache[id] || (readFileCache[id] = nodeReadFile(id, 'utf8')) | ||
|
||
const pathToDOMException = new URL('./src/lib/DOMException.js', import.meta.url).pathname | ||
|
||
const plugins = [ | ||
nodeResolve({ | ||
dedupe: [ | ||
'net', | ||
'node:net' | ||
] | ||
}), | ||
inject({ | ||
'AbortController': [ 'abort-controller/dist/abort-controller.mjs', 'AbortController' ], | ||
'ReadableStream': [ 'web-streams-polyfill/dist/ponyfill.es6.mjs', 'ReadableStream' ], | ||
'globalThis.ReadableStream': [ 'web-streams-polyfill/dist/ponyfill.es6.mjs', 'ReadableStream' ], | ||
'DOMException': [pathToDOMException, 'DOMException'], | ||
}), | ||
{ | ||
async load(id) { | ||
const pathToEsm = id | ||
const pathToMap = `${pathToEsm}.map` | ||
|
||
const code = await readFile(pathToEsm, 'utf8') | ||
|
||
const indexes = [] | ||
|
||
const replacements = [ | ||
[ /(^|\n)import\s+[^']+'node:(fs|path|worker_threads)'/g, `` ], | ||
|
||
[ /\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, `` ], | ||
|
||
[ /\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, `` ], | ||
|
||
[ / 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, `` ], | ||
] | ||
|
||
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.js', | ||
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() | ||
} | ||
} | ||
|
||
build() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
{ | ||
"name": "@astropub/webapi", | ||
"description": "Use Web APIs in Node", | ||
"version": "0.1.0", | ||
"type": "module", | ||
"exports": { | ||
".": "./mod.js" | ||
}, | ||
"files": [ | ||
"mod.js", | ||
"mod.js.map" | ||
], | ||
"keywords": [ | ||
"astro", | ||
"api", | ||
"cancelAnimationFrame", | ||
"clearImmediate", | ||
"clearInterval", | ||
"fetch", | ||
"requestAnimationFrame", | ||
"setImmediate", | ||
"setInterval", | ||
"web" | ||
], | ||
"license": "CC0-1.0", | ||
"repository": "astro-community/webapi", | ||
"author": "Jonathan Neal <[email protected]>", | ||
"bugs": "https://github.com/astro-community/webapi/issues", | ||
"homepage": "https://github.com/astro-community/webapi#readme", | ||
"devDependencies": { | ||
"@rollup/plugin-inject": "^4.0.3", | ||
"@rollup/plugin-node-resolve": "^13.1.1", | ||
"@rollup/plugin-typescript": "^8.3.0", | ||
"@skypack/package-check": "0.2.2", | ||
"abort-controller": "^3.0.0", | ||
"event-target-shim": "^6.0.2", | ||
"fetch-blob": "^3.1.3", | ||
"formdata-polyfill": "^4.0.10", | ||
"magic-string": "^0.25.7", | ||
"node-fetch": "^3.1.0", | ||
"rollup": "^2.61.1", | ||
"rollup-plugin-terser": "^7.0.2", | ||
"web-streams-polyfill": "^3.2.0" | ||
}, | ||
"scripts": { | ||
"build": "node build.js", | ||
"release": "npm publish --access public", | ||
"test": "package-check" | ||
}, | ||
"prettier": { | ||
"semi": false, | ||
"singleQuote": true, | ||
"trailingComma": "es5", | ||
"useTabs": true, | ||
"overrides": [ | ||
{ | ||
"files": [ | ||
".stackblitzrc", | ||
"*.json" | ||
], | ||
"options": { | ||
"useTabs": false | ||
} | ||
} | ||
] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export declare var requestAnimationFrame: { | ||
(callback: (...args: any[]) => any): number | ||
} | ||
|
||
export declare var cancelAnimationFrame: { | ||
(requestId: number): void | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// @ts-check | ||
|
||
import { setTimeout as nodeSetTimeout, clearTimeout as nodeClearTimeout } from 'node:timers' | ||
import { __function_bind, __performance_now } from './utils.js' | ||
|
||
const INTERNAL = { tick: 0, pool: new Map } | ||
|
||
/** @type {<TArgs extends any[], TFunc extends (...args: TArgs) => any>(callback: TFunc) => number} */ | ||
export function requestAnimationFrame(callback) { | ||
if (!INTERNAL.pool.size) { | ||
nodeSetTimeout(() => { | ||
const next = __performance_now() | ||
|
||
for (const func of INTERNAL.pool.values()) { | ||
func(next) | ||
} | ||
|
||
INTERNAL.pool.clear() | ||
}, 16) | ||
} | ||
|
||
const func = __function_bind(callback, undefined) | ||
const tick = ++INTERNAL.tick | ||
|
||
INTERNAL.pool.set(tick, func) | ||
|
||
return tick | ||
} | ||
|
||
/** @type {{ (timeoutId: number): void }} */ | ||
export function cancelAnimationFrame(requestId) { | ||
const timeout = INTERNAL.pool.get(requestId) | ||
|
||
if (timeout) { | ||
nodeClearTimeout(timeout) | ||
|
||
INTERNAL.pool.delete(requestId) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import type { Event } from './Event' | ||
|
||
interface CustomEvent<TEventType extends string = string, TEventInit extends EventInit = EventInit> extends Event {} | ||
|
||
export declare var CustomEvent: CustomEvent | ||
|
||
interface EventInit { | ||
bubbles?: boolean | ||
cancelable?: boolean | ||
composed?: boolean | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
// @ts-check | ||
|
||
import { Event } from 'event-target-shim' | ||
|
||
class CustomEvent extends Event {} | ||
|
||
export { CustomEvent } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// @ts-check | ||
|
||
export class DOMException extends Error { | ||
constructor(message = '', name = 'Error') { | ||
super(message) | ||
|
||
this.code = 0 | ||
this.name = name | ||
} | ||
|
||
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/** Evaluates an expression after a number of milliseconds, returning a numeric id for the timer. */ | ||
export declare var setTimeout: { | ||
<TArgs extends any[]>(callback: (...args: TArgs) => void, delay?: number, ...args: TArgs): number | ||
} | ||
|
||
/** Clears a timer set with a given id. */ | ||
export declare var clearTimeout: { | ||
(timeout: number): void | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// @ts-check | ||
|
||
import { setTimeout as nodeSetTimeout, clearTimeout as nodeClearTimeout } from 'node:timers' | ||
import { __function_bind } from './utils.js' | ||
|
||
const INTERNAL = { tick: 0, pool: new Map } | ||
|
||
/** @type {<TArgs extends any[], TFunc extends (...args: TArgs) => any>(callback: TFunc, delay?: number, ...args: TArgs) => number} */ | ||
export function setTimeout(callback, delay = 0, ...args) { | ||
const func = __function_bind(callback, globalThis) | ||
const tick = ++INTERNAL.tick | ||
const timeout = nodeSetTimeout(func, delay, ...args) | ||
|
||
INTERNAL.pool.set(tick, timeout) | ||
|
||
return tick | ||
} | ||
|
||
/** @type {{ (timeoutId: number): void }} */ | ||
export function clearTimeout(timeoutId) { | ||
const timeout = INTERNAL.pool.get(timeoutId) | ||
|
||
if (timeout) { | ||
nodeClearTimeout(timeout) | ||
|
||
INTERNAL.pool.delete(timeoutId) | ||
} | ||
} |
Oops, something went wrong.