From 66f87f413b5fceb90962e67888a1cd3b5862c6e5 Mon Sep 17 00:00:00 2001 From: Orion Kindel Date: Mon, 10 Jun 2024 12:16:33 -0500 Subject: [PATCH] fix: spago --- README.md | 29 +++++++++++ bun/prepare.js | 34 ++++++++++++ package.json | 2 +- spago.lock | 52 ++++++++++--------- spago.yaml | 23 ++------ src/{HTTP/MIME.purs => Data.MIME.purs} | 2 +- src/Data.Tuple.Containing.purs | 25 --------- src/{HTTP.js => Effect.Aff.HTTP.js} | 3 +- src/{HTTP.purs => Effect.Aff.HTTP.purs} | 47 +++++++++-------- src/{HTTP => Effect.Aff.HTTP}/Form.js | 0 src/{HTTP => Effect.Aff.HTTP}/Form.purs | 6 +-- src/{HTTP => Effect.Aff.HTTP}/Header.purs | 6 +-- src/{HTTP => Effect.Aff.HTTP}/Request.js | 10 ++-- src/{HTTP => Effect.Aff.HTTP}/Request.purs | 14 ++--- .../Response.Node.js | 6 +-- .../Response.Node.purs | 6 +-- src/{HTTP => Effect.Aff.HTTP}/Response.js | 0 src/{HTTP => Effect.Aff.HTTP}/Response.purs | 6 +-- 18 files changed, 147 insertions(+), 124 deletions(-) create mode 100644 README.md create mode 100644 bun/prepare.js rename src/{HTTP/MIME.purs => Data.MIME.purs} (99%) delete mode 100644 src/Data.Tuple.Containing.purs rename src/{HTTP.js => Effect.Aff.HTTP.js} (77%) rename src/{HTTP.purs => Effect.Aff.HTTP.purs} (65%) rename src/{HTTP => Effect.Aff.HTTP}/Form.js (100%) rename src/{HTTP => Effect.Aff.HTTP}/Form.purs (97%) rename src/{HTTP => Effect.Aff.HTTP}/Header.purs (97%) rename src/{HTTP => Effect.Aff.HTTP}/Request.js (74%) rename src/{HTTP => Effect.Aff.HTTP}/Request.purs (91%) rename src/{HTTP => Effect.Aff.HTTP}/Response.Node.js (85%) rename src/{HTTP => Effect.Aff.HTTP}/Response.Node.purs (82%) rename src/{HTTP => Effect.Aff.HTTP}/Response.js (100%) rename src/{HTTP => Effect.Aff.HTTP}/Response.purs (96%) diff --git a/README.md b/README.md new file mode 100644 index 0000000..f893e4f --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# purescript-ezfetch +High-level bindings to the native `fetch` API + +## `Effect.Aff.HTTP` +The main entry point is `Effect.Aff.HTTP.fetch`: + +```purescript +fetch +``` + + * `` is `Effect.Aff.HTTP.Request.Method`: + ```purescript + data Method + = GET + | PUT + | POST + | DELETE + | PATCH + | HEAD + ``` + * `` is `Data.URL.URL` (from [`url-immutable`](https://pursuit.purescript.org/packages/purescript-url-immutable/)) + * `` is a partial record of: + ```purescript + type OptionalFields = + ( body :: Body + , headers :: Headers + , credentials :: Credentials + ) + ``` diff --git a/bun/prepare.js b/bun/prepare.js new file mode 100644 index 0000000..f8cfd59 --- /dev/null +++ b/bun/prepare.js @@ -0,0 +1,34 @@ +import { readFile, writeFile } from 'fs/promises' +import { execSync } from 'child_process' + +let ver = process.argv[2] +if (!ver) { + console.error(`tag required: bun bun/prepare.js v1.0.0`) + process.exit(1) +} else if (!/v\d+\.\d+\.\d+/.test(ver)) { + console.error(`invalid tag: ${ver}`) + process.exit(1) +} + +ver = (/\d+\.\d+\.\d+/.exec(ver) || [])[0] || '' + +const pkg = await readFile('./package.json', 'utf8') +const pkgnew = pkg.replace(/"version": ".+"/, `"version": "v${ver}"`) +await writeFile('./package.json', pkgnew) + +const spago = await readFile('./spago.yaml', 'utf8') +const spagonew = spago.replace(/version: .+/, `version: '${ver}'`) +await writeFile('./spago.yaml', spagonew) + +const readme = await readFile('./README.md', 'utf8') +const readmenew = readme.replace( + /packages\/purescript-fetch\/.+?\//g, + `/packages/purescript-fetch/${ver}/`, +) +await writeFile('./README.md', readmenew) + +execSync(`git add spago.yaml package.json README.md`) +execSync(`git commit -m 'chore: prepare v${ver}'`) +execSync(`git tag v${ver}`) +execSync(`git push --tags`) +execSync(`git push --mirror github-mirror`) diff --git a/package.json b/package.json index d3e26f4..4982682 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "purs", + "name": "purescript-ezfetch", "private": true, "module": "index.js", "type": "module", diff --git a/spago.lock b/spago.lock index cdc807c..e973ee5 100644 --- a/spago.lock +++ b/spago.lock @@ -1,6 +1,6 @@ workspace: packages: - fetch: + ezfetch: path: ./ dependencies: - aff: ">=7.1.0 <8.0.0" @@ -28,7 +28,7 @@ workspace: - transformers: ">=6.0.0 <7.0.0" - tuples: ">=7.0.0 <8.0.0" - unsafe-coerce: ">=6.0.0 <7.0.0" - - url: "*" + - url-immutable: ">=1.0.0 <2.0.0" - web-file: ">=4.0.0 <5.0.0" - web-streams: ">=4.0.0 <5.0.0" test_dependencies: [] @@ -86,6 +86,7 @@ workspace: - simple-json - st - strings + - stringutils - tailrec - transformers - tuples @@ -94,29 +95,13 @@ workspace: - uint - unfoldable - unsafe-coerce - - url + - url-immutable - variant - web-dom - web-events - web-file - web-streams - extra_packages: - url: - git: https://git.orionkindel.com/thunderstrike/purescript-url-immutable.git - ref: dbfa3b6 - dependencies: - - arrays - - effect - - filterable - - foldable-traversable - - integers - - maybe - - newtype - - nullable - - ordered-collections - - prelude - - strings - - tuples + extra_packages: {} packages: aff: type: registry @@ -701,6 +686,17 @@ packages: - tuples - unfoldable - unsafe-coerce + stringutils: + type: registry + version: 0.0.12 + integrity: sha256-t63QWBlp49U0nRqUcFryKflSJsNKGTQAHKjn24/+ooI= + dependencies: + - arrays + - integers + - maybe + - partial + - prelude + - strings tailrec: type: registry version: 6.1.0 @@ -779,22 +775,28 @@ packages: version: 6.0.0 integrity: sha256-IqIYW4Vkevn8sI+6aUwRGvd87tVL36BBeOr0cGAE7t0= dependencies: [] - url: - type: git - url: https://git.orionkindel.com/thunderstrike/purescript-url-immutable.git - rev: dbfa3b6e3b01b2d6c7b02202054d52754f000b20 + url-immutable: + type: registry + version: 1.0.0 + integrity: sha256-6uCg5k4fjrqyTYUYKTmcykXgXCJKsvVpzx+gZJczAx0= dependencies: - arrays - - effect + - bifunctors + - either - filterable - foldable-traversable + - foreign - integers - maybe - newtype - nullable - ordered-collections + - partial - prelude + - simple-json - strings + - stringutils + - transformers - tuples variant: type: registry diff --git a/spago.yaml b/spago.yaml index da1feb3..4702495 100644 --- a/spago.yaml +++ b/spago.yaml @@ -1,4 +1,6 @@ +workspace: {} package: + name: 'ezfetch' dependencies: - aff: ">=7.1.0 <8.0.0" - aff-promise: ">=4.0.0 <5.0.0" @@ -25,25 +27,6 @@ package: - transformers: ">=6.0.0 <7.0.0" - tuples: ">=7.0.0 <8.0.0" - unsafe-coerce: ">=6.0.0 <7.0.0" - - url: "*" + - url-immutable: ">=1.0.0 <2.0.0" - web-file: ">=4.0.0 <5.0.0" - web-streams: ">=4.0.0 <5.0.0" - name: fetch -workspace: - extraPackages: - url: - git: 'https://git.orionkindel.com/thunderstrike/purescript-url-immutable.git' - ref: 'dbfa3b6' - dependencies: - - arrays - - effect - - filterable - - foldable-traversable - - integers - - maybe - - newtype - - nullable - - ordered-collections - - prelude - - strings - - tuples diff --git a/src/HTTP/MIME.purs b/src/Data.MIME.purs similarity index 99% rename from src/HTTP/MIME.purs rename to src/Data.MIME.purs index 4276348..3104a8d 100644 --- a/src/HTTP/MIME.purs +++ b/src/Data.MIME.purs @@ -1,4 +1,4 @@ -module HTTP.MIME where +module Data.MIME where import Prelude diff --git a/src/Data.Tuple.Containing.purs b/src/Data.Tuple.Containing.purs deleted file mode 100644 index cc25493..0000000 --- a/src/Data.Tuple.Containing.purs +++ /dev/null @@ -1,25 +0,0 @@ -module Data.Tuple.Containing where - -import Prelude - -import Data.Tuple (Tuple, fst, snd) -import Data.Tuple.Nested (type (/\), (/\)) - --- | given a tuple of any size with at least 1 value --- | of type `a`, `extract` the first occurence of `a` --- | from the tuple -class TupleContaining a tup where - extract :: tup -> a - -instance TupleContaining a a where - extract = identity -else instance TupleContaining a (a /\ b) where - extract = fst -else instance TupleContaining b (a /\ b) where - extract = snd -else instance TupleContaining b (a /\ b /\ rest) where - extract (_ /\ b /\ _) = b -else instance TupleContaining c (a /\ b /\ c /\ Unit) where - extract (_ /\ _ /\ c /\ _) = c -else instance TupleContaining a tail => TupleContaining a (Tuple head tail) where - extract (_ /\ tail) = extract tail diff --git a/src/HTTP.js b/src/Effect.Aff.HTTP.js similarity index 77% rename from src/HTTP.js rename to src/Effect.Aff.HTTP.js index 5bdf471..81a74f6 100644 --- a/src/HTTP.js +++ b/src/Effect.Aff.HTTP.js @@ -9,5 +9,4 @@ */ /** @type {(o: RequestInit) => () => Promise} */ -export const fetchImpl = o => () => - fetch(o.url, {...o, redirect: 'manual'}) +export const fetchImpl = o => () => fetch(o.url, { ...o, redirect: 'manual' }) diff --git a/src/HTTP.purs b/src/Effect.Aff.HTTP.purs similarity index 65% rename from src/HTTP.purs rename to src/Effect.Aff.HTTP.purs index 2e73c5f..5989e21 100644 --- a/src/HTTP.purs +++ b/src/Effect.Aff.HTTP.purs @@ -1,4 +1,4 @@ -module HTTP (fetch, fetchWithDefaults, OptionalFields, module X) where +module Effect.Aff.HTTP (fetch, fetchWithDefaults, OptionalFields, module X) where import Prelude @@ -13,12 +13,12 @@ import Effect (Effect) import Effect.Aff.Class (class MonadAff, liftAff) import Foreign.Object (Object) import Foreign.Object as Object -import HTTP.Header (Headers) -import HTTP.Header (headers) as X -import HTTP.Request (Body(..), Credentials(..), Method, RawBody, bodyHeaders, bodyToRaw) -import HTTP.Request (Method(..)) as X -import HTTP.Request as Req -import HTTP.Response (Response) +import Effect.Aff.HTTP.Header (Headers) +import Effect.Aff.HTTP.Header (headers) as X +import Effect.Aff.HTTP.Request (Body(..), Credentials(..), Method, RawBody, bodyHeaders, bodyToRaw) +import Effect.Aff.HTTP.Request (Method(..)) as X +import Effect.Aff.HTTP.Request as Req +import Effect.Aff.HTTP.Response (Response) import Prim.Row (class Nub, class Union) import Record as Record import Type.Prelude (Proxy(..)) @@ -54,7 +54,7 @@ makeOptionalFields => Union x OptionalFields o => Union x xm OptionalFields => Record OptionalFields - -> {|x} + -> { | x } -> Record OptionalFields makeOptionalFields d x = Record.merge x d @@ -67,7 +67,7 @@ fetchWithDefaults => Record OptionalFields -> Method -> URL - -> {|x} + -> { | x } -> m Response fetchWithDefaults defaults' method url x = let @@ -86,20 +86,21 @@ fetchWithDefaults defaults' method url x = fields = Record.modify (Proxy @"credentials") credsStr - $ Record.modify (Proxy @"headers") (Object.fromFoldableWithIndex <<< unwrap) - $ Record.insert (Proxy @"method") methodStr - $ Record.insert (Proxy @"url") (URL.toString url) - $ makeOptionalFields @x defaults' x - in do - bodyHeaders' <- (Object.fromFoldableWithIndex <<< unwrap) <$> bodyHeaders fields.body - bodyRaw <- Nullable.toNullable <$> bodyToRaw fields.body - let - fields' = - Record.modify (Proxy @"headers") (Object.union bodyHeaders') - $ Record.set (Proxy @"body") bodyRaw - $ fields + $ Record.modify (Proxy @"headers") (Object.fromFoldableWithIndex <<< unwrap) + $ Record.insert (Proxy @"method") methodStr + $ Record.insert (Proxy @"url") (URL.toString url) + $ makeOptionalFields @x defaults' x + in + do + bodyHeaders' <- (Object.fromFoldableWithIndex <<< unwrap) <$> bodyHeaders fields.body + bodyRaw <- Nullable.toNullable <$> bodyToRaw fields.body + let + fields' = + Record.modify (Proxy @"headers") (Object.union bodyHeaders') + $ Record.set (Proxy @"body") bodyRaw + $ fields - liftAff $ Promise.toAffE $ fetchImpl fields' + liftAff $ Promise.toAffE $ fetchImpl fields' fetch :: forall x xm m o @@ -109,6 +110,6 @@ fetch => Union x xm OptionalFields => Method -> URL - -> {|x} + -> { | x } -> m Response fetch = fetchWithDefaults defaults diff --git a/src/HTTP/Form.js b/src/Effect.Aff.HTTP/Form.js similarity index 100% rename from src/HTTP/Form.js rename to src/Effect.Aff.HTTP/Form.js diff --git a/src/HTTP/Form.purs b/src/Effect.Aff.HTTP/Form.purs similarity index 97% rename from src/HTTP/Form.purs rename to src/Effect.Aff.HTTP/Form.purs index 487a6a4..8f2f8e7 100644 --- a/src/HTTP/Form.purs +++ b/src/Effect.Aff.HTTP/Form.purs @@ -1,4 +1,4 @@ -module HTTP.Form where +module Effect.Aff.HTTP.Form where import Prelude @@ -25,8 +25,8 @@ import Effect.Exception (error) import Foreign (Foreign, unsafeReadTagged, unsafeToForeign) import Foreign.Object (Object) import Foreign.Object as Object -import HTTP.MIME (MIME) -import HTTP.MIME as MIME +import Data.MIME (MIME) +import Data.MIME as MIME import Simple.JSON (readImpl, unsafeStringify) import Unsafe.Coerce (unsafeCoerce) import Web.File.Blob (Blob) diff --git a/src/HTTP/Header.purs b/src/Effect.Aff.HTTP/Header.purs similarity index 97% rename from src/HTTP/Header.purs rename to src/Effect.Aff.HTTP/Header.purs index e56276b..525c749 100644 --- a/src/HTTP/Header.purs +++ b/src/Effect.Aff.HTTP/Header.purs @@ -1,4 +1,4 @@ -module HTTP.Header where +module Effect.Aff.HTTP.Header where import Prelude @@ -14,8 +14,8 @@ import Data.String.Base64 as String.Base64 import Data.Tuple (Tuple(..)) import Effect (Effect) import Effect.Class (class MonadEffect, liftEffect) -import HTTP.MIME (MIME) -import HTTP.MIME as MIME +import Data.MIME (MIME) +import Data.MIME as MIME newtype ContentType = ContentType MIME diff --git a/src/HTTP/Request.js b/src/Effect.Aff.HTTP/Request.js similarity index 74% rename from src/HTTP/Request.js rename to src/Effect.Aff.HTTP/Request.js index 0deb6d8..7d70917 100644 --- a/src/HTTP/Request.js +++ b/src/Effect.Aff.HTTP/Request.js @@ -9,8 +9,8 @@ export const rawBodySize = body => () => body instanceof ArrayBuffer ? body.byteLength : body instanceof FormData - ? Array.from(body.entries()).reduce( - (size, [k, v]) => size + k.length + formDataValueSize(v), - 0, - ) - : 0 + ? Array.from(body.entries()).reduce( + (size, [k, v]) => size + k.length + formDataValueSize(v), + 0, + ) + : 0 diff --git a/src/HTTP/Request.purs b/src/Effect.Aff.HTTP/Request.purs similarity index 91% rename from src/HTTP/Request.purs rename to src/Effect.Aff.HTTP/Request.purs index 84b46cb..8f2299b 100644 --- a/src/HTTP/Request.purs +++ b/src/Effect.Aff.HTTP/Request.purs @@ -1,4 +1,4 @@ -module HTTP.Request +module Effect.Aff.HTTP.Request ( Credentials(..) , Body(..) , RawBody @@ -25,12 +25,12 @@ import Data.Show.Generic (genericShow) import Effect (Effect) import Effect.Aff.Class (class MonadAff, liftAff) import Effect.Class (class MonadEffect, liftEffect) -import HTTP.Form (Form, RawFormData) -import HTTP.Form as Form -import HTTP.Header (ContentType(..), Headers) -import HTTP.Header as Header -import HTTP.MIME (MIME) -import HTTP.MIME as MIME +import Effect.Aff.HTTP.Form (Form, RawFormData) +import Effect.Aff.HTTP.Form as Form +import Effect.Aff.HTTP.Header (ContentType(..), Headers) +import Effect.Aff.HTTP.Header as Header +import Data.MIME (MIME) +import Data.MIME as MIME import Simple.JSON (class WriteForeign, writeJSON) import Unsafe.Coerce (unsafeCoerce) import Web.File.Blob (Blob) diff --git a/src/HTTP/Response.Node.js b/src/Effect.Aff.HTTP/Response.Node.js similarity index 85% rename from src/HTTP/Response.Node.js rename to src/Effect.Aff.HTTP/Response.Node.js index 3dad01c..495a397 100644 --- a/src/HTTP/Response.Node.js +++ b/src/Effect.Aff.HTTP/Response.Node.js @@ -1,5 +1,5 @@ -import { Readable } from 'stream'; -import { Buffer } from 'buffer'; +import { Readable } from 'stream' +import { Buffer } from 'buffer' /** @type {(r: Response) => () => Promise} */ export const bufferImpl = r => async () => Buffer.from(await r.arrayBuffer()) @@ -10,7 +10,7 @@ export const streamImpl = r => () => { throw new Error('Response body is empty') } - const reader = r.body.getReader(); + const reader = r.body.getReader() return new Readable({ read() { reader diff --git a/src/HTTP/Response.Node.purs b/src/Effect.Aff.HTTP/Response.Node.purs similarity index 82% rename from src/HTTP/Response.Node.purs rename to src/Effect.Aff.HTTP/Response.Node.purs index d0b5daf..4a1a8ad 100644 --- a/src/HTTP/Response.Node.purs +++ b/src/Effect.Aff.HTTP/Response.Node.purs @@ -1,4 +1,4 @@ -module HTTP.Response.Node +module Effect.Aff.HTTP.Response.Node ( module X , buffer , stream @@ -11,8 +11,8 @@ import Control.Promise as Promise import Effect (Effect) import Effect.Aff.Class (class MonadAff, liftAff) import Effect.Class (class MonadEffect, liftEffect) -import HTTP.Response (Response) -import HTTP.Response hiding (stream) as X +import Effect.Aff.HTTP.Response (Response) +import Effect.Aff.HTTP.Response hiding (stream) as X import Node.Buffer (Buffer) import Node.Stream (Readable) diff --git a/src/HTTP/Response.js b/src/Effect.Aff.HTTP/Response.js similarity index 100% rename from src/HTTP/Response.js rename to src/Effect.Aff.HTTP/Response.js diff --git a/src/HTTP/Response.purs b/src/Effect.Aff.HTTP/Response.purs similarity index 96% rename from src/HTTP/Response.purs rename to src/Effect.Aff.HTTP/Response.purs index f906b22..97bf78c 100644 --- a/src/HTTP/Response.purs +++ b/src/Effect.Aff.HTTP/Response.purs @@ -1,4 +1,4 @@ -module HTTP.Response +module Effect.Aff.HTTP.Response ( Response(..) , stream , clone @@ -31,8 +31,8 @@ import Effect.Class (class MonadEffect, liftEffect) import Effect.Exception (Error, error) import Foreign (Foreign) import Foreign.Object (Object) -import HTTP.Form (Form, RawFormData) -import HTTP.Form as Form +import Effect.Aff.HTTP.Form (Form, RawFormData) +import Effect.Aff.HTTP.Form as Form import Simple.JSON (class ReadForeign, readImpl) import Web.File.Blob (Blob) import Web.Streams.ReadableStream (ReadableStream)