···11+---
22+name: 'RFC'
33+about: Propose an enhancement / feature and start a discussion
44+title: 'RFC: Your Proposal'
55+labels: "future \U0001F52E"
66+---
77+88+<!--
99+ 🚨 RFCs are for proposed changes (not bugs or questions)
1010+ Specifically they are whenever you'd like to see new features
1111+ being added, or enable new use-cases.
1212+1313+ Please open a Bug Report for issues/bugs, and use GitHub Discussions
1414+ or the Discord channel for questions instead.
1515+-->
1616+1717+## Summary
1818+1919+<!--
2020+ Describe in a couple of words *what* you're proposing.
2121+ If relevant, include *why* this should be addressed now.
2222+ The problem should be clearly stated and the solution
2323+ should be summarised.
2424+-->
2525+2626+## Proposed Solution
2727+2828+<!--
2929+ Explain the solution you're proposing in detail.
3030+ *How* will this change be implemented, and how does it work?
3131+-->
3232+3333+## Requirements
3434+3535+<!--
3636+ This section is *optional*.
3737+ But if your proposed solution has multiple ways
3838+ of being implemented, you don't want to state how
3939+ it may be implemented, or you don't know yet how
4040+ it will be implemented, then:
4141+ *List* what the implementation needs to achieve to fulfil this RFC;
4242+-->
+46
.github/ISSUE_TEMPLATE/bug_report.yaml
···11+name: "\U0001F41E Bug report"
22+description: Report an issue with graphql.web
33+labels: []
44+body:
55+ - type: markdown
66+ attributes:
77+ value: |
88+ Thanks for taking the time to fill out this bug report!
99+ - type: markdown
1010+ attributes:
1111+ value: |
1212+ Thanks for taking the time to fill out this bug report!
1313+ - type: textarea
1414+ id: bug-description
1515+ attributes:
1616+ label: Describe the bug
1717+ description: Please describe your bug clearly and concisely.
1818+ placeholder: Bug description
1919+ validations:
2020+ required: true
2121+ - type: input
2222+ id: reproduction
2323+ attributes:
2424+ label: Reproduction
2525+ description: Please provide a reproduction link, e.g. to a sandbox
2626+ placeholder: Reproduction
2727+ validations:
2828+ required: true
2929+ - type: textarea
3030+ id: version
3131+ attributes:
3232+ label: Package version
3333+ description: The versions of the relevant urql packages you are using
3434+ placeholder: "wonka@6.2.5"
3535+ validations:
3636+ required: true
3737+ - type: checkboxes
3838+ id: checkboxes
3939+ attributes:
4040+ label: Validations
4141+ description: Before submitting the issue, please make sure you do the following
4242+ options:
4343+ - label: I can confirm that this is a bug report, and not a feature request, RFC, question, or discussion, for which GitHub Discussions should be used
4444+ required: true
4545+ - label: Follow our [Code of Conduct](https://github.com/0no-co/graphql.web/blob/main/CODE_OF_CONDUCT.md)
4646+ required: true
+8
.github/ISSUE_TEMPLATE/config.yml
···11+blank_issues_enabled: true
22+contact_links:
33+ - name: Ask a question
44+ url: https://github.com/@0no-co/wonka/discussions
55+ about: Ask questions and discuss with other community members
66+ - name: Join the Discord
77+ url: https://discord.gg/3EYgqrYJFS
88+ about: Chat with maintainers and other community members
+22
.github/PULL_REQUEST_TEMPLATE.md
···11+<!--
22+ Thanks for opening a pull request! We appreciate your dedication and help!
33+ Before submitting your pull request, please make sure to read our CONTRIBUTING guide.
44+55+ The best contribution is always a PR, but please make sure to open an issue or discuss
66+ your changes first, if you’re looking to submit a larger PR.
77+88+ If this PR is already related to an issue, please reference it like so:
99+ Resolves #123
1010+-->
1111+1212+## Summary
1313+1414+<!-- What's the motivation of this change? What does it solve? -->
1515+1616+## Set of changes
1717+1818+<!--
1919+ Roughly list the changes you've made and which packages are affected.
2020+ Leave some notes on what may be noteworthy files you've changed.
2121+ And lastly, please let us know if you think this is a breaking change.
2222+-->
···11# wonka
2233+## 6.3.5
44+55+### Patch Changes
66+77+- Exclude `sourcesContent` from published sourcemaps
88+ Submitted by [@kitten](https://github.com/kitten) (See [`68e608f`](https://github.com/0no-co/wonka/commit/68e608f46244e82d41c952ecfa1d7f0096e168f6))
99+1010+## 6.3.4
1111+1212+### Patch Changes
1313+1414+- Add missing `Symbol.observable` global declaration back to typings
1515+ Submitted by [@kitten](https://github.com/kitten) (See [#168](https://github.com/0no-co/wonka/pull/168))
1616+1717+## 6.3.3
1818+1919+### Patch Changes
2020+2121+- Improve compatibility of `fromAsyncIterable` and `toAsyncIterable`. The `toAsyncIterable` will now output an object that's both an `AsyncIterator` and an `AsyncIterable`. Both helpers will now use a polyfill for `Symbol.asyncIterator` to improve compatibility with the Hermes engine and Babel transpilation
2222+ Submitted by [@kitten](https://github.com/kitten) (See [#165](https://github.com/0no-co/wonka/pull/165))
2323+2424+## 6.3.2
2525+2626+### Patch Changes
2727+2828+- Publish with npm provenance
2929+ Submitted by [@kitten](https://github.com/kitten) (See [#161](https://github.com/0no-co/wonka/pull/161))
3030+3131+## 6.3.1
3232+3333+### Patch Changes
3434+3535+- ⚠️ Fix missing `declare` keyword on internal ambient enums
3636+ Submitted by [@kitten](https://github.com/kitten) (See [#159](https://github.com/0no-co/wonka/pull/159))
3737+3838+## 6.3.0
3939+4040+### Minor Changes
4141+4242+- Add `addOne` argument to `takeWhile`, allowing an additional value to be issued
4343+ Submitted by [@kitten](https://github.com/kitten) (See [#156](https://github.com/0no-co/wonka/pull/156))
4444+4545+### Patch Changes
4646+4747+- Convert `Push<T>` and `Start<T>` signals to `{ tag, 0: value }` objects, which are sufficiently backwards compatible and result in slightly faster execution in v8
4848+ Submitted by [@kitten](https://github.com/kitten) (See [#155](https://github.com/0no-co/wonka/pull/155))
4949+5050+## 6.2.6
5151+5252+### Patch Changes
5353+5454+- ⚠️ Fix missing source contents in Wonka sourcemaps
5555+ Submitted by [@kitten](https://github.com/kitten) (See [`56d9708`](https://github.com/0no-co/wonka/commit/56d970861424fddd403262bf85d7e1e3572b15e2))
5656+- ⚠️ Fix internal `SignalKind` and `TalkbackKind` enums not compiling away
5757+ Submitted by [@kitten](https://github.com/kitten) (See [#154](https://github.com/0no-co/wonka/pull/154))
5858+5959+## 6.2.5
6060+6161+### Patch Changes
6262+6363+- Make `closed: boolean` on `ObservableSubscription`s a required field to comply with the Observable proposal's type spec
6464+ Submitted by [@naporin0624](https://github.com/naporin0624) (See [#151](https://github.com/0no-co/wonka/pull/151))
6565+6666+## 6.2.4
6767+6868+### Patch Changes
6969+7070+- Add missing overload definition for `filter`, which allows types to be narrowed, e.g. by specifying a type predicate return type
7171+ Submitted by [@kitten](https://github.com/kitten) (See [#149](https://github.com/0no-co/wonka/pull/149))
7272+7373+## 6.2.3
7474+7575+### Patch Changes
7676+7777+- ⚠️ Fix overload of `pipe` type not being applied in bundled `d.ts` file, by [@kitten](https://github.com/kitten) (See [#144](https://github.com/0no-co/wonka/pull/144))
7878+379## 6.2.2
480581### Patch Changes
+163
CONTRIBUTING.md
···11+# Development
22+33+Thanks for contributing! We want to ensure that `wonka` evolves
44+and fulfills its idea of being a tiny & capable push & pull stream library!
55+66+## How to contribute?
77+88+We follow fairly standard but lenient rules around pull requests and issues.
99+Please pick a title that describes your change briefly, optionally in the imperative
1010+mood if possible.
1111+1212+If you have an idea for a feature or want to fix a bug, consider opening an issue
1313+first. We're also happy to discuss and help you open a PR and get your changes
1414+in!
1515+1616+- If you have a question, try [creating a GitHub Discussions thread.](https://github.com/0no-co/wonka/discussions/new/choose)
1717+- If you think you've found a bug, [open a new issue.](https://github.com/0no-co/wonka/issues/new)
1818+- or, if you found a bug you'd like to fix, [open a PR.](https://github.com/0no-co/wonka/compare)
1919+- If you'd like to propose a change [open an RFC issue.](https://github.com/0no-co/wonka/issues/new?labels=future+%F0%9F%94%AE&template=RFC.md&title=RFC%3A+Your+Proposal) You can read more about the RFC process [below](#how-do-i-propose-changes).
2020+2121+### What are the issue conventions?
2222+2323+There are **no strict conventions**, but we do have two templates in place that will fit most
2424+issues, since questions and other discussion start on GitHub Discussions. The bug template is fairly
2525+standard and the rule of thumb is to try to explain **what you expected** and **what you got
2626+instead.** Following this makes it very clear whether it's a known behavior, an unexpected issue,
2727+or an undocumented quirk.
2828+2929+### How do I propose changes?
3030+3131+We follow an **RFC proposal process**. This allows anyone to propose a new feature or a change, and
3232+allows us to communicate our current planned features or changes, so any technical discussion,
3333+progress, or upcoming changes are always **documented transparently.** You can [find the RFC
3434+template](https://github.com/0no-co/wonka/issues/new/choose) in our issue creator.
3535+3636+### What are the PR conventions?
3737+3838+This also comes with **no strict conventions**. We only ask you to follow the PR template we have
3939+in place more strictly here than the templates for issues, since it asks you to list a summary
4040+(maybe even with a short explanation) and a list of technical changes.
4141+4242+If you're **resolving** an issue please don't forget to add `Resolve #123` to the description so that
4343+it's automatically linked, so that there's no ambiguity and which issue is being addressed (if any)
4444+4545+You'll find that a comment by the "Changeset" bot may pop up. If you don't know what a **changeset**
4646+is and why it's asking you to document your changes, read on at ["How do I document a change for the
4747+changelog"](#how-do-i-document-a-change-for-the-changelog)
4848+4949+We also typically **name** our PRs with a slightly descriptive title, e.g. `feat: Title`.
5050+5151+## How do I set up the project?
5252+5353+Luckily it's not hard to get started. You can install dependencie
5454+[using `pnpm`](https://pnpm.io/installation#using-corepack).
5555+Please don't use `npm` or `yarn` to respect the lockfile.
5656+5757+```sh
5858+pnpm install
5959+```
6060+6161+There are multiple commands you can run in the root folder to test your changes:
6262+6363+```sh
6464+# TypeScript checks:
6565+pnpm run check
6666+6767+# Linting (prettier & eslint):
6868+pnpm run lint
6969+7070+# Unit Tests:
7171+pnpm run test
7272+7373+# Builds:
7474+pnpm run build
7575+```
7676+7777+## How do I test my changes?
7878+7979+It's always good practice to run the tests when making changes. If you're unsure which packages
8080+may be affected by your new tests or changes you may run `pnpm test` in the root of
8181+the repository.
8282+8383+If your editor is not set up with type checks you may also want to run `pnpm run check` on your
8484+changes.
8585+8686+Additionally you can head to any example in the `examples/` folder
8787+and run them. There you'll also need to install their dependencies as they're isolated projects,
8888+without a lockfile and without linking to packages in the monorepos.
8989+All examples are started using the `package.json`'s `start` script.
9090+9191+## How do I lint my code?
9292+9393+We ensure consistency in this codebase using `eslint` and `prettier`.
9494+They are run on a `precommit` hook, so if something's off they'll try
9595+to automatically fix up your code, or display an error.
9696+9797+If you have them set up in your editor, even better!
9898+9999+## How do I document a change for the changelog?
100100+101101+This project uses [changesets](https://github.com/atlassian/changesets). This means that for
102102+every PR there must be documentation for what has been changed and which package is affected.
103103+104104+You can document a change by running `changeset`, which will ask you which packages
105105+have changed and whether the change is major/minor/patch. It will then ask you to write
106106+a change entry as markdown.
107107+108108+```sh
109109+# In the root of the urql repository call:
110110+pnpm changeset
111111+```
112112+113113+This will create a new "changeset file" in the `.changeset` folder, which you should commit and
114114+push, so that it's added to your PR.
115115+This will eventually end up in the package's `CHANGELOG.md` file when we do a release.
116116+117117+You won't need to add a changeset if you're simply making "non-visible" changes to the docs or other
118118+files that aren't published to the npm registry.
119119+120120+[Read more about adding a `changeset` here.](https://github.com/atlassian/changesets/blob/master/docs/adding-a-changeset.md#i-am-in-a-multi-package-repository-a-mono-repo)
121121+122122+## How do I release new versions of our packages?
123123+124124+Hold up, that's **automated**! Since we use `changeset` to document our changes, which determines what
125125+goes into the changelog and what kind of version bump a change should make, you can also use the
126126+tool to check what's currently posed to change after a release batch using: `pnpm changeset status`.
127127+128128+We have a [GitHub Actions workflow](./.github/workflow/release.yml) which is triggered whenever new
129129+changes are merged. It will always open a **"Version Packages" PR** which is kept up-to-date. This PR
130130+documents all changes that are made and will show in its description what all new changelogs are
131131+going to contain for their new entries.
132132+133133+Once a "Version Packages" PR is approved by a contributor and merged, the action will automatically
134134+take care of creating the release, publishing all updated packages to the npm registry, and creating
135135+appropriate tags on GitHub too.
136136+137137+This process is automated, but the changelog should be checked for errors.
138138+139139+As to **when** to merge the automated PR and publish? Maybe not after every change. Typically there
140140+are two release batches: hotfixes and release batches. We expect that a hotfix for a single package
141141+should go out as quickly as possible if it negatively affects users. For **release batches**
142142+however, it's common to assume that if one change is made to a package that more will follow in the
143143+same week. So waiting for **a day or two** when other changes are expected will make sense to keep the
144144+fatigue as low as possible for downstream maintainers.
145145+146146+## How do I upgrade all dependencies?
147147+148148+It may be a good idea to keep all dependencies on this repository **up-to-date** every now and
149149+then. Typically we do this by running `pnpm update --interactive --latest` and checking one-by-one
150150+which dependencies will need to be bumped. In case of any security issues it may make sense to
151151+just run `pnpm update [package]`.
152152+153153+While this is rare with `pnpm`, upgrading some transitive dependencies may accidentally duplicate
154154+them if two packages depend on different compatible version ranges. This can be fixed by running:
155155+156156+```sh
157157+pnpm dedupe
158158+pnpm install
159159+```
160160+161161+It's common to then **create a PR** (with a changeset documenting the packages that need to reflect
162162+new changes if any `dependencies` have changed) with the name of
163163+"(chore) - Upgrade direct and transitive dependencies" or something similar.
+1-1
LICENSE.md
···11MIT License
2233-Copyright (c) 2018–2022 0no.co
33+Copyright (c) 0no.co
4455Permission is hereby granted, free of charge, to any person obtaining a copy
66of this software and associated documentation files (the "Software"), to deal
···2424 * @internal
2525 */
2626export function start<T>(talkback: TalkbackFn): Start<T> {
2727- const box: any = [talkback];
2828- box.tag = SignalKind.Start;
2929- return box;
2727+ return {
2828+ tag: SignalKind.Start,
2929+ 0: talkback,
3030+ } as Start<T>;
3031}
31323233/** Wraps the passed value in a {@link Push | Push signal}.
3334 * @internal
3435 */
3536export function push<T>(value: T): Push<T> {
3636- const box: any = [value];
3737- box.tag = SignalKind.Push;
3838- return box;
3737+ return {
3838+ tag: SignalKind.Push,
3939+ 0: value,
4040+ } as Push<T>;
3941}
4242+4343+/** Returns the well-known symbol specifying the default AsyncIterator.
4444+ * @internal
4545+ */
4646+export const asyncIteratorSymbol = (): typeof Symbol.asyncIterator =>
4747+ (typeof Symbol === 'function' && Symbol.asyncIterator) || ('@@asyncIterator' as any);
4848+4949+/** Returns the well-known symbol specifying the default ES Observable.
5050+ * @privateRemarks
5151+ * This symbol is used to mark an object as a default ES Observable. By the specification, an object
5252+ * that abides by the default Observable implementation must carry a method set to this well-known
5353+ * symbol that returns the Observable implementation. It's common for this object to be an
5454+ * Observable itself and return itself on this method.
5555+ *
5656+ * @see {@link https://github.com/0no-co/wonka/issues/122} for notes on the intercompatibility
5757+ * between Observable implementations.
5858+ *
5959+ * @internal
6060+ */
6161+export const observableSymbol = (): typeof Symbol.observable =>
6262+ (typeof Symbol === 'function' && Symbol.observable) || ('@@observable' as any);
+5-18
src/observable.ts
···11import { Source, SignalKind, TalkbackKind } from './types';
22-import { push, start, talkbackPlaceholder } from './helpers';
22+import { push, start, talkbackPlaceholder, observableSymbol } from './helpers';
3344+// NOTE: This must be placed in an exported file for `rollup-plugin-dts`
55+// to include it in output typings files
46declare global {
57 interface SymbolConstructor {
68 readonly observable: symbol;
···2628 *
2729 * @readonly
2830 */
2929- closed?: boolean;
3131+ closed: boolean;
3032 /** Cancels the subscription.
3133 * @remarks
3234 * This cancels the ongoing subscription and the {@link ObservableObserver}'s callbacks will
···7678 * @see {@link ObservableObserver} for the callbacks in an object that are called as Observables
7779 * issue events.
7880 */
7979- subscribe(observer: ObservableObserver<T>): ObservableSubscription;
8181+ subscribe(observer: ObservableObserver<T>): { unsubscribe(): void };
80828183 /** The well-known symbol specifying the default ES Observable for an object. */
8284 [Symbol.observable]?(): Observable<T>;
···117119 /** The well-known symbol specifying the default ES Observable for an object. */
118120 [Symbol.observable](): Observable<T>;
119121}
120120-121121-/** Returns the well-known symbol specifying the default ES Observable.
122122- * @privateRemarks
123123- * This symbol is used to mark an object as a default ES Observable. By the specification, an object
124124- * that abides by the default Observable implementation must carry a method set to this well-known
125125- * symbol that returns the Observable implementation. It's common for this object to be an
126126- * Observable itself and return itself on this method.
127127- *
128128- * @see {@link https://github.com/0no-co/wonka/issues/122} for notes on the intercompatibility
129129- * between Observable implementations.
130130- *
131131- * @internal
132132- */
133133-const observableSymbol = (): typeof Symbol.observable =>
134134- Symbol.observable || ('@@observable' as any);
135122136123/** Converts an ES Observable to a {@link Source}.
137124 * @param input - The {@link ObservableLike} object that will be converted.
+13-4
src/operators.ts
···11-import { Source, Sink, Operator, SignalKind, TalkbackKind, TalkbackFn } from './types';
11+import { Push, Source, Sink, Operator, SignalKind, TalkbackKind, TalkbackFn } from './types';
22import { push, start, talkbackPlaceholder } from './helpers';
33import { fromArray } from './sources';
44···268268 * );
269269 * ```
270270 */
271271-export function filter<T>(predicate: (value: T) => boolean): Operator<T, T> {
271271+function filter<In, Out extends In>(predicate: (value: In) => value is Out): Operator<In, Out>;
272272+function filter<T>(predicate: (value: T) => boolean): Operator<T, T>;
273273+function filter<In, Out>(predicate: (value: In) => boolean): Operator<In, Out> {
272274 return source => sink => {
273275 let talkback = talkbackPlaceholder;
274276 source(signal => {
···280282 } else if (!predicate(signal[0])) {
281283 talkback(TalkbackKind.Pull);
282284 } else {
283283- sink(signal);
285285+ sink(signal as Push<any>);
284286 }
285287 });
286288 };
287289}
290290+291291+export { filter };
288292289293/** Maps emitted values using the passed mapping function.
290294 *
···12501254/** Takes values from an input Source until a predicate function returns `false`.
12511255 *
12521256 * @param predicate - A function returning a boolean per value.
12571257+ * @param addOne - Lets an additional input value pass on.
12531258 * @returns An {@link Operator}.
12541259 *
12551260 * @remarks
12561261 * `takeWhile` will issue all values as normal from the input {@link Source} until the `predicate`
12571262 * function returns `false`. When the `predicate` function returns `false`, the current value is
12581263 * omitted and the {@link Source} is closed.
12641264+ *
12651265+ * If `addOne` is set to `true`, the value for which the `predicate` first returned `false` is
12661266+ * issued and passed on as well instead of being omitted.
12591267 *
12601268 * @example
12611269 * ```ts
···12681276 * );
12691277 * ```
12701278 */
12711271-export function takeWhile<T>(predicate: (value: T) => boolean): Operator<T, T> {
12791279+export function takeWhile<T>(predicate: (value: T) => boolean, addOne?: boolean): Operator<T, T> {
12721280 return source => sink => {
12731281 let talkback = talkbackPlaceholder;
12741282 let ended = false;
···12831291 sink(signal);
12841292 } else if (!predicate(signal[0])) {
12851293 ended = true;
12941294+ if (addOne) sink(signal);
12861295 sink(SignalKind.End);
12871296 talkback(TalkbackKind.Close);
12881297 } else {
+2-2
src/pipe.ts
···176176 ): R;
177177}
178178179179-function pipe(...args: Function[]): any {
179179+const pipe: pipe = (...args: Function[]): any => {
180180 let x = args[0];
181181 for (let i = 1, l = args.length; i < l; i++) x = args[i](x);
182182 return x;
183183-}
183183+};
184184185185export { pipe };
+51-40
src/sinks.ts
···11-import { Source, Subscription, TalkbackKind, SignalKind } from './types';
22-import { talkbackPlaceholder } from './helpers';
11+import { Source, Subscription, TalkbackKind, SignalKind, SourceIterable } from './types';
22+import { talkbackPlaceholder, asyncIteratorSymbol } from './helpers';
3344/** Creates a subscription to a given source and invokes a `subscriber` callback for each value.
55 * @param subscriber - A callback function called for each issued value.
···124124 * }
125125 * ```
126126 */
127127-export const toAsyncIterable = <T>(source: Source<T>): AsyncIterable<T> => ({
128128- [Symbol.asyncIterator](): AsyncIterator<T> {
129129- const buffer: T[] = [];
127127+export const toAsyncIterable = <T>(source: Source<T>): SourceIterable<T> => {
128128+ const buffer: T[] = [];
130129131131- let ended = false;
132132- let talkback = talkbackPlaceholder;
133133- let next: ((value: IteratorResult<T>) => void) | void;
130130+ let ended = false;
131131+ let started = false;
132132+ let pulled = false;
133133+ let talkback = talkbackPlaceholder;
134134+ let next: ((value: IteratorResult<T>) => void) | void;
134135135135- source(signal => {
136136- if (ended) {
137137- /*noop*/
138138- } else if (signal === SignalKind.End) {
139139- if (next) next = next(doneResult);
140140- ended = true;
141141- } else if (signal.tag === SignalKind.Start) {
142142- (talkback = signal[0])(TalkbackKind.Pull);
143143- } else if (next) {
144144- next = next({ value: signal[0], done: false });
145145- } else {
146146- buffer.push(signal[0]);
136136+ return {
137137+ async next(): Promise<IteratorResult<T>> {
138138+ if (!started) {
139139+ started = true;
140140+ source(signal => {
141141+ if (ended) {
142142+ /*noop*/
143143+ } else if (signal === SignalKind.End) {
144144+ if (next) next = next(doneResult);
145145+ ended = true;
146146+ } else if (signal.tag === SignalKind.Start) {
147147+ pulled = true;
148148+ (talkback = signal[0])(TalkbackKind.Pull);
149149+ } else {
150150+ pulled = false;
151151+ if (next) {
152152+ next = next({ value: signal[0], done: false });
153153+ } else {
154154+ buffer.push(signal[0]);
155155+ }
156156+ }
157157+ });
147158 }
148148- });
149159150150- return {
151151- async next(): Promise<IteratorResult<T>> {
152152- if (ended && !buffer.length) {
153153- return doneResult;
154154- } else if (!ended && buffer.length <= 1) {
155155- talkback(TalkbackKind.Pull);
156156- }
160160+ if (ended && !buffer.length) {
161161+ return doneResult;
162162+ } else if (!ended && !pulled && buffer.length <= 1) {
163163+ pulled = true;
164164+ talkback(TalkbackKind.Pull);
165165+ }
157166158158- return buffer.length
159159- ? { value: buffer.shift()!, done: false }
160160- : new Promise(resolve => (next = resolve));
161161- },
162162- async return(): Promise<IteratorReturnResult<void>> {
163163- if (!ended) next = talkback(TalkbackKind.Close);
164164- ended = true;
165165- return doneResult;
166166- },
167167- };
168168- },
169169-});
167167+ return buffer.length
168168+ ? { value: buffer.shift()!, done: false }
169169+ : new Promise(resolve => (next = resolve));
170170+ },
171171+ async return(): Promise<IteratorReturnResult<void>> {
172172+ if (!ended) next = talkback(TalkbackKind.Close);
173173+ ended = true;
174174+ return doneResult;
175175+ },
176176+ [asyncIteratorSymbol()](): SourceIterable<T> {
177177+ return this;
178178+ },
179179+ };
180180+};
170181171182/** Subscribes to a given source and collects all synchronous values into an array.
172183 * @param source - A {@link Source}.
+12-4
src/sources.ts
···11import { Source, Sink, SignalKind, TalkbackKind, Observer, Subject, TeardownFn } from './types';
22-import { push, start, talkbackPlaceholder, teardownPlaceholder } from './helpers';
22+import {
33+ push,
44+ start,
55+ talkbackPlaceholder,
66+ teardownPlaceholder,
77+ asyncIteratorSymbol,
88+} from './helpers';
39import { share } from './operators';
410511/** Helper creating a Source from a factory function when it's subscribed to.
···4551 * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_async_iterator_and_async_iterable_protocols}
4652 * for the JS Iterable protocol.
4753 */
4848-export function fromAsyncIterable<T>(iterable: AsyncIterable<T>): Source<T> {
5454+export function fromAsyncIterable<T>(iterable: AsyncIterable<T> | AsyncIterator<T>): Source<T> {
4955 return sink => {
5050- const iterator = iterable[Symbol.asyncIterator]();
5656+ const iterator: AsyncIterator<T> =
5757+ (iterable[asyncIteratorSymbol()] && iterable[asyncIteratorSymbol()]()) || iterable;
5858+5159 let ended = false;
5260 let looping = false;
5361 let pulled = false;
···110118 * for the JS Iterable protocol.
111119 */
112120export function fromIterable<T>(iterable: Iterable<T> | AsyncIterable<T>): Source<T> {
113113- if (iterable[Symbol.asyncIterator]) return fromAsyncIterable(iterable as AsyncIterable<T>);
121121+ if (iterable[asyncIteratorSymbol()]) return fromAsyncIterable(iterable as AsyncIterable<T>);
114122 return sink => {
115123 const iterator = iterable[Symbol.iterator]();
116124 let ended = false;
+207
src/types.d.ts
···11+/**
22+ * Talkback signal that sends instructions from a sink to a source.
33+ *
44+ * @remarks
55+ * This signal is issued via {@link TalkbackFn | talkback functions} that a {@link Sink} receives via
66+ * the {@link Start} signal, to tell a {@link Source} to either send a new value (pulling) or stop
77+ * sending values altogether (cancellation).
88+ */
99+export declare enum TalkbackKind {
1010+ /** Instructs the {@link Source} to send the next value. */
1111+ Pull = 0,
1212+ /** Instructs the {@link Source} to stop sending values and cancels it. */
1313+ Close = 1,
1414+}
1515+1616+/**
1717+ * Talkback callback that sends instructions to a source.
1818+ *
1919+ * @remarks
2020+ * This function sends a {@link TalkbackKind} signal to the source to instruct it to send a new value
2121+ * (pulling) or to be cancelled and stop sending values altogether.
2222+ */
2323+export type TalkbackFn = (signal: TalkbackKind) => void;
2424+2525+/**
2626+ * Callback that is called when a source is cancelled.
2727+ *
2828+ * @remarks
2929+ * This is used, in particular, in the {@link make | make Source} and is a returned function that is
3030+ * called when the {@link TalkbackKind.Close} signal is received by the source.
3131+ */
3232+export type TeardownFn = () => void;
3333+3434+/**
3535+ * Tag enum that is used to on signals that are sent from a source to a sink.
3636+ *
3737+ * @remarks
3838+ * This signal is issued by a {@link Source} and {@link Sink | Sinks} are called with it. The signals
3939+ * carrying values ({@link Start} and {@link Push}) are sent as a unary `[T]` tuple tagged with
4040+ * {@link Tag}. The {@link End} signal carries no value and is sent as a raw `0` value.
4141+ * @see {@link Start} for the data structure of the start signal.
4242+ * @see {@link Push} for the data structure of the push signal, carrying values.
4343+ */
4444+export declare enum SignalKind {
4545+ /**
4646+ * Informs the {@link Sink} that it's being called by a {@link Source}.
4747+ *
4848+ * @remarks
4949+ * This starts the stream of values and carries a {@link TalkbackFn | talkback function} with it
5050+ * that is used by the {@link Sink} to communicate back to the {@link Source}.
5151+ * @see {@link Start} for the data structure of the signal.
5252+ */
5353+ Start = 0,
5454+ /**
5555+ * Informs the {@link Sink} of a new values that's incoming from the {@link Source}.
5656+ *
5757+ * @remarks
5858+ * This informs the {@link Sink} of new values that are sent by the {@link Source}.
5959+ * @see {@link Push} for the data structure of the signal.
6060+ */
6161+ Push = 1,
6262+ /**
6363+ * Informs the {@link Sink} that the {@link Source} has ended and that it won't send more values.
6464+ *
6565+ * @remarks
6666+ * This signal signifies that the stream has stopped and that no more values are expected. Some
6767+ * sources don't have a set end or limit on how many values will be sent. This signal is not sent
6868+ * when the {@link Source} is cancelled with a {@link TalkbackKind.Close | Close talkback signal}.
6969+ */
7070+ End = 0,
7171+}
7272+7373+/**
7474+ * The tag property that's put on unary `[T]` tuple to turn them into signals carrying values.
7575+ *
7676+ * @internal
7777+ */
7878+export interface Tag<T> {
7979+ tag: T;
8080+}
8181+8282+/**
8383+ * Indicates the start of a stream to a {@link Sink}.
8484+ *
8585+ * @remarks
8686+ * This signal is sent from a {@link Source} to a {@link Sink} at the start of a stream to inform it
8787+ * that values can be pulled and/or will be sent. This signal carries a
8888+ * {@link TalkbackFn | talkback function} that is used by the {@link Sink} to communicate back to the
8989+ * {@link Source} as a callback. The talkback accepts {@link TalkbackKind.Pull | Pull} and
9090+ * {@link TalkbackKind.Close | Close} signals.
9191+ */
9292+export type Start<_T> = Tag<SignalKind.Start> & [TalkbackFn];
9393+9494+/**
9595+ * Sends a new value to a {@link Sink}.
9696+ *
9797+ * @remarks
9898+ * This signal is sent from a {@link Source} to a {@link Sink} to send a new value to it. This is
9999+ * essentially the signal that wraps new values coming in, like an event. Values are carried on
100100+ * unary tuples and can be accessed using `signal[0]`.
101101+ */
102102+export type Push<T> = Tag<SignalKind.Push> & [T];
103103+104104+/**
105105+ * Signals are sent from {@link Source | Sources} to {@link Sink | Sinks} to inform them of changes.
106106+ *
107107+ * @remarks
108108+ * A {@link Source}, when consumed, sends a sequence of events to {@link Sink | Sinks}. In order, a
109109+ * {@link SignalKind.Start | Start} signal will always be sent first, followed optionally by one or
110110+ * more {@link SignalKind.Push | Push signals}, carrying values and representing the stream. A
111111+ * {@link Source} will send the {@link SignalKind.End | End signal} when it runs out of values. The
112112+ * End signal will be omitted if the Source is cancelled by a
113113+ * {@link TalkbackKind.Close | Close signal}, sent back from the {@link Sink}.
114114+ * @see {@link SignalKind} for the kinds signals sent by {@link Source | Sources}.
115115+ * @see {@link Start} for the data structure of the start signal.
116116+ * @see {@link Push} for the data structure of the push signal.
117117+ */
118118+export type Signal<T> = Start<T> | Push<T> | SignalKind.End;
119119+120120+/**
121121+ * Callback function that is called by a {@link Source} with {@link Signal | Signals}.
122122+ *
123123+ * @remarks
124124+ * A Sink is a function that is called repeatedly with signals from a {@link Source}. It represents
125125+ * the receiver of the stream of signals/events coming from a {@link Source}.
126126+ * @see {@link Signal} for the data structure of signals.
127127+ */
128128+export type Sink<T> = (signal: Signal<T>) => void;
129129+130130+/** Factory function that calls {@link Sink | Sinks} with {@link Signal | Signals} when invoked.
131131+ * @remarks
132132+ * A Source is a factory function that when invoked with a {@link Sink}, calls it with
133133+ * {@link Signal | Signals} to create a stream of events, informing it of new values and the
134134+ * potential end of the stream of values. The first signal a Source sends is always a
135135+ * {@link Start | Start signal} that sends a talkback function to the {@link Sink}, so it may request
136136+ * new values or cancel the source.
137137+ *
138138+ * @see {@link Signal} for the data structure of signals.
139139+ * @see {@link Sink} for the data structure of sinks.
140140+ */
141141+export type Source<T> = (sink: Sink<T>) => void;
142142+143143+/** Transform function that accepts a {@link Source} and returns a new one.
144144+ * @remarks
145145+ * Wonka comes with several helper operators that transform a given {@link Source} into a new one,
146146+ * potentially changing its outputs, or the outputs' timing. An "operator" in Wonka typically
147147+ * accepts arguments and then returns this kind of function, so they can be chained and composed.
148148+ *
149149+ * @see {@link pipe | `pipe`} for the helper used to compose operators.
150150+ */
151151+export type Operator<In, Out> = (a: Source<In>) => Source<Out>;
152152+153153+/** Type utility to determine the type of a {@link Source}. */
154154+export type TypeOfSource<T> = T extends Source<infer U> ? U : never;
155155+156156+/** Subscription object that can be used to cancel a {@link Source}.
157157+ * @see {@link subscribe | subscribe sink} for a helper that returns this structure.
158158+ */
159159+export interface Subscription {
160160+ /**
161161+ * Cancels a {@link Source} to stop the subscription from receiving new values.
162162+ *
163163+ * @see {@link TalkbackKind.Close | Close signal} This uses the {@link TalkbackFn | talkback function} to send a {@link TalkbackKind.Close | Close signal}
164164+ * to the subscribed-to {@link Source} to stop it from sending new values. This cleans up the subscription
165165+ * and ends it immediately.
166166+ */
167167+ unsubscribe(): void;
168168+}
169169+170170+/** An Observer represents sending signals manually to a {@link Sink}.
171171+ * @remarks
172172+ * The Observer is used whenever a utility allows for signals to be sent manually as a {@link Source}
173173+ * would send them.
174174+ *
175175+ * @see {@link make | `make` source} for a helper that uses this structure.
176176+ */
177177+export interface Observer<T> {
178178+ /** Sends a new value to the receiving Sink.
179179+ * @remarks
180180+ * This creates a {@link Push | Push signal} that is sent to a {@link Sink}.
181181+ */
182182+ next(value: T): void;
183183+ /** Indicates to the receiving Sink that no more values will be sent.
184184+ * @remarks
185185+ * This creates an {@link SignalKind.End | End signal} that is sent to a {@link Sink}. The Observer
186186+ * will accept no more values via {@link Observer.next | `next` calls} once this method has been
187187+ * invoked.
188188+ */
189189+ complete(): void;
190190+}
191191+192192+/** Subjects combine a {@link Source} with the {@link Observer} that is used to send values on said Source.
193193+ * @remarks
194194+ * A Subject is used whenever an event hub-like structure is needed, as it both provides the
195195+ * {@link Observer}'s methods to send signals, as well as the `source` to receive said signals.
196196+ *
197197+ * @see {@link makeSubject | `makeSubject` source} for a helper that creates this structure.
198198+ */
199199+export interface Subject<T> extends Observer<T> {
200200+ /** The {@link Source} that issues the signals as the {@link Observer} methods are called. */
201201+ source: Source<T>;
202202+}
203203+204204+/** Async Iterable/Iterator after having converted a {@link Source}.
205205+ * @see {@link toAsyncIterable} for a helper that creates this structure.
206206+ */
207207+export interface SourceIterable<T> extends AsyncIterator<T>, AsyncIterable<T> {}
···11-/**
22- * Talkback signal that sends instructions from a sink to a source.
33- *
44- * @remarks
55- * This signal is issued via {@link TalkbackFn | talkback functions} that a {@link Sink} receives via
66- * the {@link Start} signal, to tell a {@link Source} to either send a new value (pulling) or stop
77- * sending values altogether (cancellation).
88- */
99-export const enum TalkbackKind {
1010- /** Instructs the {@link Source} to send the next value. */
1111- Pull = 0,
1212- /** Instructs the {@link Source} to stop sending values and cancels it. */
1313- Close = 1,
1414-}
1515-1616-/**
1717- * Talkback callback that sends instructions to a source.
1818- *
1919- * @remarks
2020- * This function sends a {@link TalkbackKind} signal to the source to instruct it to send a new value
2121- * (pulling) or to be cancelled and stop sending values altogether.
2222- */
2323-export type TalkbackFn = (signal: TalkbackKind) => void;
2424-2525-/**
2626- * Callback that is called when a source is cancelled.
2727- *
2828- * @remarks
2929- * This is used, in particular, in the {@link make | make Source} and is a returned function that is
3030- * called when the {@link TalkbackKind.Close} signal is received by the source.
3131- */
3232-export type TeardownFn = () => void;
3333-3434-/**
3535- * Tag enum that is used to on signals that are sent from a source to a sink.
3636- *
3737- * @remarks
3838- * This signal is issued by a {@link Source} and {@link Sink | Sinks} are called with it. The signals
3939- * carrying values ({@link Start} and {@link Push}) are sent as a unary `[T]` tuple tagged with
4040- * {@link Tag}. The {@link End} signal carries no value and is sent as a raw `0` value.
4141- * @see {@link Start} for the data structure of the start signal.
4242- * @see {@link Push} for the data structure of the push signal, carrying values.
4343- */
4444-export const enum SignalKind {
4545- /**
4646- * Informs the {@link Sink} that it's being called by a {@link Source}.
4747- *
4848- * @remarks
4949- * This starts the stream of values and carries a {@link TalkbackFn | talkback function} with it
5050- * that is used by the {@link Sink} to communicate back to the {@link Source}.
5151- * @see {@link Start} for the data structure of the signal.
5252- */
5353- Start = 0,
5454- /**
5555- * Informs the {@link Sink} of a new values that's incoming from the {@link Source}.
5656- *
5757- * @remarks
5858- * This informs the {@link Sink} of new values that are sent by the {@link Source}.
5959- * @see {@link Push} for the data structure of the signal.
6060- */
6161- Push = 1,
6262- /**
6363- * Informs the {@link Sink} that the {@link Source} has ended and that it won't send more values.
6464- *
6565- * @remarks
6666- * This signal signifies that the stream has stopped and that no more values are expected. Some
6767- * sources don't have a set end or limit on how many values will be sent. This signal is not sent
6868- * when the {@link Source} is cancelled with a {@link TalkbackKind.Close | Close talkback signal}.
6969- */
7070- End = 0,
7171-}
7272-7373-/**
7474- * The tag property that's put on unary `[T]` tuple to turn them into signals carrying values.
7575- *
7676- * @internal
7777- */
7878-export interface Tag<T> {
7979- tag: T;
8080-}
8181-8282-/**
8383- * Indicates the start of a stream to a {@link Sink}.
8484- *
8585- * @remarks
8686- * This signal is sent from a {@link Source} to a {@link Sink} at the start of a stream to inform it
8787- * that values can be pulled and/or will be sent. This signal carries a
8888- * {@link TalkbackFn | talkback function} that is used by the {@link Sink} to communicate back to the
8989- * {@link Source} as a callback. The talkback accepts {@link TalkbackKind.Pull | Pull} and
9090- * {@link TalkbackKind.Close | Close} signals.
9191- */
9292-export type Start<_T> = Tag<SignalKind.Start> & [TalkbackFn];
9393-9494-/**
9595- * Sends a new value to a {@link Sink}.
9696- *
9797- * @remarks
9898- * This signal is sent from a {@link Source} to a {@link Sink} to send a new value to it. This is
9999- * essentially the signal that wraps new values coming in, like an event. Values are carried on
100100- * unary tuples and can be accessed using `signal[0]`.
101101- */
102102-export type Push<T> = Tag<SignalKind.Push> & [T];
103103-104104-/**
105105- * Signals are sent from {@link Source | Sources} to {@link Sink | Sinks} to inform them of changes.
106106- *
107107- * @remarks
108108- * A {@link Source}, when consumed, sends a sequence of events to {@link Sink | Sinks}. In order, a
109109- * {@link SignalKind.Start | Start} signal will always be sent first, followed optionally by one or
110110- * more {@link SignalKind.Push | Push signals}, carrying values and representing the stream. A
111111- * {@link Source} will send the {@link SignalKind.End | End signal} when it runs out of values. The
112112- * End signal will be omitted if the Source is cancelled by a
113113- * {@link TalkbackKind.Close | Close signal}, sent back from the {@link Sink}.
114114- * @see {@link SignalKind} for the kinds signals sent by {@link Source | Sources}.
115115- * @see {@link Start} for the data structure of the start signal.
116116- * @see {@link Push} for the data structure of the push signal.
117117- */
118118-export type Signal<T> = Start<T> | Push<T> | SignalKind.End;
119119-120120-/**
121121- * Callback function that is called by a {@link Source} with {@link Signal | Signals}.
122122- *
123123- * @remarks
124124- * A Sink is a function that is called repeatedly with signals from a {@link Source}. It represents
125125- * the receiver of the stream of signals/events coming from a {@link Source}.
126126- * @see {@link Signal} for the data structure of signals.
127127- */
128128-export type Sink<T> = (signal: Signal<T>) => void;
129129-130130-/** Factory function that calls {@link Sink | Sinks} with {@link Signal | Signals} when invoked.
131131- * @remarks
132132- * A Source is a factory function that when invoked with a {@link Sink}, calls it with
133133- * {@link Signal | Signals} to create a stream of events, informing it of new values and the
134134- * potential end of the stream of values. The first signal a Source sends is always a
135135- * {@link Start | Start signal} that sends a talkback function to the {@link Sink}, so it may request
136136- * new values or cancel the source.
137137- *
138138- * @see {@link Signal} for the data structure of signals.
139139- * @see {@link Sink} for the data structure of sinks.
140140- */
141141-export type Source<T> = (sink: Sink<T>) => void;
142142-143143-/** Transform function that accepts a {@link Source} and returns a new one.
144144- * @remarks
145145- * Wonka comes with several helper operators that transform a given {@link Source} into a new one,
146146- * potentially changing its outputs, or the outputs' timing. An "operator" in Wonka typically
147147- * accepts arguments and then returns this kind of function, so they can be chained and composed.
148148- *
149149- * @see {@link pipe | `pipe`} for the helper used to compose operators.
150150- */
151151-export type Operator<In, Out> = (a: Source<In>) => Source<Out>;
152152-153153-/** Type utility to determine the type of a {@link Source}. */
154154-export type TypeOfSource<T> = T extends Source<infer U> ? U : never;
155155-156156-/** Subscription object that can be used to cancel a {@link Source}.
157157- * @see {@link subscribe | subscribe sink} for a helper that returns this structure.
158158- */
159159-export interface Subscription {
160160- /**
161161- * Cancels a {@link Source} to stop the subscription from receiving new values.
162162- *
163163- * @see {@link TalkbackKind.Close | Close signal} This uses the {@link TalkbackFn | talkback function} to send a {@link TalkbackKind.Close | Close signal}
164164- * to the subscribed-to {@link Source} to stop it from sending new values. This cleans up the subscription
165165- * and ends it immediately.
166166- */
167167- unsubscribe(): void;
168168-}
169169-170170-/** An Observer represents sending signals manually to a {@link Sink}.
171171- * @remarks
172172- * The Observer is used whenever a utility allows for signals to be sent manually as a {@link Source}
173173- * would send them.
174174- *
175175- * @see {@link make | `make` source} for a helper that uses this structure.
176176- */
177177-export interface Observer<T> {
178178- /** Sends a new value to the receiving Sink.
179179- * @remarks
180180- * This creates a {@link Push | Push signal} that is sent to a {@link Sink}.
181181- */
182182- next(value: T): void;
183183- /** Indicates to the receiving Sink that no more values will be sent.
184184- * @remarks
185185- * This creates an {@link SignalKind.End | End signal} that is sent to a {@link Sink}. The Observer
186186- * will accept no more values via {@link Observer.next | `next` calls} once this method has been
187187- * invoked.
188188- */
189189- complete(): void;
190190-}
191191-192192-/** Subjects combine a {@link Source} with the {@link Observer} that is used to send values on said Source.
193193- * @remarks
194194- * A Subject is used whenever an event hub-like structure is needed, as it both provides the
195195- * {@link Observer}'s methods to send signals, as well as the `source` to receive said signals.
196196- *
197197- * @see {@link makeSubject | `makeSubject` source} for a helper that creates this structure.
198198- */
199199-export interface Subject<T> extends Observer<T> {
200200- /** The {@link Source} that issues the signals as the {@link Observer} methods are called. */
201201- source: Source<T>;
202202-}