diff --git a/.github/document.sh b/.github/document.sh
new file mode 100755
index 0000000..9565303
--- /dev/null
+++ b/.github/document.sh
@@ -0,0 +1,17 @@
+export FL_TITLE="Functional IO"
+export FL_DESCRIPTION="IO methods as valid Task monads perfect to write great point-free software in JavaScript that is \
+compatible with most modern browsers and Deno."
+export FL_GITHUB_URL="https://github.com/sebastienfilion/functional-io"
+export FL_DENO_URL="https://deno.land/x/functional_io"
+export FL_VERSION="v1.1.0"
+
+deno run --allow-all --unstable ../@functional:generate-documentation/cli.js document \
+"$FL_TITLE" \
+"$FL_DESCRIPTION" \
+$FL_GITHUB_URL \
+$FL_DENO_URL \
+$FL_VERSION \
+./.github/readme-fragment-usage.md \
+./library/*.js \
+./.github/readme-fragment-typescript.md \
+./.github/readme-fragment-license.md
diff --git a/.github/fl-word_art-io-reverse.svg b/.github/fl-logo.svg
similarity index 100%
rename from .github/fl-word_art-io-reverse.svg
rename to .github/fl-logo.svg
diff --git a/.github/readme-fragment-license.md b/.github/readme-fragment-license.md
new file mode 100644
index 0000000..909a4ea
--- /dev/null
+++ b/.github/readme-fragment-license.md
@@ -0,0 +1,9 @@
+## License
+
+Copyright © 2020 - Sebastien Filion
+
+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 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.
diff --git a/.github/readme-fragment-typescript.md b/.github/readme-fragment-typescript.md
new file mode 100644
index 0000000..3277a23
--- /dev/null
+++ b/.github/readme-fragment-typescript.md
@@ -0,0 +1,23 @@
+## TypeScript
+
+You can import any types.
+
+```ts
+import {
+ Buffer,
+ Directory,
+ File,
+ Request,
+ Resource,
+ Response,
+ URL
+} from "https://deno.land/x/functional_io@v1.1.0/mod.ts";
+```
+
+Or, you can import individual sub-module with the appropriate TypeScript hint in Deno.
+
+```ts
+// @deno-types="https://deno.land/x/functional_io@v1.1.0/library/Request.d.ts"
+import Request from "https://deno.land/x/functional_io@v1.1.0/library/Request.js";
+```
+
\ No newline at end of file
diff --git a/.github/readme-fragment-usage.md b/.github/readme-fragment-usage.md
new file mode 100644
index 0000000..4323441
--- /dev/null
+++ b/.github/readme-fragment-usage.md
@@ -0,0 +1,64 @@
+# Usage
+
+This example uses the [Ramda library](https://ramdajs.com) - for simplification - but you should be able to use any
+library that implements the [Fantasy-land specifications](https://github.com/fantasyland/fantasy-land).
+
+```js
+import { __, ap, chain, compose, lift, map, match, path, prop, useWith } from "https://deno.land/x/ramda@v0.27.2/mod.ts";
+import Task from "https://deno.land/x/functional@v1.3.2/library/Task.js";
+import { safeExtract } from "https://deno.land/x/functional@v1.3.2/library/utilities.js";
+import Request from "https://deno.land/x/functional_io@v1.1.0/library/Request.js";
+import { factorizeFile } from "https://deno.land/x/functional_io@v1.1.0/library/File.js";
+import { fetch } from "https://deno.land/x/functional_io@v1.1.0/library/browser_safe.js";
+import { writeFile } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+
+const fetchBacon = compose(
+ chain(writeFile({})),
+ ap(
+ useWith(
+ lift(factorizeFile(__, __, 0)),
+ [
+ compose(
+ Task.of,
+ name => `${Deno.cwd()}/${name}.html`,
+ prop(1),
+ match(/\?type=([A-Za-z\-]+)/),
+ path([ "headers", "url" ])
+ ),
+ map(prop("raw"))
+ ]
+ ),
+ fetch
+ )
+);
+
+const container = fetchBacon(
+ Request.get("https://baconipsum.com/api/?type=all-meat¶s=3&start-with-lorem=1&format=html")
+);
+
+// Calling `fetchBacon` results in an instance of `Task` keeping the function pure.
+assert(Task.is(container));
+
+const file = safeExtract("Failed to write file.", await container.run());
+
+assert(File.is(file));
+```
+
+### Using the bundle
+
+As a convenience, when using Functional IO in the browser, you can use the **unminified** bundled copy (18KB gzipped).
+
+```js
+import { Task, safeExtract } from "https://deno.land/x/functional@v1.3.2/functional.js";
+import { Request, Response, fetch } from "https://deno.land/x/functional_io@v1.1.0/functional-io.js";
+
+const container = fetch(
+ Request.get("https://baconipsum.com/api/?type=all-meat¶s=3&start-with-lorem=1&format=html")
+);
+
+assert(Task.is(container));
+
+const response = safeExtract("Failed to fetch resource.", await container.run());
+
+assert(Response.is(response));
+```
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8b33dc4
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,24 @@
+.DS_Store
+.data/
+.docs/
+.dump/
+.idea/
+.nyc_output/
+.sass-cache/
+coverage/
+journal/
+node_modules/
+out/
+scratch/
+
+*.db
+*.iml
+*.log
+*.rdb
+*.zip
+
+.todo.md
+
+dmfx
+.dmfx
+*.dmfx.js
diff --git a/README.md b/README.md
index f1533f0..82f38b2 100644
--- a/README.md
+++ b/README.md
@@ -1,64 +1,93 @@
-
+
-IO methods as valid Task monads perfect to write great point-free software in JavaScript that is compatible with most
-modern browsers and Deno.
+IO methods as valid Task monads perfect to write great point-free software in JavaScript that is compatible with most modern browsers and Deno.
-[](https://deno.land/x/functional_io@v1.0.0)
-[](https://github.com/denoland/deno)
+[](https://deno.land/x/functional_io@v1.1.0)
+[](https://github.com/denoland/deno)
[](https://github.com/sebastienfilion/functional-io/releases)
-[](https://github.com/sebastienfilion/functional-io/blob/v1.0.0/LICENSE)
+[](https://github.com/sebastienfilion/functional-io/blob/v1.1.0/LICENSE)
+[](https://discord.gg/)
* [Buffer](#buffer)
* [Directory](#directory)
* [File](#file)
- * [FileSystemCollection](#file-system-collection)
+ * [File System Collection](#file-system-collection)
* [Request](#request)
* [Resource](#resource)
* [Response](#response)
* [URL](#url)
+ * [Browser safe](#browser-safe)
* [File System](#file-system)
- * [Browser Safe](#browser-safe)
-
+ * [Utilities](#utilities)
+ * [TypeScript](#typescript)
+
# Usage
-This example uses the [Ramda library](https://ramdajs.com) - for simplification - but you should be able to use any
-library that implements the [Fantasy-land specifications](https://github.com/fantasyland/fantasy-land).
-
-```js
-import { compose, chain, curry } from "https://x.nest.land/ramda@0.27.0/source/index.js";
-import Either from "https://deno.land/x/functional@v1.2.1/library/Either.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
-import Buffer from "https://deno.land/x/functional_io@v1.0.0/library/Buffer.js";
-import File from "https://deno.land/x/functional_io@v1.0.0/library/File.js";
-import { close, writeAll, create } from "https://deno.land/x/functional_io@v1.0.0/library/fs.js";
-
-const writeNewFile = curry(
- (buffer, destinationFile) =>
- File.isOrThrow(destinationFile)
- && compose(
- chain(close),
- chain(writeAll(buffer)),
- create
- )(destinationFile)
+This example uses the [Ramda library](https://ramdajs.com) - for simplification - but you should be able to use any
+library that implements the [Fantasy-land specifications](https://github.com/fantasyland/fantasy-land).
+
+```js
+import { __, ap, chain, compose, lift, map, match, path, prop, useWith } from "https://deno.land/x/ramda@v0.27.2/mod.ts";
+import Task from "https://deno.land/x/functional@v1.3.2/library/Task.js";
+import { safeExtract } from "https://deno.land/x/functional@v1.3.2/library/utilities.js";
+import Request from "https://deno.land/x/functional_io@v1.1.0/library/Request.js";
+import { factorizeFile } from "https://deno.land/x/functional_io@v1.1.0/library/File.js";
+import { fetch } from "https://deno.land/x/functional_io@v1.1.0/library/browser_safe.js";
+import { writeFile } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+
+const fetchBacon = compose(
+ chain(writeFile({})),
+ ap(
+ useWith(
+ lift(factorizeFile(__, __, 0)),
+ [
+ compose(
+ Task.of,
+ name => `${Deno.cwd()}/${name}.html`,
+ prop(1),
+ match(/\?type=([A-Za-z\-]+)/),
+ path([ "headers", "url" ])
+ ),
+ map(prop("raw"))
+ ]
+ ),
+ fetch
+ )
+);
+
+const container = fetchBacon(
+ Request.get("https://baconipsum.com/api/?type=all-meat¶s=3&start-with-lorem=1&format=html")
);
-// Calling `writeNewFile` results in an instance of `Task` keeping the function pure.
-assert(
- Task.is(writeNewFile(File.fromPath(`${Deno.cwd()}/hoge`), Buffer.fromString("Hello Deno")))
+// Calling `fetchBacon` results in an instance of `Task` keeping the function pure.
+assert(Task.is(container));
+
+const file = safeExtract("Failed to write file.", await container.run());
+
+assert(File.is(file));
+```
+
+### Using the bundle
+
+As a convenience, when using Functional IO in the browser, you can use the **unminified** bundled copy (18KB gzipped).
+
+```js
+import { Task, safeExtract } from "https://deno.land/x/functional@v1.3.2/functional.js";
+import { Request, Response, fetch } from "https://deno.land/x/functional_io@v1.1.0/functional-io.js";
+
+const container = fetch(
+ Request.get("https://baconipsum.com/api/?type=all-meat¶s=3&start-with-lorem=1&format=html")
);
-// Finally, calling `Task#run` will call copy to the new file and return a promise
-writeNewFile(File.fromPath(`${Deno.cwd()}/hoge`), Buffer.fromString("Hello Deno")).run()
- .then(container => {
- // The returned value should be an instance of `Either.Right` or `Either.Left`
- assert(Either.Right.is(container));
- // Forcing to coerce the container to string will show that the final value is our File representation.
- assert(container.toString(), `Either.Right(File("${Deno.cwd()}/piyo", ...))`);
- });
+assert(Task.is(container));
+
+const response = safeExtract("Failed to fetch resource.", await container.run());
-// await copyToNewFile(sourceFile, destinationFile).run() === Either.Right(File a)
+assert(Response.is(response));
```
+---
+
## Buffer
The `Buffer` is the most basic type; it only has one attribute which is a typed array named "raw".
@@ -72,11 +101,15 @@ The `Buffer` type implements the following algebras:
### Example
```js
-const buffer = Buffer.fromString("Hoge").concat(Buffer.fromString("Fuga"));
+import Buffer from "https://deno.land/x/functional_io@v1.1.0/library/Buffer.js";
+
+const buffer = Buffer.fromString("hoge").concat(Buffer.fromString("fuga"));
assert(Buffer.is(buffer));
```
+---
+
## Directory
The `Directory` type represents a directory on the file system. It is the only type with the same shape as `URL`.
@@ -95,6 +128,8 @@ The `Directory` type implements the following algebras:
assert(Directory(`${Deno.cwd()}/hoge`).lte(Directory(`${Deno.cwd()}/piyo`)));
```
+---
+
## File
The `File` type extends the `Resource` type. It represents a file with a path.
@@ -118,6 +153,8 @@ const file = File(`${Deno.cwd()}/hoge`, new Uint8Array([ 65, 66, 67, 68, 69 ]),
assert(File.is(file));
```
+---
+
## File System Collection
The `FileSystemCollection` is represents a collection of `Location`, namely of `Directory` and `File`. This of it
@@ -129,8 +166,6 @@ The `FileSystemCollection` type implements the following algebras:
- [x] Monad
- [x] Traversable
-⚠️ *The `FileSystemCollection` type as a **traversable** is experimental.*
-
### Example
```js
@@ -142,6 +177,13 @@ assert(containerA.extract() === 44);
assert(Maybe.Nothing.is(containerB));
```
+---
+
+File Group algebra law "Left identity" and "Right identity" is not respected because the rid can't be modified
+without using bimap.
+
+---
+
## Request
The `Request` represent a HTTP request.
@@ -165,7 +207,7 @@ assert(Request.is(request));
#### Utilities
The `Request` namespace comes with 4 methods for convenience to create an instance of `Request` with a common verb.
-The methods are curried when necessary. `Object -> Unint8Array -> Response`
+The methods are curried when necessary. `Object → Unint8Array → Response`
```js
const container = compose(
@@ -178,13 +220,32 @@ assert((await container.run()).extract().headers.method === "POST");
| Method name | Has 2 arguments |
|------------------------|-----------------|
-| `delete` / `DELETE` | false |
-| `get` / `GET` | false |
-| `post` / `POST` | true |
-| `put` / `PUT` | true |
+| `delete` | `DELETE` | false |
+| `get` | `GET` | false |
+| `post` | `POST` | true |
+| `put` | `PUT` | true |
✢ *The capitalized version of the methods were added because `delete` is a TypeScript reserved word.*
+---
+
+Request Semigroup algebra law "Left identity" is not respected because the headers can't be modified without using
+bimap.
+
+Request Monoid algebra law "Left identity" is not respected because the headers can't be modified without using
+bimap.
+
+Request Group algebra law "Left identity" and "Right identity" is not respected because the headers can't be
+modified without using bimap.
+
+Request Modnad algebra law "Right identity" is not respected because the headers can't be modified without using
+bimap.
+
+Request Applicative algebra law "Interchange" is not respected because the headers can't be modified without using
+bimap.
+
+---
+
## Resource
The `Resource` type extends the `Buffer` type. It represents a system resource with a handle, eg: STDOUT, STDIN or a
@@ -206,6 +267,22 @@ const resource = Resource(new Uint8Array([ 65, 66, 67, 68, 69 ]), 3)
assert(Resource.is(resource));
```
+---
+
+Resource Monoid algebra law "Left identity" is not respected because the rid can't be modified without using
+bimap.
+
+Resource Group algebra law "Left identity" and "Right identity" is not respected because the rid can't be modified
+without using bimap.
+
+Resource Modnad algebra law "Right identity" is not respected because the rid can't be modified without using
+bimap.
+
+Resource Applicative algebra law "Interchange" is not respected because the rid can't be modified without using
+bimap.
+
+---
+
## Response
The `Response` represent a HTTP response.
@@ -231,7 +308,7 @@ assert(Response.is(response));
The `Response` namespace comes with 38 methods for convenience to create an instance of `Response` with a common
status.
-The methods are curried: `Object -> Uint8Array -> Response`
+The methods are curried: `Object → Uint8Array → Response`
```js
const container = compose(
@@ -271,6 +348,25 @@ assert((await container.run()).extract().headers.status === 200);
| `GatewayTimeout` | 504 |
| `PermissionDenied` | 550 |
+---
+
+Response Semigroup algebra law "Left identity" is not respected because the headers can't be modified without using
+bimap.
+
+Response Monoid algebra law "Left identity" is not respected because the headers can't be modified without using
+bimap.
+
+Response Group algebra law "Left identity" and "Right identity" is not respected because the headers can't be
+modified without using bimap.
+
+Response Modnad algebra law "Right identity" is not respected because the headers can't be modified without using
+bimap.
+
+Response Applicative algebra law "Interchange" is not respected because the headers can't be modified without using
+bimap.
+
+---
+
## URL
The `URL` type represents an URL; either of a location on the file system or on a remote server.
@@ -289,21 +385,41 @@ The `URL` type implements the following algebras:
assert(URL(`${Deno.cwd()}/hoge`).lte(URL(`${Deno.cwd()}/piyo`)));
```
+---
+
+## Browser safe
+
+### `pureFetch`
+`Request → Task e Response`
+
+Fetches a resource on a local/remote server.
+
+```js
+import { fetch } from "https://deno.land/x/functional_io@v1.1.0/library/browser-safe.js";
+
+const containerA = fetch(Request.GET("http://localhost:8000"));
+
+assert(Task.is(containerA));
+
+const containerB = await container.run().extract();
+
+assert(Response.Success.is(containerB));
+```
+
+---
+
## File System
**⚠️ Note** `Deno.cwd` is used in the following example; if you use `Deno.cwd` to compose your paths, your functions
-are no longer pure.
+are no longer pure.
### `chdir` [📕](https://doc.deno.land/builtin/stable#Deno.chdir)
+`Directory → Task e Directory`
Change the current working directory to the specified path.
-`chdir :: Directory a -> Task e Directory a`
-
```js
-import { chdir } from "https://deno.land/x/functional_io@v1.0.0/library/fs.js";
-import Directory from "https://deno.land/x/functional_io@v1.0.0/library/Directory.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import { chdir } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
const container = chdir(Directory(".."));
@@ -311,15 +427,12 @@ assert(Task.is(container));
```
### `chmod` [📕](https://doc.deno.land/builtin/stable#Deno.chmod)
+`Number → File → Task e File`
-Changes the permission of a specific file/directory of specified path. Ignores the process's umask.
-
-`chmod :: Number -> Location a -> Task e Location a`
+Changes the permission of a specific file/directory of specified path. Ignores the process's umask.
```js
-import { chmod } from "https://deno.land/x/functional_io@v1.0.0/library/fs.js";
-import File from "https://deno.land/x/functional_io@v1.0.0/library/File.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import { chmod } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
const container = chmod(0o000, File.fromPath(`${Deno.cwd()}/hoge`));
@@ -327,15 +440,12 @@ assert(Task.is(container));
```
### `chown` [📕](https://doc.deno.land/builtin/stable#Deno.chown)
+`Number → Number → File → Task e File`
Change owner of a regular file or directory. This functionality is not available on Windows.
-`chown :: Number -> Number -> Location a -> Task e Location a`
-
```js
-import { chown } from "https://deno.land/x/functional_io@v1.0.0/library/fs.js";
-import File from "https://deno.land/x/functional_io@v1.0.0/library/File.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import { chown } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
const container = chown(null, null, File.fromPath(`${Deno.cwd()}/hoge`));
@@ -343,16 +453,13 @@ assert(Task.is(container));
```
### `close` [📕](https://doc.deno.land/builtin/stable#Deno.close)
+`Resource → Task e Resource`
-Close the given resource which has been previously opened, such as via opening or creating a file.
-Closing a file when you are finished with it is important to avoid leaking resources.
-
-`close :: File a -> Task e File a`
+Close the given resource which has been previously opened, such as via opening or creating a file.
+Closing a file when you are finished with it is important to avoid leaking resources.
```js
-import { close } from "https://deno.land/x/functional_io@v1.0.0/library/fs.js";
-import File from "https://deno.land/x/functional_io@v1.0.0/library/File.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import { close } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
const container = close(File(`${Deno.cwd()}/hoge`, new Uint8Array([]), 3));
@@ -360,15 +467,12 @@ assert(Task.is(container));
```
### `copy` [📕](https://doc.deno.land/builtin/stable#Deno.copy)
+`Object → Buffer a → Buffer b → Task e Buffer b`
-Copies from a source to a destination until either EOF (null) is read from the source, or an error occurs.
-
-`copy :: Options -> Buffer a -> Buffer b -> Task e Buffer a`
+Copies from a source to a destination until either EOF (null) is read from the source, or an error occurs.
```js
-import { copy } from "https://deno.land/x/functional_io@v1.0.0/library/fs.js";
-import Buffer from "https://deno.land/x/functional_io@v1.0.0/library/Buffer.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import { copy } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
const container = copy({}, Buffer(new Uint8Array([ 65, 66, 67, 68, 69 ])), Buffer(new Uint8Array([])));
@@ -376,16 +480,13 @@ assert(Task.is(container));
```
### `copyFile` [📕](https://doc.deno.land/builtin/stable#Deno.copyFile)
+`File a → File b → Task e File b`
-Copies the contents and permissions of one file to another specified file, by default creating a new file if needed,
+Copies the contents and permissions of one file to another specified file, by default creating a new file if needed,
else overwriting. Fails if target path is a directory or is unwritable.
-`copyFile :: File a -> File b -> Task e File b`
-
```js
-import { copyFile } from "https://deno.land/x/functional_io@v1.0.0/library/fs.js";
-import File from "https://deno.land/x/functional_io@v1.0.0/library/File.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import { copyFile } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
const container = copyFile(File.fromPath(`${Deno.cwd()}/hoge`), File.fromPath(`${Deno.cwd()}/piyo`));
@@ -393,15 +494,12 @@ assert(Task.is(container));
```
### `create` [📕](https://doc.deno.land/builtin/stable#Deno.create)
+`File → Task e File`
Creates a file if none exists or truncates an existing file.
-`create :: File a -> Task e File a`
-
```js
-import { create } from "https://deno.land/x/functional_io@v1.0.0/library/fs.js";
-import File from "https://deno.land/x/functional_io@v1.0.0/library/File.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import { create } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
const container = create(File.fromPath(`${Deno.cwd()}/hoge`));
@@ -411,45 +509,23 @@ assert(Task.is(container));
### `cwd` [📕](https://doc.deno.land/builtin/stable#Deno.cwd)
Return a Directory representation of the current working directory.
-
-`cwd :: () -> Task e Directory a`
+`() → Task e Directory`
```js
-import { cwd } from "https://deno.land/x/functional_io@v1.0.0/library/fs.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import { cwd } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
const container = cwd();
assert(Task.is(container));
```
-### `emptyDir` [📕](https://deno.land/std@0.79.0/fs#emptydir)
-
-Ensures that a directory is empty. Deletes directory contents if the directory is not empty.
-If the directory does not exist, it is created. The directory itself is not deleted.
-
-`emptyDir :: Directory a -> Task e Directory a`
-
-```js
-import { emptyDir } from "https://deno.land/x/functional_io@v1.0.0/library/fs.js";
-import Directory from "https://deno.land/x/functional_io@v1.0.0/library/Directory.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
-
-const container = emptyDir(Directory(`${Deno.cwd()}/hoge`));
-
-assert(Task.is(container));
-```
-
### `ensureDir` [📕](https://deno.land/std@0.79.0/fs#ensuredir)
+`Directory → Task e Directory`
Ensures that the directory exists. If the directory structure does not exist, it is created. Like `mkdir -p`.
-`ensureDir :: Directory a -> Task e Directory a`
-
```js
-import { ensureDir } from "https://deno.land/x/functional_io@v1.0.0/library/fs.js";
-import Directory from "https://deno.land/x/functional_io@v1.0.0/library/Directory.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import { ensureDir } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
const container = emptyDir(Directory(`${Deno.cwd()}/hoge`));
@@ -457,16 +533,13 @@ assert(Task.is(container));
```
### `exists` [📕](https://deno.land/std@0.79.0/fs#exists)
+`URL → Task e|null URL
-Test whether the given path exists by checking with the file system.
+Test whether the given path exists by checking with the file system.
If the file or directory doesn't exist, it will resolve to `Either.Left(null)`.
-`exists :: Location a -> Task null Location a`
-
```js
-import { exists } from "https://deno.land/x/functional_io@v1.0.0/library/fs.js";
-import Directory from "https://deno.land/x/functional_io@v1.0.0/library/Directory.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import { exists } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
const container = exists(Directory(`${Deno.cwd()}/hoge`));
@@ -474,15 +547,12 @@ assert(Task.is(container));
```
### `mkdir` [📕](https://deno.land/std@0.79.0/fs#mkdir)
+`Object → Directory → Task e Directory`
Creates a new directory with the specified path.
-`mkdir :: Options -> Directory a -> Task e Directory a`
-
```js
-import { mkdir } from "https://deno.land/x/functional_io@v1.0.0/library/fs.js";
-import Directory from "https://deno.land/x/functional_io@v1.0.0/library/Directory.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import { mkdir } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
const container = mkdir({}, Directory(`${Deno.cwd()}/hoge`));
@@ -490,15 +560,12 @@ assert(Task.is(container));
```
### `move` [📕](https://deno.land/std@0.79.0/fs#move)
+`Object → String → URL → Task e URL`
Moves a file or directory.
-`move :: Options -> String -> Location a -> Task e Location b`
-
```js
-import { move } from "https://deno.land/x/functional_io@v1.0.0/library/fs.js";
-import Directory from "https://deno.land/x/functional_io@v1.0.0/library/Directory.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import { move } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
const container = move({}, `${Deno.cwd()}/piyo`, Directory(`${Deno.cwd()}/hoge`));
@@ -506,16 +573,13 @@ assert(Task.is(container));
```
### `open` [📕](https://doc.deno.land/builtin/stable#Deno.open)
+`Object → File → Task e File`
Open a file and resolve to an instance of File. The file does not need to previously exist if using the create or
createNew open options. It is the callers responsibility to close the file when finished with it.
-`open :: Options -> File a -> Task e File a`
-
```js
-import { open } from "https://deno.land/x/functional_io@v1.0.0/library/fs.js";
-import Directory from "https://deno.land/x/functional_io@v1.0.0/library/Directory.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import { open } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
const container = open({ read: true, write: true }, File.fromPath(`${Deno.cwd()}/hoge`));
@@ -523,48 +587,103 @@ assert(Task.is(container));
```
### `read` [📕](https://doc.deno.land/builtin/stable#Deno.read)
+`Resource Task e Resource`
Read from a Resource given it has a non-zero raw buffer.
-`read :: Resource a -> Task e Resource a`
-
```js
-import { read } from "https://deno.land/x/functional_io@v1.0.0/library/fs.js";
-import File from "https://deno.land/x/functional_io@v1.0.0/library/File.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import { read } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
const container = read(File(`${Deno.cwd()}/hoge`, new Uint8Array(5), 3));
assert(Task.is(container));
```
+### `readLine`
+`Resource → Task e Resource`
+
+Read from a Resource to the CLRF.
+
+```js
+import { readLine } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+
+const container = readLine(File(`${Deno.cwd()}/hoge`, new Uint8Array([]), 3));
+
+assert(Task.is(container));
+```
+
+### `readNBytes`
+`Number → Resource → Task e Resource`
+
+Read N bytes from a Resource.
+
+```js
+import { readNBytes } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+
+const container = readNBytes(5, File(`${Deno.cwd()}/hoge`, new Uint8Array([]), 3));
+
+assert(Task.is(container));
+```
+
+### `readOneByte`
+`Resource → Task e Resource`
+
+Read 1 byte from a Resource.
+
+```js
+import { readOneByte } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+
+const container = readOneByte(File(`${Deno.cwd()}/hoge`, new Uint8Array([]), 3));
+
+assert(Task.is(container));
+```
+
### `readAll` [📕](https://doc.deno.land/builtin/stable#Deno.readAll)
+`Resource → Task e Resource`
Read from a Resource.
-`readAll :: Resource a -> Task e Resource a`
-
```js
-import { readAll } from "https://deno.land/x/functional_io@v1.0.0/library/fs.js";
-import Buffer from "https://deno.land/x/functional_io@v1.0.0/library/Buffer.js";
-import File from "https://deno.land/x/functional_io@v1.0.0/library/File.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import { readAll } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
const container = readAll(File(`${Deno.cwd()}/hoge`, new Uint8Array([]), 3));
assert(Task.is(container));
```
-### `rename` [📕](https://doc.deno.land/builtin/stable#Deno.rename)
+### `readFile` [📕](https://doc.deno.land/builtin/stable#Deno.readFile)
+`File → Task e File`
+
+Read from a File.
+
+```js
+import { readFile } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+
+const container = readFile(File(`${Deno.cwd()}/hoge`, new Uint8Array([]), 3));
+
+assert(Task.is(container));
+```
-Renames a file or directory.
+### `remove` [📕](https://doc.deno.land/builtin/stable#Deno.remove)
+`Object → URL → Task e URL`
-`rename :: String -> Location a -> Task e Location b`
+Removes the named file or directory.
```js
-import { rename } from "https://deno.land/x/functional_io@v1.0.0/library/fs.js";
-import Directory from "https://deno.land/x/functional_io@v1.0.0/library/Directory.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import { remove } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+
+const container = remove({ recursive: true }, Directory.fromPath(`${Deno.cwd()}/hoge`));
+
+assert(Task.is(container));
+```
+
+### `rename` [📕](https://doc.deno.land/builtin/stable#Deno.rename)
+`String → URL → Task e URL`
+
+Renames a file or directory.
+
+```js
+import { rename } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
const container = rename(`${Deno.cwd()}/piyo`, Directory(`${Deno.cwd()}/hoge`));
@@ -572,108 +691,197 @@ assert(Task.is(container));
```
### `write` [📕](https://doc.deno.land/builtin/stable#Deno.write)
+`Resource → Task e Resource`
Write to a Resource given it has a non-zero raw buffer.
-`write :: Resource a -> Task e Resource a`
-
```js
-import { write } from "https://deno.land/x/functional_io@v1.0.0/library/fs.js";
-import File from "https://deno.land/x/functional_io@v1.0.0/library/File.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import { write } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
-const container = write(
- File(`${Deno.cwd()}/hoge`, new Uint8Array([ 65, 66, 67, 68, 69 ]), _file.rid)
-);
+const container = write(File(`${Deno.cwd()}/hoge`, new Uint8Array([ 65, 66, 67, 68, 69 ]), 3));
assert(Task.is(container));
```
### `writeAll` [📕](https://doc.deno.land/builtin/stable#Deno.writeAll)
+`Buffer → Task e Resource`
Write all to a Resource from a Buffer.
-`writeAll :: Buffer b -> Resource a -> Task e Resource b`
-
```js
-import { writeAll } from "https://deno.land/x/functional_io@v1.0.0/library/fs.js";
-import Buffer from "https://deno.land/x/functional_io@v1.0.0/library/Buffer.js";
-import File from "https://deno.land/x/functional_io@v1.0.0/library/File.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import { writeAll } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
const container = writeAll(
Buffer(new Uint8Array([ 65, 66, 67, 68, 69 ])),
- File(`${Deno.cwd()}/hoge`, new Uint8Array([]), _file.rid)
+ File(`${Deno.cwd()}/hoge`, new Uint8Array([]), 3)
);
assert(Task.is(container));
```
### `writeFile` [📕](https://doc.deno.land/builtin/stable#Deno.writeFile)
+`Object → File → Task e File`
Write a File to the file system.
-`writeFile :: Options -> File a -> Task e File b`
+```js
+import { writeFile } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+
+const container = writeFile({}, File(`${Deno.cwd()}/hoge`, new Uint8Array([]), 3));
+
+assert(Task.is(container));
+```
+
+---
+
+## Utilities
+
+### `findCLRFIndex`
+`Uint8Array → Number`
+
+This function takes a `Uint8Array` and, returns the index of the last character of the first CLRF sequence
+encountered.
+
+```js
+import { findCLRFIndex } from "https://deno.land/x/functional_io@v1.1.0/library/utilities.js";
+
+assertEquals(findCLRFIndex(new Uint8Array([ 104, 111, 103, 101, 13, 10 ])), 6);
+```
+
+### `discardFirstLine`
+`Uint8Array → Uint8Array`
+
+This function takes a `Uint8Array` and, returns the typed array minus the first line separated by CLRF.
```js
-import { writeFile } from "https://deno.land/x/functional_io@v1.0.0/library/fs.js";
-import Buffer from "https://deno.land/x/functional_io@v1.0.0/library/Buffer.js";
-import File from "https://deno.land/x/functional_io@v1.0.0/library/File.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import { discardFirstLine } from "https://deno.land/x/functional_io@v1.1.0/library/utilities.js";
-const container = writeFile(
- {},
- File(`${Deno.cwd()}/hoge`, new Uint8Array([]), _file.rid)
+assertEquals(
+ discardFirstLine(new Uint8Array([ 104, 111, 103, 101, 13, 10, 104, 111, 103, 101, 13, 10 ])),
+ new Uint8Array([ 104, 111, 103, 101, 13, 10 ])
);
+```
-assert(Task.is(container));
-```
+### `discardNCharacter`
+`Number → Uint8Array → Uint8Array`
-## Browser Safe
+This function takes a Number, a `Uint8Array` and, returns the typed array minus the specified amount of character
+starting from the left side.
-### `fetch`
+```js
+import { discardNCharacter } from "https://deno.land/x/functional_io@v1.1.0/library/utilities.js";
-Fetches a resource on a local/remote server.
+assertEquals(
+ discardNCharacter(1, new Uint8Array([ 104, 111, 103, 101, 13, 10 ])),
+ new Uint8Array([ 111, 103, 101, 13, 10 ])
+);
+```
+
+### `getFirstLine`
+`Uint8Array → Uint8Array`
-`fetch :: Request a -> Task e Response b`
+This function takes a `Uint8Array` and, returns the first line separated by a CLRF inclusively.
```js
-import { fetch } from "https://deno.land/x/functional_io@v1.0.0/library/browser-safe.js";
-import Request from "https://deno.land/x/functional_io@v1.0.0/library/Request.js";
-import Response from "https://deno.land/x/functional_io@v1.0.0/library/Response.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import { getFirstLine } from "https://deno.land/x/functional_io@v1.1.0/library/utilities.js";
-const containerA = fetch(Request.GET("http://localhost:8000"));
+assertEquals(
+ getFirstLine(new Uint8Array([ 104, 111, 103, 101, 13, 10, 104, 111, 103, 101, 13, 10 ])),
+ new Uint8Array([ 104, 111, 103, 101, 13, 10 ])
+);
+```
-assert(Task.is(containerA));
+### `joinCLRF`
+`Uint8Array[] → Uint8Array`
-const containerB = await container.run().extract();
+This function takes a list of `Uint8Array` and, returns a `Uint8Array` of the list joined with CLRF sequence; the
+function is analogous to `Array#join`.
-assert(Response.Success.is(containerB));
+```js
+import { joinCLRF } from "https://deno.land/x/functional_io@v1.1.0/library/utilities.js";
+
+assertEquals(
+ joinCLRF(
+ [
+ new Uint8Array([ 104, 111, 103, 101 ]),
+ new Uint8Array([ 104, 111, 103, 101 ])
+ ]
+ ),
+ new Uint8Array([ 104, 111, 103, 101, 13, 10, 104, 111, 103, 101, 13, 10 ])
+);
```
-
-## Deno
-This codebase uses [Deno](https://deno.land/#installation).
+### `splitCLRF`
+`Uint8Array → Uint8Array[]`
-### MIT License
+This function takes a `Uint8Array` and, returns a list of `Uint8Array` of subarray split at the CLRF sequence; the
+function is analogous to `String#split`.
+
+```js
+import { splitCLRF } from "https://deno.land/x/functional_io@v1.1.0/library/utilities.js";
+
+assertEquals(
+ splitCLRF(new Uint8Array([ 104, 111, 103, 101, 13, 10, 104, 111, 103, 101, 13, 10 ])),
+ [
+ new Uint8Array([ 104, 111, 103, 101, 13, 10 ]),
+ new Uint8Array([ 104, 111, 103, 101, 13, 10 ])
+ ]
+);
+```
+
+### `trimCRLF`
+`Uint8Array → Uint8Array`
+
+This function takes a `Uint8Array` and, returns a typed array minus CRLF at the beginning and at the end;
+the function is analogous to `String#trim`.
+
+```js
+import { trimCRLF } from "https://deno.land/x/functional_io@v1.1.0/library/utilities.js";
+
+assertEquals(
+ trimCRLF(new Uint8Array([ 104, 111, 103, 101, 13, 10 ])),
+ new Uint8Array([ 104, 111, 103, 101 ])
+);
+```
+
+### `factorizeUint8Array`
+`Number|Array|Uint8Array → Uint8Array
+
+This function factorize a Uint8Array given an argument.
+
+---
+
+## TypeScript
+
+You can import any types.
+
+```ts
+import {
+ Buffer,
+ Directory,
+ File,
+ Request,
+ Resource,
+ Response,
+ URL
+} from "https://deno.land/x/functional_io@v1.1.0/mod.ts";
+```
+
+Or, you can import individual sub-module with the appropriate TypeScript hint in Deno.
+
+```ts
+// @deno-types="https://deno.land/x/functional_io@v1.1.0/library/Request.d.ts"
+import Request from "https://deno.land/x/functional_io@v1.1.0/library/Request.js";
+```
+
+---
+
+## License
Copyright © 2020 - Sebastien Filion
-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 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.
+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 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.
diff --git a/browser_save_mod.js b/browser_save_mod.js
new file mode 100644
index 0000000..f85acb9
--- /dev/null
+++ b/browser_save_mod.js
@@ -0,0 +1,5 @@
+export * from "./library/Buffer.js";
+export * from "./library/Request.js";
+export * from "./library/Response.js";
+export * from "./library/URL.js";
+export * from "./library/browser_safe.js";
diff --git a/functional-io.js b/functional-io.js
new file mode 100644
index 0000000..699de8e
--- /dev/null
+++ b/functional-io.js
@@ -0,0 +1,1720 @@
+Buffer.prototype.chain = Buffer.prototype["fantasy-land/chain"] = function(unaryFunction) {
+ return unaryFunction(this.raw);
+};
+Buffer.prototype.equals = Buffer.prototype["fantasy-land/equals"] = function(container) {
+ return this.raw.byteLength === container.raw.byteLength && !!this.raw.reduce((accumulator, value, index)=>accumulator && accumulator[index] == value ? accumulator : false
+ , container.raw);
+};
+Buffer.prototype.extract = Buffer.prototype["fantasy-land/extract"] = function() {
+ return this.raw;
+};
+Buffer.prototype.lte = Buffer.prototype["fantasy-land/equals"] = function(container) {
+ return this.raw.byteLength <= container.raw.byteLength && !!this.raw.reduce((accumulator, value, index)=>!accumulator && accumulator[index] > value ? accumulator : true
+ , container.raw);
+};
+Request1.prototype.chain = Request1.prototype["fantasy-land/chain"] = function(unaryFunction) {
+ return unaryFunction(this.raw);
+};
+Request1.prototype.equals = Request1.prototype["fantasy-land/equals"] = function(container) {
+ return this.headers.status === container.headers.status && this.headers.url === container.headers.url && this.raw.byteLength === container.raw.byteLength && !!this.raw.reduce((accumulator, value, index)=>accumulator && accumulator[index] == value ? accumulator : false
+ , container.raw);
+};
+Request1.prototype.lte = Request1.prototype["fantasy-land/lte"] = function(container) {
+ return this.headers.status === container.headers.status && this.headers.url === container.headers.url && this.raw.byteLength === container.raw.byteLength && !!this.raw.reduce((accumulator, value, index)=>!accumulator && accumulator[index] > value ? accumulator : true
+ , container.raw);
+};
+Response1.prototype.alt = Response1.prototype["fantasy-land/alt"] = function(container) {
+ return this.fold({
+ Failure: (_)=>container
+ ,
+ Success: (_)=>this
+ });
+};
+Response1.prototype.chain = Response1.prototype["fantasy-land/chain"] = function(unaryFunction) {
+ return this.fold({
+ Failure: (_)=>this
+ ,
+ Success: (_)=>unaryFunction(this.raw)
+ });
+};
+Response1.prototype.equals = Response1.prototype["fantasy-land/equals"] = function(container) {
+ return this.headers.status === container.headers.status && this.headers.url === container.headers.url && this.raw.byteLength === container.raw.byteLength && !!this.raw.reduce((accumulator, value, index)=>accumulator && accumulator[index] == value ? accumulator : false
+ , container.raw);
+};
+Response1.prototype.lte = Response1.prototype["fantasy-land/lte"] = function(container) {
+ return this.headers.status === container.headers.status && this.headers.url === container.headers.url && this.raw.byteLength === container.raw.byteLength && !!this.raw.reduce((accumulator, value, index)=>!accumulator && accumulator[index] > value ? accumulator : true
+ , container.raw);
+};
+URL1.prototype.chain = URL1.prototype["fantasy-land/chain"] = function(unaryFunction) {
+ return unaryFunction(this.path);
+};
+URL1.prototype.equals = URL1.prototype["fantasy-land/equals"] = function(container) {
+ return this.path === container.path;
+};
+URL1.prototype.extract = URL1.prototype["fantasy-land/extract"] = function() {
+ return this.path;
+};
+URL1.prototype.lte = URL1.prototype["fantasy-land/equals"] = function(container) {
+ return this.path <= container.path;
+};
+const noColor = globalThis.Deno?.noColor ?? true;
+let enabled = !noColor;
+function code(open, close) {
+ return {
+ open: `\x1b[${open.join(";")}m`,
+ close: `\x1b[${close}m`,
+ regexp: new RegExp(`\\x1b\\[${close}m`, "g")
+ };
+}
+function run(str, code1) {
+ return enabled ? `${code1.open}${str.replace(code1.regexp, code1.open)}${code1.close}` : str;
+}
+function brightBlack(str) {
+ return run(str, code([
+ 90
+ ], 39));
+}
+function clampAndTruncate(n, max = 255, min = 0) {
+ return Math.trunc(Math.max(Math.min(n, max), min));
+}
+const ANSI_PATTERN = new RegExp([
+ "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
+ "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))",
+].join("|"), "g");
+const $$decoder = new TextDecoder();
+const decodeRaw = $$decoder.decode.bind($$decoder);
+const coerceReadableStreamToUint8Array = async (readableStream)=>{
+ let _array = new Uint8Array([]);
+ return readableStream.read().then(function processBody({ done , value }) {
+ if (!done) {
+ _array = new Uint8Array([
+ ..._array,
+ ...value
+ ]);
+ return readableStream.read().then(processBody);
+ } else return _array;
+ });
+};
+function _pipe(f, g) {
+ return function() {
+ return g.call(this, f.apply(this, arguments));
+ };
+}
+function _identity(x) {
+ return x;
+}
+function _isFunction(x) {
+ var type = Object.prototype.toString.call(x);
+ return type === '[object Function]' || type === '[object AsyncFunction]' || type === '[object GeneratorFunction]' || type === '[object AsyncGeneratorFunction]';
+}
+const serializeTypeRepresentation = (typeName)=>typeName
+;
+const $$debug = Symbol.for("TaskDebug");
+const $$inspect = typeof Deno !== "undefined" ? Deno.customInspect : "inspect";
+const $$returnType = Symbol.for("ReturnType");
+const $$tag = Symbol.for("Tag");
+const $$tagList = Symbol.for("TagList");
+const $$type1 = Symbol.for("Type");
+const $$value = Symbol.for("Value");
+const $$valueList = Symbol.for("ValueList");
+Either.prototype.alt = Either.prototype["fantasy-land/alt"] = function(container) {
+ return this.fold({
+ Left: (_)=>container
+ ,
+ Right: (_)=>this
+ });
+};
+Either.prototype.chain = Either.prototype["fantasy-land/chain"] = function(unaryFunction) {
+ return this.fold({
+ Left: (_)=>this
+ ,
+ Right: (value)=>unaryFunction(value)
+ });
+};
+Either.prototype.extract = Either.prototype["fantasy-land/extract"] = function() {
+ return this.fold({
+ Left: (_)=>this
+ ,
+ Right: (value)=>value
+ });
+};
+Either.prototype.reduce = Either.prototype["fantasy-land/reduce"] = function(binaryFunction, accumulator) {
+ return this.fold({
+ Left: (_)=>accumulator
+ ,
+ Right: (value)=>binaryFunction(accumulator, value)
+ });
+};
+Either.prototype.sequence = function(TypeRepresentation) {
+ return this.traverse(TypeRepresentation, (x)=>x
+ );
+};
+Step.prototype.alt = Step.prototype["fantasy-land/alt"] = function(container) {
+ return this.fold({
+ Done: (_)=>container
+ ,
+ Loop: (_)=>this
+ });
+};
+const concat = (x)=>(y)=>x.concat(y)
+;
+const serializeFunctionForDebug = (asyncFunction)=>asyncFunction.name && asyncFunction.name !== "" ? asyncFunction.name : asyncFunction.toString().length > 25 ? asyncFunction.toString().slice(0, 25).replace(/[\n\r]/g, "").replace(/\s\s*/g, " ") + "[...]" : asyncFunction.toString().replace(/[\n\r]/g, "").replace(/\s\s*/g, " ")
+;
+Task.prototype.toString = Task.prototype[$$inspect] = function() {
+ return this[$$debug] || `Task("unknown")`;
+};
+function XMap(f, xf) {
+ this.xf = xf;
+ this.f = f;
+}
+XMap.prototype['@@transducer/step'] = function(result, input) {
+ return this.xf['@@transducer/step'](result, this.f(input));
+};
+const __default4 = Number.isInteger || function _isInteger(n) {
+ return n << 0 === n;
+};
+function _arrayFromIterator(iter) {
+ var list = [];
+ var next;
+ while(!(next = iter.next()).done){
+ list.push(next.value);
+ }
+ return list;
+}
+function _includesWith(pred, x, list) {
+ var idx = 0;
+ var len = list.length;
+ while(idx < len){
+ if (pred(x, list[idx])) {
+ return true;
+ }
+ idx += 1;
+ }
+ return false;
+}
+function _functionName(f) {
+ var match = String(f).match(/^function (\w*)/);
+ return match == null ? '' : match[1];
+}
+function _objectIs(a, b) {
+ if (a === b) {
+ return a !== 0 || 1 / a === 1 / b;
+ } else {
+ return a !== a && b !== b;
+ }
+}
+const __default1 = typeof Object.is === 'function' ? Object.is : _objectIs;
+function _quote(s) {
+ var escaped = s.replace(/\\/g, '\\\\').replace(/[\b]/g, '\\b').replace(/\f/g, '\\f').replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/\t/g, '\\t').replace(/\v/g, '\\v').replace(/\0/g, '\\0');
+ return '"' + escaped.replace(/"/g, '\\"') + '"';
+}
+var pad = function pad(n) {
+ return (n < 10 ? '0' : '') + n;
+};
+var _toISOString = typeof Date.prototype.toISOString === 'function' ? function _toISOString(d) {
+ return d.toISOString();
+} : function _toISOString(d) {
+ return d.getUTCFullYear() + '-' + pad(d.getUTCMonth() + 1) + '-' + pad(d.getUTCDate()) + 'T' + pad(d.getUTCHours()) + ':' + pad(d.getUTCMinutes()) + ':' + pad(d.getUTCSeconds()) + '.' + (d.getUTCMilliseconds() / 1000).toFixed(3).slice(2, 5) + 'Z';
+};
+function _complement(f) {
+ return function() {
+ return !f.apply(this, arguments);
+ };
+}
+function _filter(fn, list) {
+ var idx = 0;
+ var len = list.length;
+ var result = [];
+ while(idx < len){
+ if (fn(list[idx])) {
+ result[result.length] = list[idx];
+ }
+ idx += 1;
+ }
+ return result;
+}
+function _isObject(x) {
+ return Object.prototype.toString.call(x) === '[object Object]';
+}
+function XFilter(f, xf) {
+ this.xf = xf;
+ this.f = f;
+}
+XFilter.prototype['@@transducer/step'] = function(result, input) {
+ return this.f(input) ? this.xf['@@transducer/step'](result, input) : result;
+};
+function _isPlaceholder(a) {
+ return a != null && typeof a === 'object' && a['@@functional/placeholder'] === true;
+}
+function _arity(n, fn) {
+ switch(n){
+ case 0:
+ return function() {
+ return fn.apply(this, arguments);
+ };
+ case 1:
+ return function(a0) {
+ return fn.apply(this, arguments);
+ };
+ case 2:
+ return function(a0, a1) {
+ return fn.apply(this, arguments);
+ };
+ case 3:
+ return function(a0, a1, a2) {
+ return fn.apply(this, arguments);
+ };
+ case 4:
+ return function(a0, a1, a2, a3) {
+ return fn.apply(this, arguments);
+ };
+ case 5:
+ return function(a0, a1, a2, a3, a4) {
+ return fn.apply(this, arguments);
+ };
+ case 6:
+ return function(a0, a1, a2, a3, a4, a5) {
+ return fn.apply(this, arguments);
+ };
+ case 7:
+ return function(a0, a1, a2, a3, a4, a5, a6) {
+ return fn.apply(this, arguments);
+ };
+ case 8:
+ return function(a0, a1, a2, a3, a4, a5, a6, a7) {
+ return fn.apply(this, arguments);
+ };
+ case 9:
+ return function(a0, a1, a2, a3, a4, a5, a6, a7, a8) {
+ return fn.apply(this, arguments);
+ };
+ case 10:
+ return function(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) {
+ return fn.apply(this, arguments);
+ };
+ default:
+ throw new Error('First argument to _arity must be a non-negative integer no greater than ten');
+ }
+}
+function _map(fn, functor) {
+ var idx = 0;
+ var len = functor.length;
+ var result = Array(len);
+ while(idx < len){
+ result[idx] = fn(functor[idx]);
+ idx += 1;
+ }
+ return result;
+}
+function XWrap(fn) {
+ this.f = fn;
+}
+XWrap.prototype['@@transducer/init'] = function() {
+ throw new Error('init not implemented on XWrap');
+};
+XWrap.prototype['@@transducer/result'] = function(acc) {
+ return acc;
+};
+XWrap.prototype['@@transducer/step'] = function(acc, x) {
+ return this.f(acc, x);
+};
+function _xwrap(fn) {
+ return new XWrap(fn);
+}
+function _arrayReduce(xf, acc, list) {
+ var idx = 0;
+ var len = list.length;
+ while(idx < len){
+ acc = xf['@@transducer/step'](acc, list[idx]);
+ if (acc && acc['@@transducer/reduced']) {
+ acc = acc['@@transducer/value'];
+ break;
+ }
+ idx += 1;
+ }
+ return xf['@@transducer/result'](acc);
+}
+function _iterableReduce(xf, acc, iter) {
+ var step = iter.next();
+ while(!step.done){
+ acc = xf['@@transducer/step'](acc, step.value);
+ if (acc && acc['@@transducer/reduced']) {
+ acc = acc['@@transducer/value'];
+ break;
+ }
+ step = iter.next();
+ }
+ return xf['@@transducer/result'](acc);
+}
+var symIterator = typeof Symbol !== 'undefined' ? Symbol.iterator : '@@iterator';
+function _isTransformer(obj) {
+ return obj != null && typeof obj['@@transducer/step'] === 'function';
+}
+var toString1 = Object.prototype.toString;
+var hasEnumBug = !({
+ toString: null
+}).propertyIsEnumerable('toString');
+var nonEnumerableProps = [
+ 'constructor',
+ 'valueOf',
+ 'isPrototypeOf',
+ 'toString',
+ 'propertyIsEnumerable',
+ 'hasOwnProperty',
+ 'toLocaleString'
+];
+var hasArgsEnumBug = function() {
+ 'use strict';
+ return arguments.propertyIsEnumerable('length');
+}();
+var contains = function contains(list, item) {
+ var idx = 0;
+ while(idx < list.length){
+ if (list[idx] === item) {
+ return true;
+ }
+ idx += 1;
+ }
+ return false;
+};
+function _concat(set1, set2) {
+ set1 = set1 || [];
+ set2 = set2 || [];
+ var idx;
+ var len1 = set1.length;
+ var len2 = set2.length;
+ var result = [];
+ idx = 0;
+ while(idx < len1){
+ result[result.length] = set1[idx];
+ idx += 1;
+ }
+ idx = 0;
+ while(idx < len2){
+ result[result.length] = set2[idx];
+ idx += 1;
+ }
+ return result;
+}
+function _isString(x) {
+ return Object.prototype.toString.call(x) === '[object String]';
+}
+function _has(prop, obj) {
+ return Object.prototype.hasOwnProperty.call(obj, prop);
+}
+const __default2 = Array.isArray || function _isArray(val) {
+ return val != null && val.length >= 0 && Object.prototype.toString.call(val) === '[object Array]';
+};
+const __default3 = {
+ init: function() {
+ return this.xf['@@transducer/init']();
+ },
+ result: function(result) {
+ return this.xf['@@transducer/result'](result);
+ }
+};
+function _checkForMethod(methodname, fn) {
+ return function() {
+ var length = arguments.length;
+ if (length === 0) {
+ return fn();
+ }
+ var obj = arguments[length - 1];
+ return __default2(obj) || typeof obj[methodname] !== 'function' ? fn.apply(this, arguments) : obj[methodname].apply(obj, Array.prototype.slice.call(arguments, 0, length - 1));
+ };
+}
+const serializeTypeRepresentationBound = function() {
+ return serializeTypeRepresentation(this[$$type1]);
+};
+function _curry1(fn) {
+ return function f1(a) {
+ if (arguments.length === 0 || _isPlaceholder(a)) {
+ return f1;
+ } else {
+ return fn.apply(this, arguments);
+ }
+ };
+}
+function _curryN(length, received, fn) {
+ return function() {
+ var combined = [];
+ var argsIdx = 0;
+ var left = length;
+ var combinedIdx = 0;
+ while(combinedIdx < received.length || argsIdx < arguments.length){
+ var result;
+ if (combinedIdx < received.length && (!_isPlaceholder(received[combinedIdx]) || argsIdx >= arguments.length)) {
+ result = received[combinedIdx];
+ } else {
+ result = arguments[argsIdx];
+ argsIdx += 1;
+ }
+ combined[combinedIdx] = result;
+ if (!_isPlaceholder(result)) {
+ left -= 1;
+ }
+ combinedIdx += 1;
+ }
+ return left <= 0 ? fn.apply(this, combined) : _arity(left, _curryN(length, combined, fn));
+ };
+}
+XMap.prototype['@@transducer/init'] = __default3.init;
+XMap.prototype['@@transducer/result'] = __default3.result;
+var type = _curry1(function type(val) {
+ return val === null ? 'Null' : val === undefined ? 'Undefined' : Object.prototype.toString.call(val).slice(8, -1);
+});
+XFilter.prototype['@@transducer/init'] = __default3.init;
+XFilter.prototype['@@transducer/result'] = __default3.result;
+function _curry2(fn) {
+ return function f2(a, b) {
+ switch(arguments.length){
+ case 0:
+ return f2;
+ case 1:
+ return _isPlaceholder(a) ? f2 : _curry1(function(_b) {
+ return fn(a, _b);
+ });
+ default:
+ return _isPlaceholder(a) && _isPlaceholder(b) ? f2 : _isPlaceholder(a) ? _curry1(function(_a) {
+ return fn(_a, b);
+ }) : _isPlaceholder(b) ? _curry1(function(_b) {
+ return fn(a, _b);
+ }) : fn(a, b);
+ }
+ };
+}
+var _isArrayLike = _curry1(function isArrayLike(x) {
+ if (__default2(x)) {
+ return true;
+ }
+ if (!x) {
+ return false;
+ }
+ if (typeof x !== 'object') {
+ return false;
+ }
+ if (_isString(x)) {
+ return false;
+ }
+ if (x.length === 0) {
+ return true;
+ }
+ if (x.length > 0) {
+ return x.hasOwnProperty(0) && x.hasOwnProperty(x.length - 1);
+ }
+ return false;
+});
+var bind = _curry2(function bind(fn, thisObj) {
+ return _arity(fn.length, function() {
+ return fn.apply(thisObj, arguments);
+ });
+});
+function _methodReduce(xf, acc, obj, methodName) {
+ return xf['@@transducer/result'](obj[methodName](bind(xf['@@transducer/step'], xf), acc));
+}
+function _reduce(fn, acc, list) {
+ if (typeof fn === 'function') {
+ fn = _xwrap(fn);
+ }
+ if (_isArrayLike(list)) {
+ return _arrayReduce(fn, acc, list);
+ }
+ if (typeof list['fantasy-land/reduce'] === 'function') {
+ return _methodReduce(fn, acc, list, 'fantasy-land/reduce');
+ }
+ if (list[symIterator] != null) {
+ return _iterableReduce(fn, acc, list[symIterator]());
+ }
+ if (typeof list.next === 'function') {
+ return _iterableReduce(fn, acc, list);
+ }
+ if (typeof list.reduce === 'function') {
+ return _methodReduce(fn, acc, list, 'reduce');
+ }
+ throw new TypeError('reduce: list must be array or iterable');
+}
+function _dispatchable(methodNames, transducerCreator, fn) {
+ return function() {
+ if (arguments.length === 0) {
+ return fn();
+ }
+ var obj = arguments[arguments.length - 1];
+ if (!__default2(obj)) {
+ var idx = 0;
+ while(idx < methodNames.length){
+ if (typeof obj[methodNames[idx]] === 'function') {
+ return obj[methodNames[idx]].apply(obj, Array.prototype.slice.call(arguments, 0, -1));
+ }
+ idx += 1;
+ }
+ if (_isTransformer(obj)) {
+ var transducer = transducerCreator.apply(null, Array.prototype.slice.call(arguments, 0, -1));
+ return transducer(obj);
+ }
+ }
+ return fn.apply(this, arguments);
+ };
+}
+var _isArguments = function() {
+ return toString1.call(arguments) === '[object Arguments]' ? function _isArguments(x) {
+ return toString1.call(x) === '[object Arguments]';
+ } : function _isArguments(x) {
+ return _has('callee', x);
+ };
+}();
+var keys = typeof Object.keys === 'function' && !hasArgsEnumBug ? _curry1(function keys(obj) {
+ return Object(obj) !== obj ? [] : Object.keys(obj);
+}) : _curry1(function keys(obj) {
+ if (Object(obj) !== obj) {
+ return [];
+ }
+ var prop, nIdx;
+ var ks = [];
+ var checkArgsLength = hasArgsEnumBug && _isArguments(obj);
+ for(prop in obj){
+ if (_has(prop, obj) && (!checkArgsLength || prop !== 'length')) {
+ ks[ks.length] = prop;
+ }
+ }
+ if (hasEnumBug) {
+ nIdx = nonEnumerableProps.length - 1;
+ while(nIdx >= 0){
+ prop = nonEnumerableProps[nIdx];
+ if (_has(prop, obj) && !contains(ks, prop)) {
+ ks[ks.length] = prop;
+ }
+ nIdx -= 1;
+ }
+ }
+ return ks;
+});
+function _curry3(fn) {
+ return function f3(a, b, c) {
+ switch(arguments.length){
+ case 0:
+ return f3;
+ case 1:
+ return _isPlaceholder(a) ? f3 : _curry2(function(_b, _c) {
+ return fn(a, _b, _c);
+ });
+ case 2:
+ return _isPlaceholder(a) && _isPlaceholder(b) ? f3 : _isPlaceholder(a) ? _curry2(function(_a, _c) {
+ return fn(_a, b, _c);
+ }) : _isPlaceholder(b) ? _curry2(function(_b, _c) {
+ return fn(a, _b, _c);
+ }) : _curry1(function(_c) {
+ return fn(a, b, _c);
+ });
+ default:
+ return _isPlaceholder(a) && _isPlaceholder(b) && _isPlaceholder(c) ? f3 : _isPlaceholder(a) && _isPlaceholder(b) ? _curry2(function(_a, _b) {
+ return fn(_a, _b, c);
+ }) : _isPlaceholder(a) && _isPlaceholder(c) ? _curry2(function(_a, _c) {
+ return fn(_a, b, _c);
+ }) : _isPlaceholder(b) && _isPlaceholder(c) ? _curry2(function(_b, _c) {
+ return fn(a, _b, _c);
+ }) : _isPlaceholder(a) ? _curry1(function(_a) {
+ return fn(_a, b, c);
+ }) : _isPlaceholder(b) ? _curry1(function(_b) {
+ return fn(a, _b, c);
+ }) : _isPlaceholder(c) ? _curry1(function(_c) {
+ return fn(a, b, _c);
+ }) : fn(a, b, c);
+ }
+ };
+}
+var not = _curry1(function not(a) {
+ return !a;
+});
+var slice = _curry3(_checkForMethod('slice', function slice(fromIndex, toIndex, list) {
+ return Array.prototype.slice.call(list, fromIndex, toIndex);
+}));
+var tail = _curry1(_checkForMethod('tail', slice(1, Infinity)));
+var reverse = _curry1(function reverse(list) {
+ return _isString(list) ? list.split('').reverse().join('') : Array.prototype.slice.call(list, 0).reverse();
+});
+var max = _curry2(function max(a, b) {
+ return b > a ? b : a;
+});
+var isNil = _curry1(function isNil(x) {
+ return x == null;
+});
+var hasPath = _curry2(function hasPath(_path, obj) {
+ if (_path.length === 0 || isNil(obj)) {
+ return false;
+ }
+ var val = obj;
+ var idx = 0;
+ while(idx < _path.length){
+ if (!isNil(val) && _has(_path[idx], val)) {
+ val = val[_path[idx]];
+ idx += 1;
+ } else {
+ return false;
+ }
+ }
+ return true;
+});
+var has = _curry2(function has(prop, obj) {
+ return hasPath([
+ prop
+ ], obj);
+});
+var identity = _curry1(_identity);
+var zipObj = _curry2(function zipObj(keys1, values) {
+ var idx = 0;
+ var len = Math.min(keys1.length, values.length);
+ var out = {
+ };
+ while(idx < len){
+ out[keys1[idx]] = values[idx];
+ idx += 1;
+ }
+ return out;
+});
+var apply = _curry2(function apply(fn, args) {
+ return fn.apply(this, args);
+});
+var curryN = _curry2(function curryN(length, fn) {
+ if (length === 1) {
+ return _curry1(fn);
+ }
+ return _arity(length, _curryN(length, [], fn));
+});
+var _xmap = _curry2(function _xmap(f, xf) {
+ return new XMap(f, xf);
+});
+var map = _curry2(_dispatchable([
+ 'fantasy-land/map',
+ 'map'
+], _xmap, function map(fn, functor) {
+ switch(Object.prototype.toString.call(functor)){
+ case '[object Function]':
+ return curryN(functor.length, function() {
+ return fn.call(this, functor.apply(this, arguments));
+ });
+ case '[object Object]':
+ return _reduce(function(acc, key) {
+ acc[key] = fn(functor[key]);
+ return acc;
+ }, {
+ }, keys(functor));
+ default:
+ return _map(fn, functor);
+ }
+}));
+var nth = _curry2(function nth(offset, list) {
+ var idx = offset < 0 ? list.length + offset : offset;
+ return _isString(list) ? list.charAt(idx) : list[idx];
+});
+var prop = _curry2(function prop(p, obj) {
+ if (obj == null) {
+ return;
+ }
+ return __default4(p) ? nth(p, obj) : obj[p];
+});
+var reduce = _curry3(_reduce);
+var _xfilter = _curry2(function _xfilter(f, xf) {
+ return new XFilter(f, xf);
+});
+var filter = _curry2(_dispatchable([
+ 'fantasy-land/filter',
+ 'filter'
+], _xfilter, function(pred, filterable) {
+ return _isObject(filterable) ? _reduce(function(acc, key) {
+ if (pred(filterable[key])) {
+ acc[key] = filterable[key];
+ }
+ return acc;
+ }, {
+ }, keys(filterable)) : _filter(pred, filterable);
+}));
+var reject = _curry2(function reject(pred, filterable) {
+ return filter(_complement(pred), filterable);
+});
+var curry = _curry1(function curry(fn) {
+ return curryN(fn.length, fn);
+});
+function pipe() {
+ if (arguments.length === 0) {
+ throw new Error('pipe requires at least one argument');
+ }
+ return _arity(arguments[0].length, reduce(_pipe, arguments[0], tail(arguments)));
+}
+function compose() {
+ if (arguments.length === 0) {
+ throw new Error('compose requires at least one argument');
+ }
+ return pipe.apply(this, reverse(arguments));
+}
+var pluck = _curry2(function pluck(p, list) {
+ return map(prop(p), list);
+});
+var converge = _curry2(function converge(after, fns) {
+ return curryN(reduce(max, 0, pluck('length', fns)), function() {
+ var args = arguments;
+ var context = this;
+ return after.apply(context, _map(function(fn) {
+ return fn.apply(context, args);
+ }, fns));
+ });
+});
+const assertIsUnit = curry((instance, value)=>instance === value || !!value && instance[$$tag] === value[$$tag] && instance.constructor[$$type1] === value.constructor[$$type1]
+);
+const assertIsTypeRepresentation = curry((typeName, value)=>value !== undefined && value !== null && typeName === value.constructor[$$type1]
+);
+const assertIsVariant = curry((instance, value)=>!!value && instance[$$tag] === value[$$tag] && instance[$$returnType] === value.constructor[$$type1]
+);
+const serializeConstructorType = curry((typeName, tag)=>`${typeName}.${tag}`
+);
+const serializeConstructorTypeBound = function() {
+ return serializeConstructorType(this[$$returnType], this[$$tag]);
+};
+const factorizeFold = (functionByTag, instanceTag, constructorTagList)=>{
+ for (const tag of constructorTagList){
+ if (!functionByTag[tag]) {
+ throw new TypeError(`Constructors given to fold didn't include: ${tag}`);
+ }
+ }
+ return apply(functionByTag[instanceTag]);
+};
+const factorizeFoldBound = function(functionByTag) {
+ return factorizeFold(functionByTag, this[$$tag], this.constructor[$$tagList])(this[$$valueList]);
+};
+const factorizeValue = curry((propertyNameList, prototype, propertyValueList, argumentCount)=>{
+ if (argumentCount !== propertyNameList.length) {
+ throw new TypeError(`Expected ${propertyNameList.length} arguments, got ${argumentCount}.`);
+ }
+ return Object.assign(Object.create(prototype), {
+ ...zipObj(propertyNameList, propertyValueList),
+ [$$valueList]: propertyValueList
+ });
+});
+const factorizeConstructor = (propertyNameList, prototype)=>{
+ switch(propertyNameList.length){
+ case 1:
+ return function(a) {
+ return factorizeValue(propertyNameList, prototype, [
+ a
+ ], arguments.length);
+ };
+ case 2:
+ return function(a, b) {
+ return factorizeValue(propertyNameList, prototype, [
+ a,
+ b
+ ], arguments.length);
+ };
+ case 3:
+ return function(a, b, c) {
+ return factorizeValue(propertyNameList, prototype, [
+ a,
+ b,
+ c
+ ], arguments.length);
+ };
+ case 4:
+ return function(a, b, c, d) {
+ return factorizeValue(propertyNameList, prototype, [
+ a,
+ b,
+ c,
+ d
+ ], arguments.length);
+ };
+ case 5:
+ return function(a, b, c, d, e) {
+ return factorizeValue(propertyNameList, prototype, [
+ a,
+ b,
+ c,
+ d,
+ e
+ ], arguments.length);
+ };
+ case 6:
+ return function(a, b, c, d, e, f) {
+ return factorizeValue(propertyNameList, prototype, [
+ a,
+ b,
+ c,
+ d,
+ e,
+ f
+ ], arguments.length);
+ };
+ case 7:
+ return function(a, b, c, d, e, f, g) {
+ return factorizeValue(propertyNameList, prototype, [
+ a,
+ b,
+ c,
+ d,
+ e,
+ f,
+ g
+ ], arguments.length);
+ };
+ case 8:
+ return function(a, b, c, d, e, f, g, h) {
+ return factorizeValue(propertyNameList, prototype, [
+ a,
+ b,
+ c,
+ d,
+ e,
+ f,
+ g,
+ h
+ ], arguments.length);
+ };
+ case 9:
+ return function(a, b, c, d, e, f, g, h, i) {
+ return factorizeValue(propertyNameList, prototype, [
+ a,
+ b,
+ c,
+ d,
+ e,
+ f,
+ g,
+ h,
+ i
+ ], arguments.length);
+ };
+ case 10:
+ return function(a, b, c, d, e, f, g, h, i, j) {
+ return factorizeValue(propertyNameList, prototype, [
+ a,
+ b,
+ c,
+ d,
+ e,
+ f,
+ g,
+ h,
+ i,
+ j
+ ], arguments.length);
+ };
+ default:
+ return Object.defineProperty(function() {
+ return factorizeValue(propertyNameList, prototype, arguments, arguments.length);
+ }, 'length', {
+ value: propertyNameList.length
+ });
+ }
+};
+var ap = _curry2(function ap(applyF, applyX) {
+ return typeof applyX['fantasy-land/ap'] === 'function' ? applyX['fantasy-land/ap'](applyF) : typeof applyF.ap === 'function' ? applyF.ap(applyX) : typeof applyF === 'function' ? function(x) {
+ return applyF(x)(applyX(x));
+ } : _reduce(function(acc, f) {
+ return _concat(acc, map(f, applyX));
+ }, [], applyF);
+});
+var liftN = _curry2(function liftN(arity, fn) {
+ var lifted = curryN(arity, fn);
+ return curryN(arity, function() {
+ return _reduce(ap, map(lifted, arguments[0]), Array.prototype.slice.call(arguments, 1));
+ });
+});
+var lift = _curry1(function lift(fn) {
+ return liftN(fn.length, fn);
+});
+const chainLift = curry((binaryFunction, chainableFunctor, functor)=>chainableFunctor.chain((x)=>functor.map(binaryFunction(x))
+ )
+);
+var complement = lift(not);
+const factorizeConstructorFromObject = (propertyNameList, prototype)=>compose(converge(factorizeValue(propertyNameList, prototype), [
+ identity,
+ prop("length")
+ ]), (blueprintObject)=>reduce((accumulator, propertyName)=>{
+ if (complement(has)(propertyName, blueprintObject)) {
+ throw new TypeError(`Missing field: ${propertyName}`);
+ }
+ return [
+ ...accumulator,
+ blueprintObject[propertyName]
+ ];
+ }, [], propertyNameList)
+ )
+;
+Buffer.prototype.ap = Buffer.prototype["fantasy-land/ap"] = function(container) {
+ return Buffer.of(container.raw(this.raw));
+};
+Buffer.empty = Buffer.prototype.empty = Buffer.prototype["fantasy-land/empty"] = ()=>Buffer(new Uint8Array([]))
+;
+Buffer.fromString = (text)=>Buffer(new TextEncoder().encode(text))
+;
+Buffer.isOrThrow = (container)=>{
+ if (Buffer.is(container) || container.hasOwnProperty("raw") || Task1.is(container)) return container;
+ else throw new Error(`Expected a Buffer but got a "${container[$$type1] || typeof container}"`);
+};
+Buffer.prototype.concat = Buffer.prototype["fantasy-land/concat"] = function(container) {
+ return Buffer(new Uint8Array([
+ ...this.raw,
+ ...container.raw
+ ]));
+};
+Buffer.empty = Buffer.prototype.empty = Buffer.prototype["fantasy-land/empty"] = function() {
+ return Buffer(new Uint8Array([]));
+};
+Buffer.prototype.extend = Buffer.prototype["fantasy-land/extend"] = function(unaryFunction) {
+ return Buffer(unaryFunction(this));
+};
+Buffer.prototype.invert = Buffer.prototype["fantasy-land/invert"] = function() {
+ return Buffer(this.raw.reverse());
+};
+Buffer.prototype.map = Buffer.prototype["fantasy-land/map"] = function(unaryFunction) {
+ return Buffer(unaryFunction(this.raw));
+};
+Buffer.of = Buffer.prototype.of = Buffer.prototype["fantasy-land/of"] = (buffer)=>Buffer(buffer)
+;
+Request1.isOrThrow = (container)=>{
+ if (Request1.is(container)) return container;
+ else throw new Error(`Expected a Request but got a "${container[$$type] || typeof container}"`);
+};
+Request1.DELETE = Request1.delete = (url)=>Request1({
+ cache: "default",
+ headers: {
+ },
+ method: "DELETE",
+ mode: "cors",
+ url
+ }, new Uint8Array([]))
+;
+Request1.GET = Request1.get = (url)=>Request1({
+ cache: "default",
+ headers: {
+ },
+ method: "GET",
+ mode: "cors",
+ url
+ }, new Uint8Array([]))
+;
+Request1.POST = Request1.post = curry((url, _buffer)=>Request1({
+ cache: "default",
+ headers: {
+ "Content-Type": "application/json"
+ },
+ method: "POST",
+ mode: "cors",
+ url
+ }, _buffer)
+);
+Request1.PUT = Request1.put = curry((url, _buffer)=>Request1({
+ cache: "default",
+ headers: {
+ "Content-Type": "application/json"
+ },
+ method: "PUT",
+ mode: "cors",
+ url
+ }, _buffer)
+);
+Request1.prototype.ap = Request1.prototype["fantasy-land/ap"] = function(container) {
+ return Request1(this.headers, container.raw(this.raw));
+};
+Request1.prototype.bimap = Request1.prototype["fantasy-land/bimap"] = function(unaryFunctionA, unaryFunctionB) {
+ return Request1(unaryFunctionA(this.headers), unaryFunctionB(this.raw));
+};
+Request1.prototype.concat = Request1.prototype["fantasy-land/concat"] = function(container) {
+ return Request1(this.headers, new Uint8Array([
+ ...this.raw,
+ ...container.raw
+ ]));
+};
+Request1.empty = Request1.prototype.empty = Request1.prototype["fantasy-land/empty"] = ()=>Request1({
+ }, new Uint8Array([]))
+;
+Request1.isOrThrow = (container)=>{
+ if (Request1.is(container)) return container;
+ else throw new Error(`Expected a Request but got a "${container[$$type] || typeof container}"`);
+};
+Request1.prototype.invert = Request1.prototype["fantasy-land/invert"] = function() {
+ return Request1(this.headers, this.raw.reverse());
+};
+Request1.prototype.map = Request1.prototype["fantasy-land/map"] = function(unaryFunction) {
+ return Request1(this.headers, unaryFunction(this.raw));
+};
+Request1.of = Request1.prototype.of = Request1.prototype["fantasy-land/of"] = (raw)=>Request1({
+ }, raw)
+;
+Response1.OK = curry((headers, raw)=>Response1.Success({
+ ...headers,
+ status: 200
+ }, raw)
+);
+Response1.Created = curry((headers, raw)=>Response1.Success({
+ ...headers,
+ status: 201
+ }, raw)
+);
+Response1.Accepted = curry((headers, raw)=>Response1.Success({
+ ...headers,
+ status: 202
+ }, raw)
+);
+Response1.NoContent = curry((headers, raw)=>Response1.Success({
+ ...headers,
+ status: 204
+ }, raw)
+);
+Response1.MultipleChoice = curry((headers, error)=>Response1.Failure({
+ ...headers,
+ status: 300
+ }, error)
+);
+Response1.MovePermanently = curry((headers, error)=>Response1.Failure({
+ ...headers,
+ status: 301
+ }, error)
+);
+Response1.Found = curry((headers, error)=>Response1.Failure({
+ ...headers,
+ status: 302
+ }, error)
+);
+Response1.NotModified = curry((headers, error)=>Response1.Failure({
+ ...headers,
+ status: 304
+ }, error)
+);
+Response1.TemporaryRedirect = curry((headers, error)=>Response1.Failure({
+ ...headers,
+ status: 307
+ }, error)
+);
+Response1.PermanentRedirect = curry((headers, error)=>Response1.Failure({
+ ...headers,
+ status: 308
+ }, error)
+);
+Response1.BadRequest = curry((headers, error)=>Response1.Failure({
+ ...headers,
+ status: 400
+ }, error)
+);
+Response1.Unauthorized = curry((headers, error)=>Response1.Failure({
+ ...headers,
+ status: 401
+ }, error)
+);
+Response1.Forbidden = curry((headers, error)=>Response1.Failure({
+ ...headers,
+ status: 403
+ }, error)
+);
+Response1.NotFound = curry((headers, error)=>Response1.Failure({
+ ...headers,
+ status: 404
+ }, error)
+);
+Response1.MethodNotAllowed = curry((headers, error)=>Response1.Failure({
+ ...headers,
+ status: 405
+ }, error)
+);
+Response1.NotAcceptable = curry((headers, error)=>Response1.Failure({
+ ...headers,
+ status: 406
+ }, error)
+);
+Response1.RequestTimeout = curry((headers, error)=>Response1.Failure({
+ ...headers,
+ status: 408
+ }, error)
+);
+Response1.Conflict = curry((headers, error)=>Response1.Failure({
+ ...headers,
+ status: 409
+ }, error)
+);
+Response1.Gone = curry((headers, error)=>Response1.Failure({
+ ...headers,
+ status: 410
+ }, error)
+);
+Response1.ImATeapot = curry((headers, error)=>Response1.Failure({
+ ...headers,
+ status: 418
+ }, error)
+);
+Response1.InternalServerError = curry((headers, error)=>Response1.Failure({
+ ...headers,
+ status: 500
+ }, error)
+);
+Response1.NotImplemented = curry((headers, error)=>Response1.Failure({
+ ...headers,
+ status: 501
+ }, error)
+);
+Response1.BadGateway = curry((headers, error)=>Response1.Failure({
+ ...headers,
+ status: 502
+ }, error)
+);
+Response1.ServiceUnavailable = curry((headers, error)=>Response1.Failure({
+ ...headers,
+ status: 503
+ }, error)
+);
+Response1.GatewayTimeout = curry((headers, error)=>Response1.Failure({
+ ...headers,
+ status: 504
+ }, error)
+);
+Response1.PermissionDenied = curry((headers, error)=>Response1.Failure({
+ ...headers,
+ status: 550
+ }, error)
+);
+Response1.prototype.ap = Response1.prototype["fantasy-land/ap"] = function(container) {
+ return this.fold({
+ Failure: (_)=>this
+ ,
+ Success: (_)=>Response1.Success(this.headers, container.raw(this.raw))
+ });
+};
+Response1.prototype.bimap = Response1.prototype["fantasy-land/bimap"] = function(unaryFunctionA, unaryFunctionB) {
+ return this.fold({
+ Failure: (_)=>this
+ ,
+ Success: (_)=>Response1.Success(unaryFunctionA(this.headers), unaryFunctionB(this.raw))
+ });
+};
+Response1.prototype.concat = Response1.prototype["fantasy-land/concat"] = function(container) {
+ return this.fold({
+ Failure: (_)=>this
+ ,
+ Success: (_)=>Response1.Success(this.headers, new Uint8Array([
+ ...this.raw,
+ ...container.raw
+ ]))
+ });
+};
+Response1.empty = Response1.prototype.empty = Response1.prototype["fantasy-land/empty"] = ()=>Response1.Success({
+ }, new Uint8Array([]))
+;
+Response1.isOrThrow = (container)=>{
+ if (Response1.is(container)) return container;
+ else throw new Error(`Expected a Response but got a "${container[$$type] || typeof container}"`);
+};
+Response1.prototype.invert = Response1.prototype["fantasy-land/invert"] = function() {
+ return this.fold({
+ Failure: (_)=>this
+ ,
+ Success: (_)=>Response1.Success(this.headers, this.raw.reverse())
+ });
+};
+Response1.prototype.map = Response1.prototype["fantasy-land/map"] = function(unaryFunction) {
+ return this.fold({
+ Failure: (_)=>this
+ ,
+ Success: (_)=>Response1.Success(this.headers, unaryFunction(this.raw))
+ });
+};
+Response1.of = Response1.prototype.of = Response1.prototype["fantasy-land/of"] = (raw)=>Response1.Success({
+ }, raw)
+;
+Response1.zero = Response1.prototype.zero = Response1.prototype["fantasy-land/zero"] = ()=>Response1.Failure({
+ }, new Uint8Array([]))
+;
+URL1.prototype.ap = URL1.prototype["fantasy-land/ap"] = function(container) {
+ return URL1.of(container.path(this.path));
+};
+URL1.prototype.extend = URL1.prototype["fantasy-land/extend"] = function(unaryFunction) {
+ return URL1(unaryFunction(this));
+};
+URL1.fromPath = (path)=>URL1(path)
+;
+URL1.isOrThrow = (container)=>{
+ if (URL1.is(container) || container.hasOwnProperty("path") || Task2.is(container)) return container;
+ else throw new Error(`Expected a URL but got a "${container[$$type1] || typeof container}"`);
+};
+URL1.prototype.map = URL1.prototype["fantasy-land/map"] = function(unaryFunction) {
+ return URL1(unaryFunction(this.path));
+};
+URL1.of = URL1.prototype.of = URL1.prototype["fantasy-land/of"] = (path)=>URL1(path)
+;
+const pureFetch = (request)=>__default.isOrThrow(request) && Task3.wrap((_)=>fetch(request.headers.url, {
+ ...request.headers,
+ body: request.headers["Content-Type"] === "application/javascript" || /^application\/[a-z-\.]*\+*json$/.test(request.headers["Content-Type"]) || /^text\//.test(request.headers["Content-Type"]) ? decodeRaw(request.raw) : request.raw
+ })
+ ).chain(({ body , headers , status })=>apply(lift(status < 300 ? __default.Success : __default.Failure), [
+ Task3.of({
+ ...headers,
+ status
+ }),
+ Task3.wrap((_)=>coerceReadableStreamToUint8Array(body.getReader())
+ )
+ ])
+ )
+;
+export { pureFetch as fetch };
+var invoker = _curry2(function invoker(arity, method) {
+ return curryN(arity + 1, function() {
+ var target = arguments[arity];
+ if (target != null && _isFunction(target[method])) {
+ return target[method].apply(target, Array.prototype.slice.call(arguments, 0, arity));
+ }
+ throw new TypeError(toString3(target) + ' does not have a method named "' + method + '"');
+ });
+});
+var join = invoker(1, 'join');
+const serializeTypeInstance = curry((typeName, valueList)=>`${typeName}(${serializeList(valueList)})`
+);
+const serializeTypeInstanceWithTag = curry((typeName, tagName, valueList)=>valueList.length > 0 ? `${typeName}.${tagName}(${serializeList(valueList)})` : `${typeName}.${tagName}`
+);
+const serializeTypeInstanceBound = function() {
+ return Object.getPrototypeOf(this).hasOwnProperty($$tag) ? serializeTypeInstanceWithTag(this.constructor[$$type1], this[$$tag], this[$$valueList]) : serializeTypeInstance(this.constructor[$$type1], this[$$valueList]);
+};
+const factorizeType = (typeName, propertyNameList)=>{
+ let prototypeAccumulator = {
+ toString: serializeTypeInstanceBound,
+ [$$inspect]: serializeTypeInstanceBound,
+ [$$type1]: typeName
+ };
+ const typeRepresentationConstructor = factorizeConstructor(propertyNameList, prototypeAccumulator);
+ typeRepresentationConstructor.from = factorizeConstructorFromObject(propertyNameList, prototypeAccumulator);
+ typeRepresentationConstructor.is = assertIsTypeRepresentation(typeName);
+ typeRepresentationConstructor.prototype = prototypeAccumulator;
+ typeRepresentationConstructor.toString = serializeTypeRepresentationBound;
+ typeRepresentationConstructor[$$inspect] = serializeTypeRepresentationBound;
+ typeRepresentationConstructor[$$type1] = typeName;
+ prototypeAccumulator.constructor = typeRepresentationConstructor;
+ return typeRepresentationConstructor;
+};
+const factorizeSumType = (typeName, propertyNameListByTag)=>{
+ let prototypeAccumulator = {
+ fold: factorizeFoldBound,
+ toString: serializeTypeInstanceBound,
+ [$$inspect]: serializeTypeInstanceBound
+ };
+ const tagList = Object.keys(propertyNameListByTag);
+ const typeRepresentation = prototypeAccumulator.constructor = {
+ is: assertIsTypeRepresentation(typeName),
+ prototype: prototypeAccumulator,
+ toString: serializeTypeRepresentationBound,
+ [$$inspect]: serializeTypeRepresentationBound,
+ [$$tagList]: tagList,
+ [$$type1]: typeName
+ };
+ for (const [tag, propertyNameList] of Object.entries(propertyNameListByTag)){
+ const tagPrototypeAccumulator = Object.assign(Object.create(prototypeAccumulator), {
+ [$$tag]: tag
+ });
+ if (propertyNameList.length === 0) {
+ typeRepresentation[tag] = factorizeValue(propertyNameList, tagPrototypeAccumulator, [], 0);
+ typeRepresentation[tag].is = assertIsUnit(typeRepresentation[tag]);
+ continue;
+ }
+ typeRepresentation[tag] = factorizeConstructor(propertyNameList, tagPrototypeAccumulator);
+ typeRepresentation[tag].from = factorizeConstructorFromObject(propertyNameList, tagPrototypeAccumulator);
+ typeRepresentation[tag].toString = serializeConstructorTypeBound;
+ typeRepresentation[tag][$$inspect] = serializeConstructorTypeBound;
+ typeRepresentation[tag][$$returnType] = typeName;
+ typeRepresentation[tag][$$tag] = tag;
+ typeRepresentation[tag].is = assertIsVariant(typeRepresentation[tag]);
+ }
+ return typeRepresentation;
+};
+const Either = factorizeSumType("Either", {
+ Left: [
+ $$value
+ ],
+ Right: [
+ $$value
+ ]
+});
+Either.fromNullable = (value)=>!(typeof value !== "undefined") || !value && typeof value === "object" ? Either.Left(value) : Either.Right(value)
+;
+Either.left = (value)=>Either.Left(value)
+;
+Either.right = (value)=>Either.Right(value)
+;
+Either.of = Either.prototype.of = Either.prototype["fantasy-land/of"] = (value)=>Either.Right(value)
+;
+Either.prototype.ap = Either.prototype["fantasy-land/ap"] = function(container) {
+ return this.fold({
+ Left: (_)=>this
+ ,
+ Right: (value)=>Either.Right.is(container) ? Either.Right(container[$$value](value)) : container
+ });
+};
+Either.prototype.extend = Either.prototype["fantasy-land/extend"] = function(unaryFunction) {
+ return this.fold({
+ Left: (_)=>this
+ ,
+ Right: (_)=>Either.of(unaryFunction(this))
+ });
+};
+Either.prototype.map = Either.prototype["fantasy-land/map"] = function(unaryFunction) {
+ return this.fold({
+ Left: (_)=>this
+ ,
+ Right: (value)=>Either.of(unaryFunction(value))
+ });
+};
+Either.prototype.traverse = Either.prototype["fantasy-land/traverse"] = function(TypeRepresentation, unaryFunction) {
+ return this.fold({
+ Left: (value)=>TypeRepresentation.of(Either.Left(value))
+ ,
+ Right: (value)=>unaryFunction(value).map((x)=>Either.Right(x)
+ )
+ });
+};
+Either.zero = Either.prototype.zero = Either.prototype["fantasy-land/zero"] = ()=>Either.Left(null)
+;
+const Pair = factorizeType("Pair", [
+ "first",
+ "second"
+]);
+Pair.prototype.bimap = Pair.prototype["fantasy-land/bimap"] = function(unaryFunctionA, unaryFunctionB) {
+ return Pair(unaryFunctionA(this.first), unaryFunctionB(this.second));
+};
+Pair.prototype.map = Pair.prototype["fantasy-land/map"] = function(unaryFunction) {
+ return Pair(unaryFunction(this.first), this.second);
+};
+const Step = factorizeSumType("Step", {
+ Done: [
+ 'value'
+ ],
+ Loop: [
+ 'value'
+ ]
+});
+const Done = Step.Done;
+const Loop = Step.Loop;
+const Task = factorizeType("Task", [
+ "asyncFunction"
+]);
+Task.wrap = (asyncFunction)=>{
+ let promise;
+ const proxyFunction = function(...argumentList) {
+ promise = promise || asyncFunction.call(null, ...argumentList);
+ return promise.then((maybeContainer)=>Either.is(maybeContainer) ? maybeContainer : Either.Right(maybeContainer)
+ , (maybeContainer)=>Either.is(maybeContainer) ? maybeContainer : Either.Left(maybeContainer)
+ );
+ };
+ return Object.defineProperty(Task(Object.defineProperty(proxyFunction, 'length', {
+ value: asyncFunction.length
+ })), $$debug, {
+ writable: false,
+ value: `Task(${serializeFunctionForDebug(asyncFunction)})`
+ });
+};
+Task.prototype.ap = Task.prototype["fantasy-land/ap"] = function(container) {
+ return Object.defineProperty(Task((_)=>{
+ const maybePromiseValue = this.asyncFunction();
+ const maybePromiseUnaryFunction = container.asyncFunction();
+ return Promise.all([
+ maybePromiseUnaryFunction instanceof Promise ? maybePromiseUnaryFunction : Promise.resolve(maybePromiseUnaryFunction),
+ maybePromiseValue instanceof Promise ? maybePromiseValue : Promise.resolve(maybePromiseValue)
+ ]).then(([maybeApplicativeUnaryFunction, maybeContainerValue])=>{
+ return (Reflect.getPrototypeOf(maybeContainerValue).ap ? maybeContainerValue : Either.Right(maybeContainerValue)).ap(Reflect.getPrototypeOf(maybeApplicativeUnaryFunction).ap ? maybeApplicativeUnaryFunction : Either.Right(maybeApplicativeUnaryFunction));
+ });
+ }), $$debug, {
+ writable: false,
+ value: `${this[$$debug]}.ap(${container})`
+ });
+};
+Task.prototype.chain = Task.prototype["fantasy-land/chain"] = function(unaryFunction) {
+ return Object.defineProperty(Task((_)=>{
+ const maybePromise = this.asyncFunction();
+ return (maybePromise instanceof Promise ? maybePromise : Promise.resolve(maybePromise)).then((maybeContainer)=>(Either.is(maybeContainer) ? maybeContainer : Either.Right(maybeContainer)).chain((value)=>{
+ const maybePromise1 = unaryFunction(value).run();
+ return (maybePromise1 instanceof Promise ? maybePromise1 : Promise.resolve(maybePromise1)).then((maybeContainer1)=>Either.is(maybeContainer1) ? maybeContainer1 : Either.Right(maybeContainer1)
+ , (maybeContainer1)=>Either.is(maybeContainer1) ? maybeContainer1 : Either.Left(maybeContainer1)
+ );
+ })
+ , Either.Left);
+ }), $$debug, {
+ writable: false,
+ value: `${this[$$debug]}.chain(${serializeFunctionForDebug(unaryFunction)})`
+ });
+};
+Task.prototype.chainRec = Task.prototype["fantasy-land/chainRec"] = function(ternaryFunction, initialCursor) {
+ let accumulator = this;
+ let result = Loop(Pair(initialCursor, null));
+ while(!Done.is(result)){
+ result = ternaryFunction(Loop, Done, result.value.first);
+ if (Loop.is(result)) {
+ accumulator = chainLift(concat, accumulator, result.value.second);
+ }
+ }
+ return accumulator;
+};
+Task.prototype.map = Task.prototype["fantasy-land/map"] = function(unaryFunction) {
+ return Object.defineProperty(Task((_)=>{
+ const promise = this.asyncFunction();
+ return promise.then((container)=>container.chain((value)=>{
+ const maybeContainer = unaryFunction(value);
+ return Either.is(maybeContainer) ? maybeContainer : Either.Right(maybeContainer);
+ })
+ , Either.Left);
+ }), $$debug, {
+ writable: false,
+ value: `${this[$$debug]}.map(${serializeFunctionForDebug(unaryFunction)})`
+ });
+};
+Task.of = Task.prototype.of = Task.prototype["fantasy-land/of"] = (value)=>Object.defineProperty(Task((_)=>Promise.resolve(Either.Right(value))
+ ), $$debug, {
+ writable: false,
+ value: `Task(${serializeFunctionForDebug(value)})`
+ })
+;
+Task.prototype.run = async function() {
+ const maybePromise = this.asyncFunction();
+ return (maybePromise instanceof Promise ? maybePromise : Promise.resolve(maybePromise)).then((maybeContainer)=>Either.is(maybeContainer) ? maybeContainer : Either.Right(maybeContainer)
+ , (maybeContainer)=>Either.is(maybeContainer) ? maybeContainer : Either.Left(maybeContainer)
+ );
+};
+function _uniqContentEquals(aIterator, bIterator, stackA, stackB) {
+ var a = _arrayFromIterator(aIterator);
+ var b = _arrayFromIterator(bIterator);
+ function eq(_a, _b) {
+ return _equals(_a, _b, stackA.slice(), stackB.slice());
+ }
+ return !_includesWith(function(b1, aItem) {
+ return !_includesWith(eq, aItem, b1);
+ }, b, a);
+}
+function _equals(a, b, stackA, stackB) {
+ if (__default1(a, b)) {
+ return true;
+ }
+ var typeA = type(a);
+ if (typeA !== type(b)) {
+ return false;
+ }
+ if (typeof a['fantasy-land/equals'] === 'function' || typeof b['fantasy-land/equals'] === 'function') {
+ return typeof a['fantasy-land/equals'] === 'function' && a['fantasy-land/equals'](b) && typeof b['fantasy-land/equals'] === 'function' && b['fantasy-land/equals'](a);
+ }
+ if (typeof a.equals === 'function' || typeof b.equals === 'function') {
+ return typeof a.equals === 'function' && a.equals(b) && typeof b.equals === 'function' && b.equals(a);
+ }
+ switch(typeA){
+ case 'Arguments':
+ case 'Array':
+ case 'Object':
+ if (typeof a.constructor === 'function' && _functionName(a.constructor) === 'Promise') {
+ return a === b;
+ }
+ break;
+ case 'Boolean':
+ case 'Number':
+ case 'String':
+ if (!(typeof a === typeof b && __default1(a.valueOf(), b.valueOf()))) {
+ return false;
+ }
+ break;
+ case 'Date':
+ if (!__default1(a.valueOf(), b.valueOf())) {
+ return false;
+ }
+ break;
+ case 'Error':
+ return a.name === b.name && a.message === b.message;
+ case 'RegExp':
+ if (!(a.source === b.source && a.global === b.global && a.ignoreCase === b.ignoreCase && a.multiline === b.multiline && a.sticky === b.sticky && a.unicode === b.unicode)) {
+ return false;
+ }
+ break;
+ }
+ var idx = stackA.length - 1;
+ while(idx >= 0){
+ if (stackA[idx] === a) {
+ return stackB[idx] === b;
+ }
+ idx -= 1;
+ }
+ switch(typeA){
+ case 'Map':
+ if (a.size !== b.size) {
+ return false;
+ }
+ return _uniqContentEquals(a.entries(), b.entries(), stackA.concat([
+ a
+ ]), stackB.concat([
+ b
+ ]));
+ case 'Set':
+ if (a.size !== b.size) {
+ return false;
+ }
+ return _uniqContentEquals(a.values(), b.values(), stackA.concat([
+ a
+ ]), stackB.concat([
+ b
+ ]));
+ case 'Arguments':
+ case 'Array':
+ case 'Object':
+ case 'Boolean':
+ case 'Number':
+ case 'String':
+ case 'Date':
+ case 'Error':
+ case 'RegExp':
+ case 'Int8Array':
+ case 'Uint8Array':
+ case 'Uint8ClampedArray':
+ case 'Int16Array':
+ case 'Uint16Array':
+ case 'Int32Array':
+ case 'Uint32Array':
+ case 'Float32Array':
+ case 'Float64Array':
+ case 'ArrayBuffer': break;
+ default:
+ return false;
+ }
+ var keysA = keys(a);
+ if (keysA.length !== keys(b).length) {
+ return false;
+ }
+ var extendedStackA = stackA.concat([
+ a
+ ]);
+ var extendedStackB = stackB.concat([
+ b
+ ]);
+ idx = keysA.length - 1;
+ while(idx >= 0){
+ var key = keysA[idx];
+ if (!(_has(key, b) && _equals(b[key], a[key], extendedStackA, extendedStackB))) {
+ return false;
+ }
+ idx -= 1;
+ }
+ return true;
+}
+var equals = _curry2(function equals(a, b) {
+ return _equals(a, b, [], []);
+});
+function _indexOf(list, a, idx) {
+ var inf, item;
+ if (typeof list.indexOf === 'function') {
+ switch(typeof a){
+ case 'number':
+ if (a === 0) {
+ inf = 1 / a;
+ while(idx < list.length){
+ item = list[idx];
+ if (item === 0 && 1 / item === inf) {
+ return idx;
+ }
+ idx += 1;
+ }
+ return -1;
+ } else if (a !== a) {
+ while(idx < list.length){
+ item = list[idx];
+ if (typeof item === 'number' && item !== item) {
+ return idx;
+ }
+ idx += 1;
+ }
+ return -1;
+ }
+ return list.indexOf(a, idx);
+ case 'string':
+ case 'boolean':
+ case 'function':
+ case 'undefined':
+ return list.indexOf(a, idx);
+ case 'object':
+ if (a === null) {
+ return list.indexOf(a, idx);
+ }
+ }
+ }
+ while(idx < list.length){
+ if (equals(list[idx], a)) {
+ return idx;
+ }
+ idx += 1;
+ }
+ return -1;
+}
+function _includes(a, list) {
+ return _indexOf(list, a, 0) >= 0;
+}
+function _toString(x, seen) {
+ var recur = function recur(y) {
+ var xs = seen.concat([
+ x
+ ]);
+ return _includes(y, xs) ? '' : _toString(y, xs);
+ };
+ var mapPairs = function(obj, keys1) {
+ return _map(function(k) {
+ return _quote(k) + ': ' + recur(obj[k]);
+ }, keys1.slice().sort());
+ };
+ switch(Object.prototype.toString.call(x)){
+ case '[object Arguments]':
+ return '(function() { return arguments; }(' + _map(recur, x).join(', ') + '))';
+ case '[object Array]':
+ return '[' + _map(recur, x).concat(mapPairs(x, reject(function(k) {
+ return /^\d+$/.test(k);
+ }, keys(x)))).join(', ') + ']';
+ case '[object Boolean]':
+ return typeof x === 'object' ? 'new Boolean(' + recur(x.valueOf()) + ')' : x.toString();
+ case '[object Date]':
+ return 'new Date(' + (isNaN(x.valueOf()) ? recur(NaN) : _quote(_toISOString(x))) + ')';
+ case '[object Null]':
+ return 'null';
+ case '[object Number]':
+ return typeof x === 'object' ? 'new Number(' + recur(x.valueOf()) + ')' : 1 / x === -Infinity ? '-0' : x.toString(10);
+ case '[object String]':
+ return typeof x === 'object' ? 'new String(' + recur(x.valueOf()) + ')' : _quote(x);
+ case '[object Undefined]':
+ return 'undefined';
+ default:
+ if (typeof x.toString === 'function') {
+ var repr = x.toString();
+ if (repr !== '[object Object]') {
+ return repr;
+ }
+ }
+ return '{' + mapPairs(x, keys(x)).join(', ') + '}';
+ }
+}
+var toString2 = _curry1(function toString2(val) {
+ return _toString(val, []);
+});
+const Task1 = Task;
+export const Buffer = factorizeType("Buffer", [
+ "raw"
+]);
+export const factorizeBuffer = curry(Buffer);
+export default Buffer;
+const Request1 = factorizeType("Request", [
+ "headers",
+ "raw"
+]);
+export { Request1 as Request };
+export default Request1;
+const Response1 = factorizeSumType("Response", {
+ Failure: [
+ "headers",
+ "raw"
+ ],
+ Success: [
+ "headers",
+ "raw"
+ ]
+});
+export { Response1 as Response };
+export default Response1;
+const Task2 = Task;
+const URL1 = factorizeType("URL", [
+ "path"
+]);
+export { URL1 as URL };
+export default URL1;
+const Task3 = Task;
+const toString3 = toString2;
+const serializeList = compose(join(", "), map(toString2));
diff --git a/library/Buffer.js b/library/Buffer.js
index 1b9d00a..47476a8 100644
--- a/library/Buffer.js
+++ b/library/Buffer.js
@@ -1,9 +1,11 @@
-import { curry } from "https://x.nest.land/ramda@0.27.0/source/index.js";
-import { factorizeType } from "https://deno.land/x/functional@v1.2.1/library/factories.js";
-import { $$type } from "https://deno.land/x/functional@v1.2.1/library/Symbols.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import curry from "https://deno.land/x/ramda@v0.27.2/source/curry.js";
+import { factorizeType } from "https://deno.land/x/functional@v1.3.2/library/factories.js";
+import { $$type } from "https://deno.land/x/functional@v1.3.2/library/Symbols.js";
+import Task from "https://deno.land/x/functional@v1.3.2/library/Task.js";
/**
+ * ## Buffer
+ *
* The `Buffer` is the most basic type; it only has one attribute which is a typed array named "raw".
* Any type that share the raw attribute is composable with `Buffer` (and each other) and interoperable.
*
@@ -15,7 +17,9 @@ import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
* ### Example
*
* ```js
- * const buffer = Buffer.fromString("Hoge").concat(Buffer.fromString("Fuga"));
+ * import Buffer from "https://deno.land/x/functional_io@v1.1.0/library/Buffer.js";
+ *
+ * const buffer = Buffer.fromString("hoge").concat(Buffer.fromString("fuga"));
*
* assert(Buffer.is(buffer));
* ```
diff --git a/library/Directory.js b/library/Directory.js
index b8c67b5..173e059 100644
--- a/library/Directory.js
+++ b/library/Directory.js
@@ -1,9 +1,11 @@
-import { factorizeType } from "https://deno.land/x/functional@v1.2.1/library/factories.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import { factorizeType } from "https://deno.land/x/functional@v1.3.2/library/factories.js";
+import Task from "https://deno.land/x/functional@v1.3.2/library/Task.js";
-import { $$type } from "https://deno.land/x/functional@v1.2.1/library/Symbols.js";
+import { $$type } from "https://deno.land/x/functional@v1.3.2/library/Symbols.js";
/**
+ * ## Directory
+ *
* The `Directory` type represents a directory on the file system. It is the only type with the same shape as `URL`.
* It has only one attributes: the path of the directory.
* A `Directory` is interoperable with a `URL` or a `File`.
diff --git a/library/File.js b/library/File.js
index 0ccf4ce..b0db648 100644
--- a/library/File.js
+++ b/library/File.js
@@ -1,9 +1,12 @@
-import { factorizeType } from "https://deno.land/x/functional@v1.2.1/library/factories.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import curry from "https://deno.land/x/ramda@v0.27.2/source/curry.js";
+import { factorizeType } from "https://deno.land/x/functional@v1.3.2/library/factories.js";
+import Task from "https://deno.land/x/functional@v1.3.2/library/Task.js";
-import { $$type } from "https://deno.land/x/functional@v1.2.1/library/Symbols.js";
+import { $$type } from "https://deno.land/x/functional@v1.3.2/library/Symbols.js";
/**
+ * ## File
+ *
* The `File` type extends the `Resource` type. It represents a file with a path.
* It has three attributes: the first is the path of the file, the second is a typed array named "raw" and the last
* is the Resource ID (`rid`).
@@ -104,4 +107,6 @@ File.prototype.map = File.prototype["fantasy-land/map"] = function (unaryFunctio
File.of = File.prototype.of = File.prototype["fantasy-land/of"] = raw => File("", raw, 0);
+export const factorizeFile = curry(File);
+
export default File;
diff --git a/library/FileSystemCollection.js b/library/FileSystemCollection.js
index ce1dbee..8930978 100644
--- a/library/FileSystemCollection.js
+++ b/library/FileSystemCollection.js
@@ -1,8 +1,10 @@
-import { factorizeType } from "https://deno.land/x/functional@v1.2.1/library/factories.js";
+import { factorizeType } from "https://deno.land/x/functional@v1.3.2/library/factories.js";
-import { $$value } from "https://deno.land/x/functional@v1.2.1/library/Symbols.js";
+import { $$value } from "https://deno.land/x/functional@v1.3.2/library/Symbols.js";
/**
+ * ## File System Collection
+ *
* The `FileSystemCollection` is represents a collection of `Location`, namely of `Directory` and `File`. This of it
* as an Array for those types.
*
diff --git a/library/Request.js b/library/Request.js
index 8c613cc..7cdef96 100644
--- a/library/Request.js
+++ b/library/Request.js
@@ -1,8 +1,10 @@
-import { curry } from "https://x.nest.land/ramda@0.27.0/source/index.js";
+import curry from "https://deno.land/x/ramda@v0.27.2/source/curry.js";
-import { factorizeType } from "https://deno.land/x/functional@v1.2.1/library/factories.js";
+import { factorizeType } from "https://deno.land/x/functional@v1.3.2/library/factories.js";
/**
+ * ## Request
+ *
* The `Request` represent a HTTP request.
* It has two attributes: the first is an object for the response "header" and the second is a typed array named "raw".
* The `Request` type is mostly interoperable with `Resource`, `File` and `Response`.
diff --git a/library/Resource.js b/library/Resource.js
index dd77215..2de1609 100644
--- a/library/Resource.js
+++ b/library/Resource.js
@@ -1,10 +1,12 @@
-import { curry } from "https://x.nest.land/ramda@0.27.0/source/index.js";
-import { factorizeType } from "https://deno.land/x/functional@v1.2.1/library/factories.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import curry from "https://deno.land/x/ramda@v0.27.2/source/curry.js";
+import { factorizeType } from "https://deno.land/x/functional@v1.3.2/library/factories.js";
+import Task from "https://deno.land/x/functional@v1.3.2/library/Task.js";
-import { $$type } from "https://deno.land/x/functional@v1.2.1/library/Symbols.js";
+import { $$type } from "https://deno.land/x/functional@v1.3.2/library/Symbols.js";
/**
+ * ## Resource
+ *
* The `Resource` type extends the `Buffer` type. It represents a system resource with a handle, eg: STDOUT, STDIN or a
* file. It has two attributes: the first is a typed array named "raw" and the second is the Resource ID (`rid`).
* Any type that share the `Resource` attributes is composable and interoperable.
diff --git a/library/Response.js b/library/Response.js
index 357a2e9..9c2ca1e 100644
--- a/library/Response.js
+++ b/library/Response.js
@@ -1,8 +1,10 @@
-import { curry } from "https://x.nest.land/ramda@0.27.0/source/index.js";
+import curry from "https://deno.land/x/ramda@v0.27.2/source/curry.js";
-import { factorizeSumType } from "https://deno.land/x/functional@v1.2.1/library/factories.js";
+import { factorizeSumType } from "https://deno.land/x/functional@v1.3.2/library/factories.js";
/**
+ * ## Response
+ *
* The `Response` represent a HTTP response.
* It has two attributes: the first is an object for the response "header" and the second is a typed array named "raw".
* The `Response` type is mostly interoperable with `Resource`, `File` and `Request`.
diff --git a/library/URL.js b/library/URL.js
index 5a15bb2..27336f8 100644
--- a/library/URL.js
+++ b/library/URL.js
@@ -1,9 +1,11 @@
-import { factorizeType } from "https://deno.land/x/functional@v1.2.1/library/factories.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import { factorizeType } from "https://deno.land/x/functional@v1.3.2/library/factories.js";
+import Task from "https://deno.land/x/functional@v1.3.2/library/Task.js";
-import { $$type } from "https://deno.land/x/functional@v1.2.1/library/Symbols.js";
+import { $$type } from "https://deno.land/x/functional@v1.3.2/library/Symbols.js";
/**
+ * ## URL
+ *
* The `URL` type represents an URL; either of a location on the file system or on a remote server.
* It has only one attributes: the path of the URL.
* A `URL` is interoperable with a `File` or a `Directory`.
@@ -51,7 +53,7 @@ URL.prototype.extract = URL.prototype["fantasy-land/extract"] = function () {
URL.fromPath = path => URL(path);
URL.isOrThrow = container => {
- if (URL.is(container) || Task.is(container)) return container;
+ if (URL.is(container) || container.hasOwnProperty("path") || Task.is(container)) return container;
else throw new Error(`Expected a URL but got a "${container[$$type] || typeof container}"`);
};
diff --git a/library/browser_safe.js b/library/browser_safe.js
index 33c0442..8540f8f 100644
--- a/library/browser_safe.js
+++ b/library/browser_safe.js
@@ -1,10 +1,16 @@
-import { apply, lift } from "https://x.nest.land/ramda@0.27.0/source/index.js";
+import apply from "https://deno.land/x/ramda@v0.27.2/source/apply.js";
+import lift from "https://deno.land/x/ramda@v0.27.2/source/lift.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import Task from "https://deno.land/x/functional@v1.3.2/library/Task.js";
+import { decodeRaw } from "https://deno.land/x/functional@v1.3.2/library/utilities.js";
import Request from "./Request.js";
import Response from "./Response.js";
+/**
+ * ## Browser safe
+ */
+
const coerceReadableStreamToUint8Array = async readableStream => {
let _array = new Uint8Array([]);
@@ -17,7 +23,24 @@ const coerceReadableStreamToUint8Array = async readableStream => {
});
}
-// fetch :: Request -> Task e Response
+/**
+ * ### `pureFetch`
+ * `Request -> Task e Response`
+ *
+ * Fetches a resource on a local/remote server.
+ *
+ * ```js
+ * import { fetch } from "https://deno.land/x/functional_io@v1.1.0/library/browser-safe.js";
+ *
+ * const containerA = fetch(Request.GET("http://localhost:8000"));
+ *
+ * assert(Task.is(containerA));
+ *
+ * const containerB = await container.run().extract();
+ *
+ * assert(Response.Success.is(containerB));
+ * ```
+ */
const pureFetch = request => Request.isOrThrow(request)
&& Task.wrap(_ =>
fetch(
@@ -29,7 +52,7 @@ const pureFetch = request => Request.isOrThrow(request)
|| /^application\/[a-z-\.]*\+*json$/.test(request.headers["Content-Type"])
|| /^text\//.test(request.headers["Content-Type"])
)
- ? new TextDecoder().decode(request.raw)
+ ? decodeRaw(request.raw)
: request.raw
}
)
diff --git a/library/browser_safe_test.js b/library/browser_safe_test.js
index d1dd8e7..2a516e5 100644
--- a/library/browser_safe_test.js
+++ b/library/browser_safe_test.js
@@ -2,8 +2,8 @@ import { assert } from "https://deno.land/std@0.79.0/testing/asserts.ts";
import { serve } from "https://deno.land/std@0.79.0/http/server.ts";
import { fetch } from "./browser_safe.js";
-import Either from "https://deno.land/x/functional@v1.2.1/library/Either.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js";
+import Either from "https://deno.land/x/functional@v1.3.2/library/Either.js";
+import Task from "https://deno.land/x/functional@v1.3.2/library/Task.js";
import Request from "./Request.js";
const startAsyncIterator = async (state, server, callback) => {
diff --git a/library/fs.js b/library/fs.js
index 91ab770..ace7fcd 100644
--- a/library/fs.js
+++ b/library/fs.js
@@ -5,45 +5,133 @@ import {
exists as _exists,
move as _move
} from "https://deno.land/std@0.79.0/fs/mod.ts";
-import { compose, curry } from "https://x.nest.land/ramda@0.27.0/source/index.js";
-import Either from "https://deno.land/x/functional@v1.2.1/library/Either.js"
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js"
+import { compose, curry } from "https://deno.land/x/ramda@v0.27.2/mod.ts";
+import Either from "https://deno.land/x/functional@v1.3.2/library/Either.js"
+import Task from "https://deno.land/x/functional@v1.3.2/library/Task.js"
import Buffer from "./Buffer.js";
import Directory from "./Directory.js";
import File from "./File.js";
import Resource from "./Resource.js";
+import URL from "./URL.js";
import { coerceAsReader, coerceAsWriter, factorizeUint8Array } from "./utilities.js";
-// chdir :: Directory a -> Task e Directory a
+/**
+ * ## File System
+ *
+ * **⚠️ Note** `Deno.cwd` is used in the following example; if you use `Deno.cwd` to compose your paths, your functions
+ * are no longer pure.
+ */
+
+/**
+ * ### `chdir` [📕](https://doc.deno.land/builtin/stable#Deno.chdir)
+ * `Directory -> Task e Directory`
+ *
+ * Change the current working directory to the specified path.
+ *
+ * ```js
+ * import { chdir } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+ *
+ * const container = chdir(Directory(".."));
+ *
+ * assert(Task.is(container));
+ * ```
+ */
export const chdir = directory => Directory.isOrThrow(directory)
&& Task.wrap(_ => Deno.chdir(directory.path) || Promise.resolve(undefined))
.map(_ => Directory(directory.path));
-// chmod :: Number -> File a -> Task e File a
+/**
+ * ### `chmod` [📕](https://doc.deno.land/builtin/stable#Deno.chmod)
+ * `Number -> File -> Task e File`
+ *
+ * Changes the permission of a specific file/directory of specified path. Ignores the process's umask.
+ *
+ * ```js
+ * import { chmod } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+ *
+ * const container = chmod(0o000, File.fromPath(`${Deno.cwd()}/hoge`));
+ *
+ * assert(Task.is(container));
+ * ```
+ */
export const chmod = curry(
(mode, file) => File.isOrThrow(file) && Task.wrap(_ => Deno.chmod(file.path, mode))
.map(_ => File(file.path, file.raw, file.rid))
);
-// chown :: Number -> Number -> File a -> Task e File a
+/**
+ * ### `chown` [📕](https://doc.deno.land/builtin/stable#Deno.chown)
+ * `Number -> Number -> File -> Task e File`
+ *
+ * Change owner of a regular file or directory. This functionality is not available on Windows.
+ *
+ * ```js
+ * import { chown } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+ *
+ * const container = chown(null, null, File.fromPath(`${Deno.cwd()}/hoge`));
+ *
+ * assert(Task.is(container));
+ * ```
+ */
export const chown = curry(
(uid, gid, file) => File.isOrThrow(file)
&& Task.wrap(_ => Deno.chown(file.path, uid, gid))
.map(_ => File(file.path, file.raw, file.rid))
);
-// close :: Resource a -> Task e Resource a
+/**
+ * ### `close` [📕](https://doc.deno.land/builtin/stable#Deno.close)
+ * `Resource -> Task e Resource`
+ *
+ * Close the given resource which has been previously opened, such as via opening or creating a file.
+ * Closing a file when you are finished with it is important to avoid leaking resources.
+ *
+ * ```js
+ * import { close } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+ *
+ * const container = close(File(`${Deno.cwd()}/hoge`, new Uint8Array([]), 3));
+ *
+ * assert(Task.is(container));
+ * ```
+ */
export const close = resource => Resource.isOrThrow(resource)
&& Task.wrap(_ => Deno.close(resource.rid) || Promise.resolve(undefined))
.map(_ => resource.constructor.from({ ...resource }));
-// copy :: Options -> Buffer a -> Buffer b -> Task e Buffer a
+/**
+ * ### `copy` [📕](https://doc.deno.land/builtin/stable#Deno.copy)
+ * `Object -> Buffer a -> Buffer b -> Task e Buffer b`
+ *
+ * Copies from a source to a destination until either EOF (null) is read from the source, or an error occurs.
+ *
+ * ```js
+ * import { copy } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+ *
+ * const container = copy({}, Buffer(new Uint8Array([ 65, 66, 67, 68, 69 ])), Buffer(new Uint8Array([])));
+ *
+ * assert(Task.is(container));
+ * ```
+ */
export const copy = curry(
(options, readerBuffer, writerBuffer) => (Buffer.isOrThrow(readerBuffer) && Buffer.isOrThrow(writerBuffer))
&& Task.of(writerBuffer.constructor.from({ ...writerBuffer, raw: readerBuffer.raw }))
);
-// copyFile :: File a -> File b -> Task e File b
+/**
+ * ### `copyFile` [📕](https://doc.deno.land/builtin/stable#Deno.copyFile)
+ * `File a -> File b -> Task e File b`
+ *
+ * Copies the contents and permissions of one file to another specified file, by default creating a new file if needed,
+ * else overwriting. Fails if target path is a directory or is unwritable.
+ *
+ * ```js
+ * import { copyFile } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+ *
+ * const container = copyFile(File.fromPath(`${Deno.cwd()}/hoge`), File.fromPath(`${Deno.cwd()}/piyo`));
+ *
+ * assert(Task.is(container));
+ * ```
+ */
export const copyFile = curry(
(fileA, fileB) => (File.isOrThrow(fileA) && File.isOrThrow(fileB))
// NOTE: I don't know if the file should be read after being copied so that the return File has the right content.
@@ -51,21 +139,74 @@ export const copyFile = curry(
.map(_ => File(fileB.path, fileA.raw, fileB.rid))
);
-// create :: File a -> Task e File a
+/**
+ * ### `create` [📕](https://doc.deno.land/builtin/stable#Deno.create)
+ * `File -> Task e File`
+ *
+ * Creates a file if none exists or truncates an existing file.
+ *
+ * ```js
+ * import { create } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+ *
+ * const container = create(File.fromPath(`${Deno.cwd()}/hoge`));
+ *
+ * assert(Task.is(container));
+ * ```
+ */
export const create = file => File.isOrThrow(file)
&& Task.wrap(_ => Deno.create(file.path))
.map(_file => File(file.path, new Uint8Array(file.raw.length), _file.rid));
-// cwd :: () Task e Directory a
+/**
+ * ### `cwd` [📕](https://doc.deno.land/builtin/stable#Deno.cwd)
+ *
+ * Return a Directory representation of the current working directory.
+ * `() -> Task e Directory`
+ *
+ * ```js
+ * import { cwd } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+ *
+ * const container = cwd();
+ *
+ * assert(Task.is(container));
+ * ```
+ */
export const cwd = () => Task.wrap(_ => Promise.resolve(Deno.cwd()))
.map(cwd => Directory(cwd));
-// emptyDir :: Directory a -> Task e Directory a
+/**
+ * ### `emptyDir` [📕](https://deno.land/std@0.79.0/fs#emptydir)
+ * `Directory -> Task e Directory`
+ *
+ * Ensures that a directory is empty. Deletes directory contents if the directory is not empty.
+ * If the directory does not exist, it is created. The directory itself is not deleted.
+ *
+ * ```js
+ * import { emptyDir } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+ *
+ * const container = emptyDir(Directory(`${Deno.cwd()}/hoge`));
+ *
+ * assert(Task.is(container));
+ ```
+ */
export const emptyDir = directory => Directory.isOrThrow(directory)
&& Task.wrap(_ => _emptyDir(directory.path))
.map(_ => Directory(directory.path));
-// ensureDir :: Directory a -> Task e Directory a
+/**
+ * ### `ensureDir` [📕](https://deno.land/std@0.79.0/fs#ensuredir)
+ * `Directory -> Task e Directory`
+ *
+ * Ensures that the directory exists. If the directory structure does not exist, it is created. Like `mkdir -p`.
+ *
+ * ```js
+ * import { ensureDir } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+ *
+ * const container = emptyDir(Directory(`${Deno.cwd()}/hoge`));
+ *
+ * assert(Task.is(container));
+ * ```
+ */
export const ensureDir = directory => Directory.isOrThrow(directory)
&& Task.wrap(_ => _ensureDir(directory.path))
.map(_ => Directory(directory.path));
@@ -75,44 +216,100 @@ export const ensureSymlink = directory => Directory.isOrThrow(directory)
&& Task.wrap(_ => _ensureSymlink(directory.path))
.map(_ => Directory(directory.path));
-// exists :: URL a -> Task null URL a
-export const exists = url => {
- if (!Directory.is(url) && !File.is(url)) {
- throw new Error(`Expected a Directory or a File but got a "${typeof url}"`);
- }
-
- return Task.wrap(_ => _exists(url.path))
- .map(
- fileExists => {
- if (!fileExists) return Either.Left(null);
-
- return url.constructor.from({ ...url });
- }
- )
-};
-
-// mkdir :: Options -> Directory a -> Task e Directory a
+/**
+ * ### `exists` [📕](https://deno.land/std@0.79.0/fs#exists)
+ * `URL -> Task e|null URL
+ *
+ * Test whether the given path exists by checking with the file system.
+ * If the file or directory doesn't exist, it will resolve to `Either.Left(null)`.
+ *
+ * ```js
+ * import { exists } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+ *
+ * const container = exists(Directory(`${Deno.cwd()}/hoge`));
+ *
+ * assert(Task.is(container));
+ * ```
+ */
+export const exists = url => URL.isOrThrow(url)
+ && Task.wrap(_ => _exists(url.path))
+ .map(fileExists => !fileExists ? Either.Left(null) : url.constructor.from({ ...url }));
+
+/**
+ * ### `mkdir` [📕](https://deno.land/std@0.79.0/fs#mkdir)
+ * `Object -> Directory -> Task e Directory`
+ *
+ * Creates a new directory with the specified path.
+ *
+ * ```js
+ * import { mkdir } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+ *
+ * const container = mkdir({}, Directory(`${Deno.cwd()}/hoge`));
+ *
+ * assert(Task.is(container));
+ * ```
+ */
export const mkdir = curry(
(options, directory) => (Directory.isOrThrow(directory))
&& Task.wrap(_ => Deno.mkdir(directory.path, options))
.map(_ => Directory(directory.path))
);
-// move :: Options -> String -> URL a -> Task e URL b
+/**
+ * ### `move` [📕](https://deno.land/std@0.79.0/fs#move)
+ * `Object -> String -> URL -> Task e URL`
+ *
+ * Moves a file or directory.
+ *
+ * ```js
+ * import { move } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+ *
+ * const container = move({}, `${Deno.cwd()}/piyo`, Directory(`${Deno.cwd()}/hoge`));
+ *
+ * assert(Task.is(container));
+ * ```
+ */
export const move = curry(
- (options, destinationPath, url) => url.hasOwnProperty("path")
+ (options, destinationPath, url) => URL.isOrThrow(url)
&& Task.wrap(_ => _move(url.path, destinationPath))
.map(_ => url.constructor.from({ ...url, path: destinationPath }))
);
-// open :: Options -> File a -> Task e File a
+/**
+ * ### `open` [📕](https://doc.deno.land/builtin/stable#Deno.open)
+ * `Object -> File -> Task e File`
+ *
+ * Open a file and resolve to an instance of File. The file does not need to previously exist if using the create or
+ * createNew open options. It is the callers responsibility to close the file when finished with it.
+ *
+ * ```js
+ * import { open } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+ *
+ * const container = open({ read: true, write: true }, File.fromPath(`${Deno.cwd()}/hoge`));
+ *
+ * assert(Task.is(container));
+ * ```
+ */
export const open = curry(
(options, file) => File.isOrThrow(file)
&& Task.wrap(_ => Deno.open(file.path, options))
.map(_file => File(file.path, new Uint8Array([]), _file.rid))
);
-// read :: Resource a -> Task e Resource a
+/**
+ * ### `read` [📕](https://doc.deno.land/builtin/stable#Deno.read)
+ * `Resource Task e Resource`
+ *
+ * Read from a Resource given it has a non-zero raw buffer.
+ *
+ * ```js
+ * import { read } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+ *
+ * const container = read(File(`${Deno.cwd()}/hoge`, new Uint8Array(5), 3));
+ *
+ * assert(Task.is(container));
+ * ```
+ */
export const read = resource => {
const _buffer = new Uint8Array(resource.raw.length);
@@ -121,7 +318,20 @@ export const read = resource => {
.map(_ => resource.constructor.from({ ...resource, raw: _buffer }))
};
-// readLine :: Resource a -> Task e Resource a
+/**
+ * ### `readLine`
+ * `Resource -> Task e Resource`
+ *
+ * Read from a Resource to the CLRF.
+ *
+ * ```js
+ * import { readLine } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+ *
+ * const container = readLine(File(`${Deno.cwd()}/hoge`, new Uint8Array([]), 3));
+ *
+ * assert(Task.is(container));
+ * ```
+ */
export const readLine = resource => Task.wrap(async _ => {
let _accumulatorBuffer = new Uint8Array(1024);
let index = 0;
@@ -138,7 +348,20 @@ export const readLine = resource => Task.wrap(async _ => {
return resource.constructor.from({ ...resource, raw: _accumulatorBuffer.slice(0, index) });
});
-// readNBytes :: Number -> Resource a -> Task e Resource a
+/**
+ * ### `readNBytes`
+ * `Number -> Resource -> Task e Resource`
+ *
+ * Read N bytes from a Resource.
+ *
+ * ```js
+ * import { readNBytes } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+ *
+ * const container = readNBytes(5, File(`${Deno.cwd()}/hoge`, new Uint8Array([]), 3));
+ *
+ * assert(Task.is(container));
+ * ```
+ */
export const readNBytes = curry(
compose(
read,
@@ -146,39 +369,133 @@ export const readNBytes = curry(
)
);
-// readOneByte :: Resource a -> Task e Resource a
+/**
+ * ### `readOneByte`
+ * `Resource -> Task e Resource`
+ *
+ * Read 1 byte from a Resource.
+ *
+ * ```js
+ * import { readOneByte } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+ *
+ * const container = readOneByte(File(`${Deno.cwd()}/hoge`, new Uint8Array([]), 3));
+ *
+ * assert(Task.is(container));
+ * ```
+ */
export const readOneByte = readNBytes(1);
-// readAll :: Resource a -> Task e Resource a
+/**
+ * ### `readAll` [📕](https://doc.deno.land/builtin/stable#Deno.readAll)
+ * `Resource -> Task e Resource`
+ *
+ * Read from a Resource.
+ *
+ * ```js
+ * import { readAll } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+ *
+ * const container = readAll(File(`${Deno.cwd()}/hoge`, new Uint8Array([]), 3));
+ *
+ * assert(Task.is(container));
+ * ```
+ */
export const readAll = resource => Resource.isOrThrow(resource)
&& Task.wrap(_ => Deno.readAll(coerceAsReader(resource)))
.map(_buffer => resource.constructor.from({ ...resource, raw: _buffer }));
-// readFile :: File a -> Task e File a
+/**
+ * ### `readFile` [📕](https://doc.deno.land/builtin/stable#Deno.readFile)
+ * `File -> Task e File`
+ *
+ * Read from a File.
+ *
+ * ```js
+ * import { readFile } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+ *
+ * const container = readFile(File(`${Deno.cwd()}/hoge`, new Uint8Array([]), 3));
+ *
+ * assert(Task.is(container));
+ * ```
+ */
export const readFile = file => File.isOrThrow(file)
&& Task.wrap(_ => Deno.readFile(file.path))
.map(_buffer => File(file.path, _buffer, file.rid));
-// remove :: Options -> URL a -> Task e URL a
+/**
+ * ### `remove` [📕](https://doc.deno.land/builtin/stable#Deno.remove)
+ * `Object -> URL -> Task e URL`
+ *
+ * Removes the named file or directory.
+ *
+ * ```js
+ * import { remove } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+ *
+ * const container = remove({ recursive: true }, Directory.fromPath(`${Deno.cwd()}/hoge`));
+ *
+ * assert(Task.is(container));
+ * ```
+ */
export const remove = curry(
- (options, url) => url.hasOwnProperty("path")
+ (options, url) => URL.isOrThrow(url)
&& Task.wrap(_ => Deno.remove(url.path, options))
.map(_ => url.constructor.from({ ...url }))
);
-// rename :: String -> URL a -> Task e URL b
+/**
+ * ### `rename` [📕](https://doc.deno.land/builtin/stable#Deno.rename)
+ * `String -> URL -> Task e URL`
+ *
+ * Renames a file or directory.
+ *
+ * ```js
+ * import { rename } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+ *
+ * const container = rename(`${Deno.cwd()}/piyo`, Directory(`${Deno.cwd()}/hoge`));
+ *
+ * assert(Task.is(container));
+ * ```
+ */
export const rename = curry(
- (destinationPath, url) => url.hasOwnProperty("path")
+ (destinationPath, url) => URL.isOrThrow(url)
&& Task.wrap(_ => Deno.rename(url.path, destinationPath))
.map(_ => url.constructor.from({ ...url, path: destinationPath }))
);
-// write :: Resource a -> Task e Resource a
+/**
+ * ### `write` [📕](https://doc.deno.land/builtin/stable#Deno.write)
+ * `Resource -> Task e Resource`
+ *
+ * Write to a Resource given it has a non-zero raw buffer.
+ *
+ * ```js
+ * import { write } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+ *
+ * const container = write(File(`${Deno.cwd()}/hoge`, new Uint8Array([ 65, 66, 67, 68, 69 ]), 3));
+ *
+ * assert(Task.is(container));
+ * ```
+ */
export const write = resource => Resource.isOrThrow(resource)
&& Task.wrap(_ => Deno.write(resource.rid, resource.raw))
.map(_ => resource.constructor.from({ ...resource }));
-// writeAll :: Buffer b -> Resource a -> Task e Resource b
+/**
+ * ### `writeAll` [📕](https://doc.deno.land/builtin/stable#Deno.writeAll)
+ * `Buffer -> Task e Resource`
+ *
+ * Write all to a Resource from a Buffer.
+ *
+ * ```js
+ * import { writeAll } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+ *
+ * const container = writeAll(
+ * Buffer(new Uint8Array([ 65, 66, 67, 68, 69 ])),
+ * File(`${Deno.cwd()}/hoge`, new Uint8Array([]), 3)
+ * );
+ *
+ * assert(Task.is(container));
+ * ```
+ */
export const writeAll = curry(
(buffer, resource) => Resource.isOrThrow(resource) && Buffer.isOrThrow(buffer)
&& Task.wrap(_ =>
@@ -186,7 +503,20 @@ export const writeAll = curry(
.map(_ => resource.constructor.from({ ...resource, raw: buffer.raw }))
);
-// writeFile :: File a -> Task e File a
+/**
+ * ### `writeFile` [📕](https://doc.deno.land/builtin/stable#Deno.writeFile)
+ * `Object -> File -> Task e File`
+ *
+ * Write a File to the file system.
+ *
+ * ```js
+ * import { writeFile } from "https://deno.land/x/functional_io@v1.1.0/library/fs.js";
+ *
+ * const container = writeFile({}, File(`${Deno.cwd()}/hoge`, new Uint8Array([]), 3));
+ *
+ * assert(Task.is(container));
+ * ```
+ */
export const writeFile = curry(
(options, file) => Resource.isOrThrow(file)
&& Task.wrap(_ => Deno.writeFile(file.path, file.raw, options))
diff --git a/library/fs_test.js b/library/fs_test.js
index b02d987..4e5884c 100644
--- a/library/fs_test.js
+++ b/library/fs_test.js
@@ -1,24 +1,36 @@
import {
+ __,
+ ap,
compose,
concat,
converge,
chain,
curry,
flip,
+ head,
join,
lift,
map,
match,
+ path,
+ prop,
replace,
- trim
-} from "https://x.nest.land/ramda@0.27.0/source/index.js";
+ trim,
+ useWith
+} from "https://deno.land/x/ramda@v0.27.2/mod.ts";
import { assert, assertEquals } from "https://deno.land/std@0.79.0/testing/asserts.ts";
import {
emptyDir as _emptyDir,
ensureDir as _ensureDir
} from "https://deno.land/std@0.79.0/fs/mod.ts";
-import Either from "https://deno.land/x/functional@v1.2.1/library/Either.js"
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task.js"
+import Either from "https://deno.land/x/functional@v1.3.2/library/Either.js"
+import Task from "https://deno.land/x/functional@v1.3.2/library/Task.js";
+import { log, safeExtract } from "https://deno.land/x/functional@v1.3.2/library/utilities.js";
+import Buffer from "./Buffer.js";
+import Directory from "./Directory.js";
+import File, { factorizeFile } from "./File.js";
+import Request from "./Request.js";
+import { fetch } from "./browser_safe.js";
import {
chdir,
chmod,
@@ -43,12 +55,9 @@ import {
write,
writeAll,
writeFile
-} from "../library/fs.js"
-import Buffer from "./Buffer.js";
-import Directory from "./Directory.js";
-import File from "./File.js";
+} from "./fs.js"
-import { $$value } from "https://deno.land/x/functional@v1.2.1/library/Symbols.js";
+import { $$value } from "https://deno.land/x/functional@v1.3.2/library/Symbols.js";
Deno.test(
"Integration: chdir",
@@ -881,4 +890,39 @@ Deno.test(
assert((await container.run()).extract().headers.status === 200);
}
-)
\ No newline at end of file
+);
+
+Deno.test(
+ "Scenario 5",
+ async () => {
+ const fetchBacon = compose(
+ chain(writeFile({})),
+ ap(
+ useWith(
+ lift(factorizeFile(__, __, 0)),
+ [
+ compose(
+ Task.of,
+ name => `${Deno.cwd()}/${name}.html`,
+ prop(1),
+ match(/\?type=([A-Za-z\-]+)/),
+ path([ "headers", "url" ])
+ ),
+ map(prop("raw"))
+ ]
+ ),
+ fetch
+ )
+ );
+
+ const container = await fetchBacon(
+ Request.get("https://baconipsum.com/api/?type=all-meat¶s=3&start-with-lorem=1&format=html")
+ ).run();
+
+ const file = safeExtract("Failed to write file.", container);
+
+ assert(File.is(file));
+
+ await Deno.remove(`${Deno.cwd()}/all-meat.html`);
+ }
+);
diff --git a/library/network.js b/library/network.js
index 1aa6f1d..74d4f26 100644
--- a/library/network.js
+++ b/library/network.js
@@ -1,5 +1,5 @@
import { Connection } from "./Resource.js";
-import Task from "https://deno.land/x/functional@v1.2.1/library/Task";
+import Task from "https://deno.land/x/functional@v1.3.2/library/Task";
// connect :: Connection a -> Task e Connection a
export const connect = connection => Connection.isOrThrow(connection)
diff --git a/library/utilities.js b/library/utilities.js
index ffc4fee..ff05693 100644
--- a/library/utilities.js
+++ b/library/utilities.js
@@ -1,30 +1,37 @@
import {
__,
- always,
ap,
compose,
flip,
- gte,
- ifElse,
map,
prop,
reduce,
- slice,
- subtract,
-} from "https://x.nest.land/ramda@0.27.0/source/index.js";
+ slice
+} from "https://deno.land/x/ramda@v0.27.2/mod.ts";
-import Pair from "https://deno.land/x/functional@v1.2.1/library/Pair.js";
+import Pair from "https://deno.land/x/functional@v1.3.2/library/Pair.js";
+import { decodeRaw, encodeText } from "https://deno.land/x/functional@v1.3.2/library/utilities.js";
const CHARACTER_CODE_CL = "\r".charCodeAt(0);
const CHARACTER_CODE_RF = "\n".charCodeAt(0);
-const $$decoder = new TextDecoder();
-const $$encoder = new TextEncoder();
-
-export const decodeRaw = $$decoder.decode.bind($$decoder);
-export const encodeText = $$encoder.encode.bind($$encoder);
-
-// findCLRFIndex :: Uint8Array -> Number
+/**
+ * ## Utilities
+ */
+
+/**
+ * ### `findCLRFIndex`
+ * `Uint8Array -> Number`
+ *
+ * This function takes a `Uint8Array` and, returns the index of the last character of the first CLRF sequence
+ * encountered.
+ *
+ * ```js
+ * import { findCLRFIndex } from "https://deno.land/x/functional_io@v1.1.0/library/utilities.js";
+ *
+ * assertEquals(findCLRFIndex(new Uint8Array([ 104, 111, 103, 101, 13, 10 ])), 6);
+ * ```
+ */
export const findCLRFIndex = compose(
prop("second"),
reduce(
@@ -41,18 +48,105 @@ export const findCLRFIndex = compose(
)
);
+/**
+ * ### `discardFirstLine`
+ * `Uint8Array -> Uint8Array`
+ *
+ * This function takes a `Uint8Array` and, returns the typed array minus the first line separated by CLRF.
+ *
+ * ```js
+ * import { discardFirstLine } from "https://deno.land/x/functional_io@v1.1.0/library/utilities.js";
+ *
+ * assertEquals(
+ * discardFirstLine(new Uint8Array([ 104, 111, 103, 101, 13, 10, 104, 111, 103, 101, 13, 10 ])),
+ * new Uint8Array([ 104, 111, 103, 101, 13, 10 ])
+ * );
+ * ```
+ */
export const discardFirstLine = ap(flip(slice(__, Infinity)), findCLRFIndex);
+/**
+ * ### `discardNCharacter`
+ * `Number -> Uint8Array -> Uint8Array`
+ *
+ * This function takes a Number, a `Uint8Array` and, returns the typed array minus the specified amount of character
+ * starting from the left side.
+ *
+ * ```js
+ * import { discardNCharacter } from "https://deno.land/x/functional_io@v1.1.0/library/utilities.js";
+ *
+ * assertEquals(
+ * discardNCharacter(1, new Uint8Array([ 104, 111, 103, 101, 13, 10 ])),
+ * new Uint8Array([ 111, 103, 101, 13, 10 ])
+ * );
+ * ```
+ */
export const discardNCharacter = slice(__, Infinity);
+/**
+ * ### `getFirstLine`
+ * `Uint8Array -> Uint8Array`
+ *
+ * This function takes a `Uint8Array` and, returns the first line separated by a CLRF inclusively.
+ *
+ * ```js
+ * import { getFirstLine } from "https://deno.land/x/functional_io@v1.1.0/library/utilities.js";
+ *
+ * assertEquals(
+ * getFirstLine(new Uint8Array([ 104, 111, 103, 101, 13, 10, 104, 111, 103, 101, 13, 10 ])),
+ * new Uint8Array([ 104, 111, 103, 101, 13, 10 ])
+ * );
+ * ```
+ */
export const getFirstLine = ap(flip(slice(0)), findCLRFIndex);
+/**
+ * ### `joinCLRF`
+ * `Uint8Array[] -> Uint8Array`
+ *
+ * This function takes a list of `Uint8Array` and, returns a `Uint8Array` of the list joined with CLRF sequence; the
+ * function is analogous to `Array#join`.
+ *
+ * ```js
+ * import { joinCLRF } from "https://deno.land/x/functional_io@v1.1.0/library/utilities.js";
+ *
+ * assertEquals(
+ * joinCLRF(
+ * [
+ * new Uint8Array([ 104, 111, 103, 101 ]),
+ * new Uint8Array([ 104, 111, 103, 101 ])
+ * ]
+ * ),
+ * new Uint8Array([ 104, 111, 103, 101, 13, 10, 104, 111, 103, 101, 13, 10 ])
+ * );
+ * ```
+ */
export const joinCLRF = reduce(
- (accumulator, _buffer) => new Uint8Array([ ...accumulator, 13, 10, ..._buffer ]),
+ (accumulator, _buffer) => accumulator.byteLength > 0
+ ? new Uint8Array([ ...accumulator, ..._buffer, CHARACTER_CODE_CL, CHARACTER_CODE_RF ])
+ : new Uint8Array([ ..._buffer, CHARACTER_CODE_CL, CHARACTER_CODE_RF ]),
new Uint8Array([])
);
-// splitCLRF :: Uint8Array -> Uint8Array[]
+/**
+ * ### `splitCLRF`
+ * `Uint8Array -> Uint8Array[]`
+ *
+ * This function takes a `Uint8Array` and, returns a list of `Uint8Array` of subarray split at the CLRF sequence; the
+ * function is analogous to `String#split`.
+ *
+ * ```js
+ * import { splitCLRF } from "https://deno.land/x/functional_io@v1.1.0/library/utilities.js";
+ *
+ * assertEquals(
+ * splitCLRF(new Uint8Array([ 104, 111, 103, 101, 13, 10, 104, 111, 103, 101, 13, 10 ])),
+ * [
+ * new Uint8Array([ 104, 111, 103, 101, 13, 10 ]),
+ * new Uint8Array([ 104, 111, 103, 101, 13, 10 ])
+ * ]
+ * );
+ * ```
+ */
export const splitCLRF = characterCodeList => {
const accumulator = [];
let remainingCharacterCodeList = characterCodeList;
@@ -73,8 +167,41 @@ export const splitCLRF = characterCodeList => {
// mapBuffer :: Buffer -> (String -> String) -> Buffer
export const mapBuffer = unaryFunction => map(compose(encodeText, unaryFunction, decodeRaw));
-// trimCRLF :: Uint8Array -> Uint8Array
-export const trimCRLF = ap(flip(slice(0)), compose(ifElse(flip(gte)(0), subtract(__, 2), always(Infinity)), findCLRFIndex));
+/**
+ * ### `trimCRLF`
+ * `Uint8Array -> Uint8Array`
+ *
+ * This function takes a `Uint8Array` and, returns a typed array minus CRLF at the beginning and at the end;
+ * the function is analogous to `String#trim`.
+ *
+ * ```js
+ * import { trimCRLF } from "https://deno.land/x/functional_io@v1.1.0/library/utilities.js";
+ *
+ * assertEquals(
+ * trimCRLF(new Uint8Array([ 104, 111, 103, 101, 13, 10 ])),
+ * new Uint8Array([ 104, 111, 103, 101 ])
+ * );
+ * ```
+ */
+export const trimCRLF = characterCodeList => {
+ let remainingCharacterCodeList = characterCodeList;
+
+ while (true) {
+ if (remainingCharacterCodeList[0] === CHARACTER_CODE_CL && remainingCharacterCodeList[1] === CHARACTER_CODE_RF)
+ remainingCharacterCodeList = remainingCharacterCodeList.slice(2, Infinity);
+ else break;
+ }
+
+ while (true) {
+ if (
+ remainingCharacterCodeList[remainingCharacterCodeList.length - 2] === CHARACTER_CODE_CL
+ && remainingCharacterCodeList[remainingCharacterCodeList.length - 1] === CHARACTER_CODE_RF
+ ) remainingCharacterCodeList = remainingCharacterCodeList.slice(0, remainingCharacterCodeList.length - 2);
+ else break;
+ }
+
+ return remainingCharacterCodeList;
+};
export const coerceAsReader = resource => {
@@ -111,4 +238,10 @@ export const coerceAsWriter = resource => {
};
};
+/**
+ * ### `factorizeUint8Array`
+ * `Number|Array|Uint8Array -> Uint8Array
+ *
+ * This function factorize a Uint8Array given an argument.
+ */
export const factorizeUint8Array = x => new Uint8Array(x);
diff --git a/library/utilities_test.js b/library/utilities_test.js
index bf610da..2b5b476 100644
--- a/library/utilities_test.js
+++ b/library/utilities_test.js
@@ -1,7 +1,15 @@
import { assertEquals } from "https://deno.land/std@0.79.0/testing/asserts.ts";
import Buffer from "./Buffer.js";
-import { coerceAsReader, coerceAsWriter, findCLRFIndex, splitCLRF, trimCRLF } from "./utilities.js";
+import {
+ coerceAsReader,
+ coerceAsWriter,
+ discardFirstLine,
+ discardNCharacter,
+ findCLRFIndex, getFirstLine, joinCLRF,
+ splitCLRF,
+ trimCRLF
+} from "./utilities.js";
Deno.test(
"coerceAsReader",
@@ -150,6 +158,66 @@ Deno.test(
}
);
+Deno.test(
+ "discardFirstLine",
+ () => {
+ assertEquals(
+ discardFirstLine(new Uint8Array([ 104, 111, 103, 101, 13, 10, 104, 111, 103, 101, 13, 10 ])),
+ new Uint8Array([ 104, 111, 103, 101, 13, 10 ])
+ );
+
+ assertEquals(
+ discardFirstLine(new Uint8Array([ 104, 111, 103, 101, 13, 10 ])),
+ new Uint8Array([])
+ );
+ }
+);
+
+Deno.test(
+ "discardNCharacter",
+ () => {
+ assertEquals(
+ discardNCharacter(1, new Uint8Array([ 104, 111, 103, 101, 13, 10 ])),
+ new Uint8Array([ 111, 103, 101, 13, 10 ])
+ );
+ }
+);
+
+Deno.test(
+ "getFirstLine",
+ () => {
+ assertEquals(
+ getFirstLine(new Uint8Array([ 104, 111, 103, 101, 13, 10, 104, 111, 103, 101, 13, 10 ])),
+ new Uint8Array([ 104, 111, 103, 101, 13, 10 ])
+ );
+
+ assertEquals(
+ getFirstLine(new Uint8Array([ 104, 111, 103, 101, 13, 10 ])),
+ new Uint8Array([ 104, 111, 103, 101, 13, 10 ])
+ );
+ }
+);
+
+Deno.test(
+ "joinCLRF",
+ () => {
+ assertEquals(
+ joinCLRF(
+ [
+ new Uint8Array([ 104, 111, 103, 101 ]),
+ new Uint8Array([ 112, 105, 121, 111 ])
+ ]
+ ),
+ new Uint8Array([ 104, 111, 103, 101, 13, 10, 112, 105, 121, 111, 13, 10 ])
+ );
+
+ assertEquals(
+ joinCLRF([ new Uint8Array([ 104, 111, 103, 101 ]) ]),
+ new Uint8Array([ 104, 111, 103, 101, 13, 10 ])
+ );
+ }
+)
+
Deno.test(
"splitCLRF",
() => {
@@ -161,24 +229,24 @@ Deno.test(
);
assertEquals(
- splitCLRF(new Uint8Array([ 104, 111, 103, 101, 13, 10, 104, 111, 103, 101, 13, 10 ])),
+ splitCLRF(new Uint8Array([ 104, 111, 103, 101, 13, 10, 112, 105, 121, 111, 13, 10 ])),
[
new Uint8Array([ 104, 111, 103, 101, 13, 10 ]),
- new Uint8Array([ 104, 111, 103, 101, 13, 10 ])
+ new Uint8Array([ 112, 105, 121, 111, 13, 10 ])
]
);
assertEquals(
- splitCLRF(new Uint8Array([ 104, 111, 103, 101, 13, 104, 111, 103, 101 ])),
+ splitCLRF(new Uint8Array([ 104, 111, 103, 101, 13, 112, 105, 121, 111 ])),
[
- new Uint8Array([ 104, 111, 103, 101, 13, 104, 111, 103, 101 ])
+ new Uint8Array([ 104, 111, 103, 101, 13, 112, 105, 121, 111 ])
]
);
assertEquals(
- splitCLRF(new Uint8Array([ 104, 111, 103, 101, 10, 104, 111, 103, 101 ])),
+ splitCLRF(new Uint8Array([ 104, 111, 103, 101, 10, 112, 105, 121, 111 ])),
[
- new Uint8Array([ 104, 111, 103, 101, 10, 104, 111, 103, 101 ])
+ new Uint8Array([ 104, 111, 103, 101, 10, 112, 105, 121, 111 ])
]
);
}
@@ -192,6 +260,21 @@ Deno.test(
new Uint8Array([ 104, 111, 103, 101 ])
);
+ assertEquals(
+ trimCRLF(new Uint8Array([ 13, 10, 104, 111, 103, 101, 13, 10 ])),
+ new Uint8Array([ 104, 111, 103, 101 ])
+ );
+
+ assertEquals(
+ trimCRLF(new Uint8Array([ 13, 10, 13, 10, 104, 111, 103, 101, 13, 10 ])),
+ new Uint8Array([ 104, 111, 103, 101 ])
+ );
+
+ assertEquals(
+ trimCRLF(new Uint8Array([ 13, 10, 104, 111, 103, 101, 13, 10, 112, 105, 121, 111, 13, 10 ])),
+ new Uint8Array([ 104, 111, 103, 101, 13, 10, 112, 105, 121, 111 ])
+ );
+
assertEquals(
trimCRLF(new Uint8Array([ 104, 111, 103, 101 ])),
new Uint8Array([ 104, 111, 103, 101 ])
diff --git a/mod.js b/mod.js
new file mode 100644
index 0000000..c75ea10
--- /dev/null
+++ b/mod.js
@@ -0,0 +1,11 @@
+export * from "./library/Buffer.js";
+export * from "./library/Directory.js";
+export * from "./library/File.js";
+export * from "./library/FileSystemCollection.js";
+export * from "./library/Request.js";
+export * from "./library/Resource.js";
+export * from "./library/Response.js";
+export * from "./library/URL.js";
+export * from "./library/browser_safe.js";
+export * from "./library/fs.js";
+export * from "./library/utilities.js";
diff --git a/mod.ts b/mod.ts
new file mode 100644
index 0000000..7eb4dd5
--- /dev/null
+++ b/mod.ts
@@ -0,0 +1,18 @@
+// @deno-types="./library/Buffer.d.ts"
+export * from "./library/Buffer.js";
+// @deno-types="./library/Directory.d.ts"
+export * from "./library/Directory.js";
+// @deno-types="./library/File.d.ts"
+export * from "./library/File.js";
+export * from "./library/FileSystemCollection.js";
+// @deno-types="./library/Request.d.ts"
+export * from "./library/Request.js";
+// @deno-types="./library/Resource.d.ts"
+export * from "./library/Resource.js";
+// @deno-types="./library/Response.d.ts"
+export * from "./library/Response.js";
+// @deno-types="./library/URL.d.ts"
+export * from "./library/URL.js";
+export * from "./library/browser_safe.js";
+export * from "./library/fs.js";
+export * from "./library/utilities.js";