-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
move more reusable logic into toolkit package (#2401)
* deprecate unused property * move async helper functions to toolkit * move format functions to toolkit * add changeset * more elaborate comment
- Loading branch information
1 parent
cb39d02
commit 60a744b
Showing
7 changed files
with
181 additions
and
136 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,6 @@ | ||
--- | ||
'graphiql': patch | ||
'@graphiql/toolkit': patch | ||
--- | ||
|
||
move async helper functions and formatting functions over into the @graphiql/toolkit package |
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,5 @@ | ||
--- | ||
'@graphiql/toolkit': patch | ||
--- | ||
|
||
deprecate the unused `shouldPersistHeaders` property from fetcher options to be removed in the next major version |
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,89 @@ | ||
import { | ||
FetcherResult, | ||
FetcherReturnType, | ||
Observable, | ||
} from '../create-fetcher'; | ||
|
||
// Duck-type promise detection. | ||
export function isPromise<T>(value: Promise<T> | any): value is Promise<T> { | ||
return typeof value === 'object' && typeof value.then === 'function'; | ||
} | ||
|
||
// Duck-type Observable.take(1).toPromise() | ||
function observableToPromise<T>(observable: Observable<T>): Promise<T> { | ||
return new Promise((resolve, reject) => { | ||
const subscription = observable.subscribe({ | ||
next: v => { | ||
resolve(v); | ||
subscription.unsubscribe(); | ||
}, | ||
error: reject, | ||
complete: () => { | ||
reject(new Error('no value resolved')); | ||
}, | ||
}); | ||
}); | ||
} | ||
|
||
// Duck-type observable detection. | ||
export function isObservable<T>(value: any): value is Observable<T> { | ||
return ( | ||
typeof value === 'object' && | ||
'subscribe' in value && | ||
typeof value.subscribe === 'function' | ||
); | ||
} | ||
|
||
export function isAsyncIterable( | ||
input: unknown, | ||
): input is AsyncIterable<unknown> { | ||
return ( | ||
typeof input === 'object' && | ||
input !== null && | ||
// Some browsers still don't have Symbol.asyncIterator implemented (iOS Safari) | ||
// That means every custom AsyncIterable must be built using a AsyncGeneratorFunction (async function * () {}) | ||
((input as any)[Symbol.toStringTag] === 'AsyncGenerator' || | ||
Symbol.asyncIterator in input) | ||
); | ||
} | ||
|
||
function asyncIterableToPromise<T>( | ||
input: AsyncIterable<T> | AsyncIterableIterator<T>, | ||
): Promise<T> { | ||
return new Promise((resolve, reject) => { | ||
// Also support AsyncGenerator on Safari iOS. | ||
// As mentioned in the isAsyncIterable function there is no Symbol.asyncIterator available | ||
// so every AsyncIterable must be implemented using AsyncGenerator. | ||
const iteratorReturn = ('return' in input | ||
? input | ||
: input[Symbol.asyncIterator]() | ||
).return?.bind(input); | ||
const iteratorNext = ('next' in input | ||
? input | ||
: input[Symbol.asyncIterator]() | ||
).next.bind(input); | ||
|
||
iteratorNext() | ||
.then(result => { | ||
resolve(result.value); | ||
// ensure cleanup | ||
iteratorReturn?.(); | ||
}) | ||
.catch(err => { | ||
reject(err); | ||
}); | ||
}); | ||
} | ||
|
||
export function fetcherReturnToPromise( | ||
fetcherResult: FetcherReturnType, | ||
): Promise<FetcherResult> { | ||
return Promise.resolve(fetcherResult).then(result => { | ||
if (isAsyncIterable(result)) { | ||
return asyncIterableToPromise(result); | ||
} else if (isObservable(result)) { | ||
return observableToPromise(result); | ||
} | ||
return result; | ||
}); | ||
} |
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
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,48 @@ | ||
import { GraphQLError, GraphQLFormattedError } from 'graphql'; | ||
|
||
function stringify(obj: unknown): string { | ||
return JSON.stringify(obj, null, 2); | ||
} | ||
|
||
const formatSingleError = (error: Error): Error => ({ | ||
...error, | ||
// Raise these details even if they're non-enumerable | ||
message: error.message, | ||
stack: error.stack, | ||
}); | ||
|
||
type InputError = Error | GraphQLError | string; | ||
|
||
function handleSingleError( | ||
error: InputError, | ||
): GraphQLFormattedError | Error | string { | ||
if (error instanceof GraphQLError) { | ||
return error.toString(); | ||
} | ||
if (error instanceof Error) { | ||
return formatSingleError(error); | ||
} | ||
return error; | ||
} | ||
|
||
type GenericError = | ||
| Error | ||
| readonly Error[] | ||
| string | ||
| readonly string[] | ||
| GraphQLError | ||
| readonly GraphQLError[]; | ||
|
||
export function formatError(error: GenericError): string { | ||
if (Array.isArray(error)) { | ||
return stringify({ | ||
errors: error.map((e: InputError) => handleSingleError(e)), | ||
}); | ||
} | ||
// @ts-ignore | ||
return stringify({ errors: handleSingleError(error) }); | ||
} | ||
|
||
export function formatResult(result: any): string { | ||
return stringify(result); | ||
} |
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 |
---|---|---|
@@ -1,2 +1,4 @@ | ||
export * from './async-helpers'; | ||
export * from './create-fetcher'; | ||
export * from './format'; | ||
// TODO: move the most useful utilities from graphiql to here |
Oops, something went wrong.