Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/@whatwg-node_cookie-store-2102-dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@whatwg-node/cookie-store": patch
---
dependencies updates:
- Added dependency [`@whatwg-node/promise-helpers@^0.0.0` ↗︎](https://www.npmjs.com/package/@whatwg-node/promise-helpers/v/0.0.0) (to `dependencies`)
5 changes: 5 additions & 0 deletions .changeset/@whatwg-node_disposablestack-2102-dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@whatwg-node/disposablestack": patch
---
dependencies updates:
- Added dependency [`@whatwg-node/promise-helpers@^0.0.0` ↗︎](https://www.npmjs.com/package/@whatwg-node/promise-helpers/v/0.0.0) (to `dependencies`)
5 changes: 5 additions & 0 deletions .changeset/@whatwg-node_node-fetch-2102-dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@whatwg-node/node-fetch": patch
---
dependencies updates:
- Added dependency [`@whatwg-node/promise-helpers@^0.0.0` ↗︎](https://www.npmjs.com/package/@whatwg-node/promise-helpers/v/0.0.0) (to `dependencies`)
5 changes: 5 additions & 0 deletions .changeset/@whatwg-node_server-2102-dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@whatwg-node/server": patch
---
dependencies updates:
- Added dependency [`@whatwg-node/promise-helpers@^0.0.0` ↗︎](https://www.npmjs.com/package/@whatwg-node/promise-helpers/v/0.0.0) (to `dependencies`)
5 changes: 5 additions & 0 deletions .changeset/green-rocks-bow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@whatwg-node/promise-helpers': patch
---

New promise helpers
3 changes: 2 additions & 1 deletion deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"fetchache": "./packages/fetchache/src/index.ts",
"@whatwg-node/node-fetch": "./packages/node-fetch/src/index.ts",
"@whatwg-node/server": "./packages/server/src/index.ts",
"@whatwg-node/server-plugin-cookies": "./packages/server-plugin-cookies/src/index.ts"
"@whatwg-node/server-plugin-cookies": "./packages/server-plugin-cookies/src/index.ts",
"@whatwg-node/promise-helpers": "./packages/promise-helpers/src/index.ts"
}
}
1 change: 1 addition & 0 deletions packages/cookie-store/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
},
"typings": "dist/typings/index.d.ts",
"dependencies": {
"@whatwg-node/promise-helpers": "^0.0.0",
"tslib": "^2.6.3"
},
"publishConfig": {
Expand Down
15 changes: 8 additions & 7 deletions packages/cookie-store/src/CookieStore.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { fakePromise } from '@whatwg-node/promise-helpers';
import { CookieChangeEvent } from './CookieChangeEvent.js';
import { parse } from './parse.js';
import {
Expand All @@ -21,15 +22,15 @@ export class CookieStore extends EventTarget {
this.cookieMap = parse(cookieString);
}

async get(
get(
init?: CookieStoreGetOptions['name'] | CookieStoreGetOptions | undefined,
): Promise<Cookie | undefined> {
if (init == null) {
throw new TypeError('CookieStoreGetOptions must not be empty');
} else if (init instanceof Object && !Object.keys(init).length) {
throw new TypeError('CookieStoreGetOptions must not be empty');
}
return (await this.getAll(init))[0];
return this.getAll(init).then(cookies => cookies[0]);
}

async set(init: CookieListItem | string, possibleValue?: string): Promise<void> {
Expand Down Expand Up @@ -95,21 +96,21 @@ export class CookieStore extends EventTarget {
}
}

async getAll(init?: CookieStoreGetOptions['name'] | CookieStoreGetOptions): Promise<Cookie[]> {
getAll(init?: CookieStoreGetOptions['name'] | CookieStoreGetOptions): Promise<Cookie[]> {
const cookies = Array.from(this.cookieMap.values());
if (init == null || Object.keys(init).length === 0) {
return cookies;
return fakePromise(cookies);
}
let name: string | undefined;
if (typeof init === 'string') {
name = init as string;
} else {
name = init.name;
}
return cookies.filter(cookie => cookie.name === name);
return fakePromise(cookies.filter(cookie => cookie.name === name));
}

async delete(init: CookieStoreDeleteOptions['name'] | CookieStoreDeleteOptions): Promise<void> {
delete(init: CookieStoreDeleteOptions['name'] | CookieStoreDeleteOptions): Promise<void> {
const item: CookieListItem = {
name: '',
value: '',
Expand All @@ -128,6 +129,6 @@ export class CookieStore extends EventTarget {

item.expires = 0;

await this.set(item);
return this.set(item);
}
}
1 change: 1 addition & 0 deletions packages/disposablestack/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
},
"typings": "dist/typings/index.d.ts",
"dependencies": {
"@whatwg-node/promise-helpers": "^0.0.0",
"tslib": "^2.6.3"
},
"publishConfig": {
Expand Down
34 changes: 14 additions & 20 deletions packages/disposablestack/src/AsyncDisposableStack.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { handleMaybePromiseLike, MaybePromiseLike } from '@whatwg-node/promise-helpers';
import { PonyfillSuppressedError } from './SupressedError.js';
import { DisposableSymbols } from './symbols.js';
import { isAsyncDisposable, isSyncDisposable, MaybePromise } from './utils.js';
import { isAsyncDisposable, isSyncDisposable } from './utils.js';

const SuppressedError = globalThis.SuppressedError || PonyfillSuppressedError;

export class PonyfillAsyncDisposableStack implements AsyncDisposableStack {
private callbacks: (() => MaybePromise<void>)[] = [];
private callbacks: (() => MaybePromiseLike<void>)[] = [];
get disposed(): boolean {
return this.callbacks.length === 0;
}
Expand All @@ -19,14 +20,14 @@ export class PonyfillAsyncDisposableStack implements AsyncDisposableStack {
return value;
}

adopt<T>(value: T, onDisposeAsync: (value: T) => MaybePromise<void>): T {
adopt<T>(value: T, onDisposeAsync: (value: T) => MaybePromiseLike<void>): T {
if (onDisposeAsync) {
this.callbacks.push(() => onDisposeAsync(value));
}
return value;
}

defer(onDisposeAsync: () => MaybePromise<void>): void {
defer(onDisposeAsync: () => MaybePromiseLike<void>): void {
if (onDisposeAsync) {
this.callbacks.push(onDisposeAsync);
}
Expand All @@ -45,24 +46,17 @@ export class PonyfillAsyncDisposableStack implements AsyncDisposableStack {

private _error?: Error | undefined;

private _iterateCallbacks(): MaybePromise<void> {
private _iterateCallbacks(): MaybePromiseLike<void> {
const cb = this.callbacks.pop();
if (cb) {
try {
const res$ = cb();
if (res$?.then) {
return res$.then(
() => this._iterateCallbacks(),
error => {
this._error = this._error ? new SuppressedError(error, this._error) : error;
return this._iterateCallbacks();
},
);
}
} catch (error: any) {
this._error = this._error ? new SuppressedError(error, this._error) : error;
}
return this._iterateCallbacks();
return handleMaybePromiseLike(
cb,
() => this._iterateCallbacks(),
error => {
this._error = this._error ? new SuppressedError(error, this._error) : error;
return this._iterateCallbacks();
},
);
}
}

Expand Down
2 changes: 0 additions & 2 deletions packages/disposablestack/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,3 @@ export function isSyncDisposable(obj: any): obj is Disposable {
export function isAsyncDisposable(obj: any): obj is AsyncDisposable {
return obj?.[DisposableSymbols.asyncDispose] != null;
}

export type MaybePromise<T> = T | PromiseLike<T>;
3 changes: 2 additions & 1 deletion packages/disposablestack/tests/disposablestack.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { describe, expect, it, jest } from '@jest/globals';
import { MaybePromise } from '@whatwg-node/promise-helpers';
import { AsyncDisposableStack, DisposableStack, DisposableSymbols, patchSymbols } from '../src';

function createTestCases<
Expand All @@ -11,7 +12,7 @@ function createTestCases<
): Record<
string,
{
run(stack: TStack, disposeFn: jest.Mock): void | Promise<void>;
run(stack: TStack, disposeFn: jest.Mock): MaybePromise<void>;
check(disposeFn: jest.Mock): void;
}
> {
Expand Down
1 change: 1 addition & 0 deletions packages/node-fetch/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"typings": "dist/typings/index.d.ts",
"dependencies": {
"@whatwg-node/disposablestack": "^0.0.5",
"@whatwg-node/promise-helpers": "^0.0.0",
"busboy": "^1.6.0",
"tslib": "^2.6.3"
},
Expand Down
8 changes: 2 additions & 6 deletions packages/node-fetch/src/fetchCurl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,10 @@ import { Buffer } from 'node:buffer';
import { PassThrough, Readable } from 'node:stream';
import { pipeline } from 'node:stream/promises';
import { rootCertificates } from 'node:tls';
import { createDeferredPromise } from '@whatwg-node/promise-helpers';
import { PonyfillRequest } from './Request.js';
import { PonyfillResponse } from './Response.js';
import {
createDeferredPromise,
defaultHeadersSerializer,
isNodeReadable,
shouldRedirect,
} from './utils.js';
import { defaultHeadersSerializer, isNodeReadable, shouldRedirect } from './utils.js';

export function fetchCurl<TResponseJSON = any, TRequestJSON = any>(
fetchRequest: PonyfillRequest<TRequestJSON>,
Expand Down
62 changes: 1 addition & 61 deletions packages/node-fetch/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,43 +25,7 @@ export function defaultHeadersSerializer(
return headerArray;
}

function isPromise<T>(val: T | Promise<T>): val is Promise<T> {
return (val as any)?.then != null;
}

export function fakePromise<T>(value: T): Promise<T> {
if (isPromise(value)) {
return value;
}
// Write a fake promise to avoid the promise constructor
// being called with `new Promise` in the browser.
return {
then(resolve: (value: T) => any) {
if (resolve) {
const callbackResult = resolve(value);
if (isPromise(callbackResult)) {
return callbackResult;
}
return fakePromise(callbackResult);
}
return this;
},
catch() {
return this;
},
finally(cb) {
if (cb) {
const callbackResult = cb();
if (isPromise(callbackResult)) {
return callbackResult.then(() => value);
}
return fakePromise(value);
}
return this;
},
[Symbol.toStringTag]: 'Promise',
};
}
export { fakePromise } from '@whatwg-node/promise-helpers';

export function isArrayBufferView(obj: any): obj is ArrayBufferView {
return obj != null && obj.buffer != null && obj.byteLength != null && obj.byteOffset != null;
Expand All @@ -71,30 +35,6 @@ export function isNodeReadable(obj: any): obj is Readable {
return obj != null && obj.pipe != null;
}

export interface DeferredPromise<T = void> {
promise: Promise<T>;
resolve: (value: T) => void;
reject: (reason: any) => void;
}

export function createDeferredPromise<T = void>(): DeferredPromise<T> {
let resolveFn: (value: T) => void;
let rejectFn: (reason: any) => void;
const promise = new Promise<T>(function deferredPromiseExecutor(resolve, reject) {
resolveFn = resolve;
rejectFn = reject;
});
return {
promise,
get resolve() {
return resolveFn;
},
get reject() {
return rejectFn;
},
};
}

export function isIterable(value: any): value is Iterable<unknown> {
return value?.[Symbol.iterator] != null;
}
Expand Down
50 changes: 50 additions & 0 deletions packages/promise-helpers/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"name": "@whatwg-node/promise-helpers",
"version": "0.0.0",
"type": "module",
"description": "Promise helpers",
"repository": {
"type": "git",
"url": "ardatan/whatwg-node",
"directory": "packages/promise-helpers"
},
"author": "Arda TANRIKULU <[email protected]>",
"license": "MIT",
"engines": {
"node": ">=18.0.0"
},
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"exports": {
".": {
"require": {
"types": "./dist/typings/index.d.cts",
"default": "./dist/cjs/index.js"
},
"import": {
"types": "./dist/typings/index.d.ts",
"default": "./dist/esm/index.js"
},
"default": {
"types": "./dist/typings/index.d.ts",
"default": "./dist/esm/index.js"
}
},
"./package.json": "./package.json"
},
"typings": "dist/typings/index.d.ts",
"dependencies": {
"tslib": "^2.6.3"
},
"publishConfig": {
"directory": "dist",
"access": "public"
},
"sideEffects": false,
"buildOptions": {
"input": "./src/index.ts"
},
"typescript": {
"definition": "dist/typings/index.d.ts"
}
}
Loading
Loading