From 71bde281604ebf219faa766888c275fc3ba305d2 Mon Sep 17 00:00:00 2001 From: Thomas Honeyman Date: Thu, 15 Oct 2026 18:04:26 +0000 Subject: [PATCH 1/9] Migrate package tooling and CI to Spago --- .eslintrc.json | 26 -------------------------- .github/workflows/ci.yml | 33 ++++++++++++++++----------------- .gitignore | 6 ++++-- .oxfmtrc.json | 3 +++ .tidyrc.json | 10 ++++++++++ CHANGELOG.md | 11 +++-------- bower.json | 36 ------------------------------------ examples/spago.yaml | 15 +++++++++++++++ package.json | 17 ++++++++++------- spago.yaml | 23 +++++++++++++++++++++++ 10 files changed, 84 insertions(+), 96 deletions(-) delete mode 100644 .eslintrc.json create mode 100644 .oxfmtrc.json create mode 100644 .tidyrc.json delete mode 100644 bower.json create mode 100644 examples/spago.yaml create mode 100644 spago.yaml diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 1c6afb9..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "parserOptions": { - "ecmaVersion": 6, - "sourceType": "module" - }, - "extends": "eslint:recommended", - "rules": { - "strict": [2, "global"], - "block-scoped-var": 2, - "consistent-return": 2, - "eqeqeq": [2, "smart"], - "guard-for-in": 2, - "no-caller": 2, - "no-extend-native": 2, - "no-loop-func": 2, - "no-new": 2, - "no-param-reassign": 2, - "no-return-assign": 2, - "no-unused-expressions": 2, - "no-use-before-define": 2, - "radix": [2, "always"], - "indent": [2, 2], - "quotes": [2, "double"], - "semi": [2, "always"] - } -} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c69237a..c7fdf3b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,30 +6,29 @@ on: pull_request: branches: [master] +permissions: + contents: read + jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - - uses: purescript-contrib/setup-purescript@main - with: - purescript: "unstable" - - - uses: actions/setup-node@v2 + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 with: - node-version: "14.x" + node-version: "24" - name: Install dependencies - run: | - npm install -g bower - npm install - bower install --production + run: npm install - name: Build source - run: npm run-script build + run: npm run build + + - name: Build examples + run: npm test + + - name: Lint + run: npm run lint - - name: Run tests - run: | - bower install - npm run-script test --if-present + - name: Check formatting + run: npm run format:check diff --git a/.gitignore b/.gitignore index b846b63..7ddb3b1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,10 @@ /.* !/.gitignore -!/.eslintrc.json +!/.tidyrc.json +!/.oxfmtrc.json !/.github/ /bower_components/ /node_modules/ /output/ -package-lock.json +/package-lock.json +/spago.lock diff --git a/.oxfmtrc.json b/.oxfmtrc.json new file mode 100644 index 0000000..757fd64 --- /dev/null +++ b/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "trailingComma": "es5" +} diff --git a/.tidyrc.json b/.tidyrc.json new file mode 100644 index 0000000..9e39cf1 --- /dev/null +++ b/.tidyrc.json @@ -0,0 +1,10 @@ +{ + "importSort": "ide", + "importWrap": "source", + "indent": 2, + "operatorsFile": null, + "ribbon": 1, + "typeArrowPlacement": "first", + "unicode": "never", + "width": null +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 40eec6a..0a3bf5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,16 +2,12 @@ Notable changes to this project are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] - -Breaking changes: - -New features: - -Bugfixes: +## [v7.0.1](https://github.com/purescript/purescript-foreign/releases/tag/v7.0.1) Other improvements: +- Migrate from Bower/Pulp to Spago and update CI, linting, and formatting. + ## [v7.0.0](https://github.com/purescript/purescript-foreign/releases/tag/v7.0.0) - 2022-04-27 Breaking changes: @@ -194,4 +190,3 @@ Quite a few breaking changes to both names and types: ## [v0.1.0](https://github.com/purescript/purescript-foreign/releases/tag/v0.1.0) - 2014-04-26 - diff --git a/bower.json b/bower.json deleted file mode 100644 index c84d014..0000000 --- a/bower.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "purescript-foreign", - "homepage": "https://github.com/purescript/purescript-foreign", - "authors": [ - "Gary Burgess ", - "Phil Freeman " - ], - "repository": { - "type": "git", - "url": "https://github.com/purescript/purescript-foreign.git" - }, - "license": "BSD-3-Clause", - "ignore": [ - "**/.*", - "bower_components", - "examples", - "node_modules", - "output", - "bower.json", - "package.json" - ], - "dependencies": { - "purescript-either": "^6.0.0", - "purescript-functions": "^6.0.0", - "purescript-identity": "^6.0.0", - "purescript-integers": "^6.0.0", - "purescript-lists": "^7.0.0", - "purescript-maybe": "^6.0.0", - "purescript-prelude": "^6.0.0", - "purescript-strings": "^6.0.0", - "purescript-transformers": "^6.0.0" - }, - "devDependencies": { - "purescript-console": "^6.0.0" - } -} diff --git a/examples/spago.yaml b/examples/spago.yaml new file mode 100644 index 0000000..5aaaf60 --- /dev/null +++ b/examples/spago.yaml @@ -0,0 +1,15 @@ +package: + name: foreign-examples + build: + strict: true + pedanticPackages: true + dependencies: + - console: ">=6.0.0 <7.0.0" + - effect: ">=4.0.0 <5.0.0" + - foreign: "*" + - functions: ">=6.0.0 <7.0.0" + - lists: ">=7.0.0 <8.0.0" + - maybe: ">=6.0.0 <7.0.0" + - prelude: ">=6.0.0 <7.0.0" + - transformers: ">=6.0.0 <7.0.0" + - traversable: ">=6.0.0 <7.0.0" diff --git a/package.json b/package.json index 2353ab5..748f099 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,17 @@ { "private": true, "scripts": { - "clean": "rimraf output && rimraf .pulp-cache", - "build": "eslint src && pulp build -- --censor-lib --strict", - "test": "pulp build -I examples -- --censor-lib --strict" + "build": "spago build -p foreign", + "test": "spago build -p foreign-examples", + "lint": "oxlint --deny-warnings src examples/src", + "format": "purs-tidy format-in-place src examples/src && oxfmt --write .", + "format:check": "purs-tidy check src examples/src && oxfmt --check ." }, "devDependencies": { - "eslint": "^7.15.0", - "pulp": "16.0.0-0", - "purescript-psa": "^0.8.2", - "rimraf": "^3.0.2" + "oxfmt": "^0.73.0", + "oxlint": "^1.88.0", + "purescript": "^0.15.16", + "purs-tidy": "^0.11.1", + "spago": "^1.0.5" } } diff --git a/spago.yaml b/spago.yaml new file mode 100644 index 0000000..28479e9 --- /dev/null +++ b/spago.yaml @@ -0,0 +1,23 @@ +package: + name: foreign + description: Library for dealing with foreign data (JavaScript objects). + build: + strict: true + pedanticPackages: true + publish: + version: 7.0.1 + license: BSD-3-Clause + location: + githubOwner: purescript + githubRepo: purescript-foreign + dependencies: + - either: ">=6.0.0 <7.0.0" + - functions: ">=6.0.0 <7.0.0" + - integers: ">=6.0.0 <7.0.0" + - lists: ">=7.0.0 <8.0.0" + - maybe: ">=6.0.0 <7.0.0" + - prelude: ">=6.0.0 <7.0.0" + - strings: ">=6.0.0 <7.0.0" + - transformers: ">=6.0.0 <7.0.0" + - unsafe-coerce: ">=6.0.0 <7.0.0" +workspace: {} From 3c88d298f216f4bf46c630b0d9be9c13fbdedacd Mon Sep 17 00:00:00 2001 From: Thomas Honeyman Date: Thu, 15 Oct 2026 18:04:46 +0000 Subject: [PATCH 2/9] Move examples into their Spago package source directory --- README.md | 18 +++++++++--------- examples/{ => src}/Applicative.purs | 0 examples/{ => src}/Arrays.purs | 0 examples/{ => src}/Complex.purs | 0 examples/{ => src}/MaybeNullable.purs | 0 examples/{ => src}/Nested.purs | 0 examples/{ => src}/Objects.purs | 0 examples/{ => src}/ParseErrors.purs | 0 examples/{ => src}/SimpleTypes.purs | 0 examples/{ => src}/Union.purs | 0 examples/{ => src}/Util/Value.js | 0 examples/{ => src}/Util/Value.purs | 0 12 files changed, 9 insertions(+), 9 deletions(-) rename examples/{ => src}/Applicative.purs (100%) rename examples/{ => src}/Arrays.purs (100%) rename examples/{ => src}/Complex.purs (100%) rename examples/{ => src}/MaybeNullable.purs (100%) rename examples/{ => src}/Nested.purs (100%) rename examples/{ => src}/Objects.purs (100%) rename examples/{ => src}/ParseErrors.purs (100%) rename examples/{ => src}/SimpleTypes.purs (100%) rename examples/{ => src}/Union.purs (100%) rename examples/{ => src}/Util/Value.js (100%) rename examples/{ => src}/Util/Value.purs (100%) diff --git a/README.md b/README.md index a7676dd..6edca88 100644 --- a/README.md +++ b/README.md @@ -14,15 +14,15 @@ spago install foreign ## Examples -- [Simple types](examples/SimpleTypes.purs) -- [Arrays](examples/Arrays.purs) -- [Objects](examples/Objects.purs) -- [Complex objects](examples/Complex.purs) -- [Applicative style parser](examples/Applicative.purs) -- [Maybe for nulls](examples/MaybeNullable.purs) -- [Nested objects](examples/Nested.purs) -- [Unions](examples/Union.purs) -- [Parser errors](examples/ParseErrors.purs) +- [Simple types](examples/src/SimpleTypes.purs) +- [Arrays](examples/src/Arrays.purs) +- [Objects](examples/src/Objects.purs) +- [Complex objects](examples/src/Complex.purs) +- [Applicative style parser](examples/src/Applicative.purs) +- [Maybe for nulls](examples/src/MaybeNullable.purs) +- [Nested objects](examples/src/Nested.purs) +- [Unions](examples/src/Union.purs) +- [Parser errors](examples/src/ParseErrors.purs) ## Documentation diff --git a/examples/Applicative.purs b/examples/src/Applicative.purs similarity index 100% rename from examples/Applicative.purs rename to examples/src/Applicative.purs diff --git a/examples/Arrays.purs b/examples/src/Arrays.purs similarity index 100% rename from examples/Arrays.purs rename to examples/src/Arrays.purs diff --git a/examples/Complex.purs b/examples/src/Complex.purs similarity index 100% rename from examples/Complex.purs rename to examples/src/Complex.purs diff --git a/examples/MaybeNullable.purs b/examples/src/MaybeNullable.purs similarity index 100% rename from examples/MaybeNullable.purs rename to examples/src/MaybeNullable.purs diff --git a/examples/Nested.purs b/examples/src/Nested.purs similarity index 100% rename from examples/Nested.purs rename to examples/src/Nested.purs diff --git a/examples/Objects.purs b/examples/src/Objects.purs similarity index 100% rename from examples/Objects.purs rename to examples/src/Objects.purs diff --git a/examples/ParseErrors.purs b/examples/src/ParseErrors.purs similarity index 100% rename from examples/ParseErrors.purs rename to examples/src/ParseErrors.purs diff --git a/examples/SimpleTypes.purs b/examples/src/SimpleTypes.purs similarity index 100% rename from examples/SimpleTypes.purs rename to examples/src/SimpleTypes.purs diff --git a/examples/Union.purs b/examples/src/Union.purs similarity index 100% rename from examples/Union.purs rename to examples/src/Union.purs diff --git a/examples/Util/Value.js b/examples/src/Util/Value.js similarity index 100% rename from examples/Util/Value.js rename to examples/src/Util/Value.js diff --git a/examples/Util/Value.purs b/examples/src/Util/Value.purs similarity index 100% rename from examples/Util/Value.purs rename to examples/src/Util/Value.purs From aabdce249ce54373cc1760f5867922010904fa17 Mon Sep 17 00:00:00 2001 From: Thomas Honeyman Date: Thu, 15 Oct 2026 18:05:37 +0000 Subject: [PATCH 3/9] Use the registry name for the examples traversable dependency --- examples/spago.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/spago.yaml b/examples/spago.yaml index 5aaaf60..df1454c 100644 --- a/examples/spago.yaml +++ b/examples/spago.yaml @@ -6,10 +6,10 @@ package: dependencies: - console: ">=6.0.0 <7.0.0" - effect: ">=4.0.0 <5.0.0" + - foldable-traversable: ">=6.0.0 <7.0.0" - foreign: "*" - functions: ">=6.0.0 <7.0.0" - lists: ">=7.0.0 <8.0.0" - maybe: ">=6.0.0 <7.0.0" - prelude: ">=6.0.0 <7.0.0" - transformers: ">=6.0.0 <7.0.0" - - traversable: ">=6.0.0 <7.0.0" From 9140bb706e05efaf2d76c4336f0d5b449c927790 Mon Sep 17 00:00:00 2001 From: Thomas Honeyman Date: Thu, 15 Oct 2026 18:06:09 +0000 Subject: [PATCH 4/9] Put the multiline example conditional branch on its own line --- examples/src/Union.purs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/src/Union.purs b/examples/src/Union.purs index feee5d1..73a6e2d 100755 --- a/examples/src/Union.purs +++ b/examples/src/Union.purs @@ -21,7 +21,8 @@ readStringList value = value ! "nil" >>= readBoolean >>= if _ - then pure Nil + then + pure Nil else Cons <$> (value ! "head" >>= readString) From c1b44b85c64c7467fd1f899695ac620f33aa0229 Mon Sep 17 00:00:00 2001 From: Thomas Honeyman Date: Thu, 15 Oct 2026 18:06:47 +0000 Subject: [PATCH 5/9] Format PureScript and repository files --- CHANGELOG.md | 17 +++++++++-------- examples/src/Applicative.purs | 2 +- examples/src/Complex.purs | 2 +- examples/src/MaybeNullable.purs | 8 +++----- examples/src/SimpleTypes.purs | 2 +- examples/src/Union.purs | 8 ++++---- examples/src/Util/Value.purs | 1 - src/Foreign.js | 8 +++++--- src/Foreign/Index.purs | 8 ++++---- src/Foreign/Keys.js | 18 ++++++++++-------- src/Foreign/Keys.purs | 2 +- 11 files changed, 39 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a3bf5d..548ff9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ Other improvements: ## [v7.0.0](https://github.com/purescript/purescript-foreign/releases/tag/v7.0.0) - 2022-04-27 Breaking changes: + - Migrate FFI to ES modules (#86 by @kl0tl and @JordanMartinez) New features: @@ -18,6 +19,7 @@ New features: Bugfixes: Other improvements: + - Replace all usages of `F` and `FT` with `Except`/`ExceptT (NonEmptyList ForeignError)` (#87 by @JordanMartinez) Often times, the `F` and `FT` aliases did more to hinder usage of this library than help. These aliases @@ -27,14 +29,17 @@ Other improvements: ## [v6.0.1](https://github.com/purescript/purescript-foreign/releases/tag/v6.0.1) - 2021-04-20 Other improvements: + - Fix warnings revealed by v0.14.1 PureScript release (#85 by @JordanMartinez) ## [v6.0.0](https://github.com/purescript/purescript-foreign/releases/tag/v6.0.0) - 2021-02-26 Breaking changes: + - Added support for PureScript 0.14 and dropped support for all previous versions (#80) Other improvements: + - Migrated CI to GitHub Actions and updated installation instructions to use Spago (#81) - Added a CHANGELOG.md file and pull request template (#82, #83) - Replaced `unsafeToForeign` and `unsafeFromForeign` with `unsafeCoerce` (#72) @@ -55,8 +60,8 @@ Fix `Show` instance for `ForeignError` (@rightfold) - Updated for PureScript 0.11 - The library has been drastically simplified to focus on its core use; validating and extracting data from foreign values. This involves changes such as: - - Removal of `IsForeign` / `AsForeign` classes - - Removal of `parseJSON` as this library is not intended for general JSON parsing + - Removal of `IsForeign` / `AsForeign` classes + - Removal of `parseJSON` as this library is not intended for general JSON parsing - New functions were added for `readNull`, `readUndefined`, `readNullOrUndefined` rather than using the newtypes to direct `IsForeign` choice as it was before - The `(!)` index/property reading operator has been enhanced to work with `Foreign` or `F Foreign` on the left hand side, allowing for chained property reads @@ -134,6 +139,7 @@ Updated docs ## [v0.4.0](https://github.com/purescript/purescript-foreign/releases/tag/v0.4.0) - 2015-02-21 **This release requires PureScript v0.6.8 or later** + - Updated dependencies ## [v0.3.0](https://github.com/purescript/purescript-foreign/releases/tag/v0.3.0) - 2015-01-10 @@ -146,8 +152,6 @@ Updated docs ## [v0.2.2](https://github.com/purescript/purescript-foreign/releases/tag/v0.2.2) - 2014-11-19 - - ## [v0.2.1](https://github.com/purescript/purescript-foreign/releases/tag/v0.2.1) - 2014-11-18 - `IsForeign` instance for `Foreign`. (@MichaelXavier) @@ -155,6 +159,7 @@ Updated docs ## [v0.2.0](https://github.com/purescript/purescript-foreign/releases/tag/v0.2.0) - 2014-08-20 Quite a few breaking changes to both names and types: + - A type for errors instead of using string concatenation. - Breaking a few functions out into their own submodules. - Adding types and instances to handle null-like values. @@ -185,8 +190,4 @@ Quite a few breaking changes to both names and types: ## [v0.1.1](https://github.com/purescript/purescript-foreign/releases/tag/v0.1.1) - 2014-04-27 - - ## [v0.1.0](https://github.com/purescript/purescript-foreign/releases/tag/v0.1.0) - 2014-04-26 - - diff --git a/examples/src/Applicative.purs b/examples/src/Applicative.purs index 52961c6..25064be 100755 --- a/examples/src/Applicative.purs +++ b/examples/src/Applicative.purs @@ -13,7 +13,7 @@ import Foreign.Index ((!)) data Point = Point Number Number Number instance showPoint :: Show Point where - show (Point x y z) = "(Point " <> show [x, y, z] <> ")" + show (Point x y z) = "(Point " <> show [ x, y, z ] <> ")" readPoint :: Foreign -> Except (NonEmptyList ForeignError) Point readPoint value = do diff --git a/examples/src/Complex.purs b/examples/src/Complex.purs index 68b6875..690a7f8 100755 --- a/examples/src/Complex.purs +++ b/examples/src/Complex.purs @@ -9,7 +9,7 @@ import Data.Traversable (traverse) import Effect (Effect) import Effect.Console (logShow) import Example.Util.Value (foreignValue) -import Foreign (Foreign, ForeignError, readArray, readBoolean, readNumber, readString, readNullOrUndefined) +import Foreign (Foreign, ForeignError, readArray, readBoolean, readNullOrUndefined, readNumber, readString) import Foreign.Index ((!)) type SomeObject = diff --git a/examples/src/MaybeNullable.purs b/examples/src/MaybeNullable.purs index 1831663..9fb0e41 100755 --- a/examples/src/MaybeNullable.purs +++ b/examples/src/MaybeNullable.purs @@ -2,14 +2,12 @@ module Example.MaybeNullable where import Prelude -import Effect (Effect) -import Effect.Console (logShow) import Control.Monad.Except (runExcept) - -import Foreign (readBoolean, readNull) import Data.Traversable (traverse) - +import Effect (Effect) +import Effect.Console (logShow) import Example.Util.Value (foreignValue) +import Foreign (readBoolean, readNull) -- Parsing values that are allowed to null or undefined is possible by -- using Maybe types. diff --git a/examples/src/SimpleTypes.purs b/examples/src/SimpleTypes.purs index e3ba48c..0ae062a 100644 --- a/examples/src/SimpleTypes.purs +++ b/examples/src/SimpleTypes.purs @@ -6,7 +6,7 @@ import Control.Monad.Except (runExcept) import Effect (Effect) import Effect.Console (logShow) import Example.Util.Value (foreignValue) -import Foreign (readString, readNumber, readBoolean) +import Foreign (readBoolean, readNumber, readString) -- Parsing of the simple JSON String, Number and Boolean types is provided -- out of the box. diff --git a/examples/src/Union.purs b/examples/src/Union.purs index 73a6e2d..3d5ae5e 100755 --- a/examples/src/Union.purs +++ b/examples/src/Union.purs @@ -18,10 +18,10 @@ instance showStringList :: Show StringList where readStringList :: Foreign -> Except (NonEmptyList ForeignError) StringList readStringList value = - value ! "nil" >>= - readBoolean >>= - if _ - then + value ! "nil" + >>= readBoolean + >>= + if _ then pure Nil else Cons diff --git a/examples/src/Util/Value.purs b/examples/src/Util/Value.purs index f70cc40..ecb96b4 100644 --- a/examples/src/Util/Value.purs +++ b/examples/src/Util/Value.purs @@ -5,7 +5,6 @@ import Prelude import Control.Monad.Except (Except) import Data.Function.Uncurried (Fn3, runFn3) import Data.List.NonEmpty (NonEmptyList) - import Foreign (Foreign, ForeignError(..), fail) foreign import foreignValueImpl :: forall r. Fn3 (String -> r) (Foreign -> r) String r diff --git a/src/Foreign.js b/src/Foreign.js index fdea3ee..9bdcc07 100644 --- a/src/Foreign.js +++ b/src/Foreign.js @@ -14,6 +14,8 @@ export function isUndefined(value) { return value === undefined; } -export const isArray = Array.isArray || function (value) { - return Object.prototype.toString.call(value) === "[object Array]"; -}; +export const isArray = + Array.isArray || + function (value) { + return Object.prototype.toString.call(value) === "[object Array]"; + }; diff --git a/src/Foreign/Index.purs b/src/Foreign/Index.purs index 994db83..43f184e 100644 --- a/src/Foreign/Index.purs +++ b/src/Foreign/Index.purs @@ -6,7 +6,8 @@ module Foreign.Index , class Indexable , readProp , readIndex - , ix, (!) + , ix + , (!) , index , hasProperty , hasOwnProperty @@ -16,10 +17,9 @@ module Foreign.Index import Prelude import Control.Monad.Except.Trans (ExceptT) - -import Foreign (Foreign, ForeignError(..), typeOf, isUndefined, isNull, fail) -import Data.Function.Uncurried (Fn2, runFn2, Fn4, runFn4) +import Data.Function.Uncurried (Fn2, Fn4, runFn2, runFn4) import Data.List.NonEmpty (NonEmptyList) +import Foreign (Foreign, ForeignError(..), fail, isNull, isUndefined, typeOf) -- | This type class identifies types that act like _property indices_. -- | diff --git a/src/Foreign/Keys.js b/src/Foreign/Keys.js index f5b8f0c..30ed968 100644 --- a/src/Foreign/Keys.js +++ b/src/Foreign/Keys.js @@ -1,9 +1,11 @@ -export const unsafeKeys = Object.keys || function (value) { - var keys = []; - for (var prop in value) { - if (Object.prototype.hasOwnProperty.call(value, prop)) { - keys.push(prop); +export const unsafeKeys = + Object.keys || + function (value) { + var keys = []; + for (var prop in value) { + if (Object.prototype.hasOwnProperty.call(value, prop)) { + keys.push(prop); + } } - } - return keys; -}; + return keys; + }; diff --git a/src/Foreign/Keys.purs b/src/Foreign/Keys.purs index bca6595..8f6d1f7 100644 --- a/src/Foreign/Keys.purs +++ b/src/Foreign/Keys.purs @@ -7,9 +7,9 @@ module Foreign.Keys import Prelude -import Foreign (Foreign, ForeignError(..), typeOf, isUndefined, isNull, fail) import Control.Monad.Except (ExceptT) import Data.List.NonEmpty (NonEmptyList) +import Foreign (Foreign, ForeignError(..), fail, isNull, isUndefined, typeOf) foreign import unsafeKeys :: Foreign -> Array String From cd99e4d50c95f0c9c32cb78d31635b82e0bfc532 Mon Sep 17 00:00:00 2001 From: Thomas Honeyman Date: Thu, 15 Oct 2026 18:12:48 +0000 Subject: [PATCH 6/9] Credit the migration pull request in the changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 548ff9c..2db98b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ Notable changes to this project are documented in this file. The format is based Other improvements: -- Migrate from Bower/Pulp to Spago and update CI, linting, and formatting. +- Migrate from Bower/Pulp to Spago and update CI, linting, and formatting (#89 by @thomashoneyman). ## [v7.0.0](https://github.com/purescript/purescript-foreign/releases/tag/v7.0.0) - 2022-04-27 From 2eab552f76cb68d12d291b55f52e1e707df78adb Mon Sep 17 00:00:00 2001 From: Thomas Honeyman Date: Thu, 15 Oct 2026 21:26:10 +0000 Subject: [PATCH 7/9] Restore Unreleased changelog template and date proposed release --- CHANGELOG.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2db98b2..eb6d6a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,17 @@ Notable changes to this project are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [v7.0.1](https://github.com/purescript/purescript-foreign/releases/tag/v7.0.1) +## [Unreleased] + +Breaking changes: + +New features: + +Bugfixes: + +Other improvements: + +## [v7.0.1](https://github.com/purescript/purescript-foreign/releases/tag/v7.0.1) - 2026-10-17 Other improvements: From 6df91240eea7bf3ecabc17fb468663e590130a1d Mon Sep 17 00:00:00 2001 From: Thomas Honeyman Date: Sat, 17 Oct 2026 13:02:58 +0000 Subject: [PATCH 8/9] Apply reviewed case and conditional layouts --- examples/src/Union.purs | 23 ++++++++-------- src/Foreign.purs | 58 +++++++++++++++++++++++++---------------- src/Foreign/Index.purs | 22 ++++++++++------ src/Foreign/Keys.purs | 11 ++++---- 4 files changed, 66 insertions(+), 48 deletions(-) diff --git a/examples/src/Union.purs b/examples/src/Union.purs index 3d5ae5e..d181e40 100755 --- a/examples/src/Union.purs +++ b/examples/src/Union.purs @@ -13,20 +13,19 @@ import Foreign.Index ((!)) data StringList = Nil | Cons String StringList instance showStringList :: Show StringList where - show Nil = "Nil" - show (Cons s l) = "(Cons " <> show s <> " " <> show l <> ")" + show = case _ of + Nil -> "Nil" + Cons s l -> "(Cons " <> show s <> " " <> show l <> ")" readStringList :: Foreign -> Except (NonEmptyList ForeignError) StringList -readStringList value = - value ! "nil" - >>= readBoolean - >>= - if _ then - pure Nil - else - Cons - <$> (value ! "head" >>= readString) - <*> (value ! "tail" >>= readStringList) +readStringList value = do + isNil <- value ! "nil" >>= readBoolean + if isNil then + pure Nil + else + Cons + <$> (value ! "head" >>= readString) + <*> (value ! "tail" >>= readStringList) main :: Effect Unit main = do diff --git a/src/Foreign.purs b/src/Foreign.purs index e655e25..2482504 100644 --- a/src/Foreign.purs +++ b/src/Foreign.purs @@ -67,19 +67,21 @@ derive instance eqForeignError :: Eq ForeignError derive instance ordForeignError :: Ord ForeignError instance showForeignError :: Show ForeignError where - show (ForeignError msg) = "(ForeignError " <> show msg <> ")" - show (ErrorAtIndex i e) = "(ErrorAtIndex " <> show i <> " " <> show e <> ")" - show (ErrorAtProperty prop e) = "(ErrorAtProperty " <> show prop <> " " <> show e <> ")" - show (TypeMismatch exps act) = "(TypeMismatch " <> show exps <> " " <> show act <> ")" + show = case _ of + ForeignError msg -> "(ForeignError " <> show msg <> ")" + ErrorAtIndex i e -> "(ErrorAtIndex " <> show i <> " " <> show e <> ")" + ErrorAtProperty prop e -> "(ErrorAtProperty " <> show prop <> " " <> show e <> ")" + TypeMismatch exps act -> "(TypeMismatch " <> show exps <> " " <> show act <> ")" -- | A type for accumulating multiple `ForeignError`s. type MultipleErrors = NonEmptyList ForeignError renderForeignError :: ForeignError -> String -renderForeignError (ForeignError msg) = msg -renderForeignError (ErrorAtIndex i e) = "Error at array index " <> show i <> ": " <> renderForeignError e -renderForeignError (ErrorAtProperty prop e) = "Error at property " <> show prop <> ": " <> renderForeignError e -renderForeignError (TypeMismatch exp act) = "Type mismatch: expected " <> exp <> ", found " <> act +renderForeignError = case _ of + ForeignError msg -> msg + ErrorAtIndex i e -> "Error at array index " <> show i <> ": " <> renderForeignError e + ErrorAtProperty prop e -> "Error at property " <> show prop <> ": " <> renderForeignError e + TypeMismatch exp act -> "Type mismatch: expected " <> exp <> ", found " <> act -- | While this alias is not deprecated, it is recommended -- | that one use `Except (NonEmptyList ForeignError)` directly @@ -121,9 +123,11 @@ foreign import tagOf :: Foreign -> String -- | Unsafely coerce a `Foreign` value when the value has a particular `tagOf` -- | value. unsafeReadTagged :: forall m a. Monad m => String -> Foreign -> ExceptT (NonEmptyList ForeignError) m a -unsafeReadTagged tag value - | tagOf value == tag = pure (unsafeFromForeign value) - | otherwise = fail $ TypeMismatch tag (tagOf value) +unsafeReadTagged tag value = + if tagOf value == tag then + pure (unsafeFromForeign value) + else + fail $ TypeMismatch tag (tagOf value) -- | Test whether a foreign value is null foreign import isNull :: Foreign -> Boolean @@ -162,24 +166,32 @@ readInt value = mapExceptT (map $ either (const error) fromNumber) (readNumber v -- | Attempt to coerce a foreign value to an array. readArray :: forall m. Monad m => Foreign -> ExceptT (NonEmptyList ForeignError) m (Array Foreign) -readArray value - | isArray value = pure $ unsafeFromForeign value - | otherwise = fail $ TypeMismatch "array" (tagOf value) +readArray value = + if isArray value then + pure $ unsafeFromForeign value + else + fail $ TypeMismatch "array" (tagOf value) readNull :: forall m. Monad m => Foreign -> ExceptT (NonEmptyList ForeignError) m (Maybe Foreign) -readNull value - | isNull value = pure Nothing - | otherwise = pure (Just value) +readNull value = + if isNull value then + pure Nothing + else + pure (Just value) readUndefined :: forall m. Monad m => Foreign -> ExceptT (NonEmptyList ForeignError) m (Maybe Foreign) -readUndefined value - | isUndefined value = pure Nothing - | otherwise = pure (Just value) +readUndefined value = + if isUndefined value then + pure Nothing + else + pure (Just value) readNullOrUndefined :: forall m. Monad m => Foreign -> ExceptT (NonEmptyList ForeignError) m (Maybe Foreign) -readNullOrUndefined value - | isNull value || isUndefined value = pure Nothing - | otherwise = pure (Just value) +readNullOrUndefined value = + if isNull value || isUndefined value then + pure Nothing + else + pure (Just value) -- | Throws a failure error in `ExceptT (NonEmptyList ForeignError) m`. fail :: forall m a. Monad m => ForeignError -> ExceptT (NonEmptyList ForeignError) m a diff --git a/src/Foreign/Index.purs b/src/Foreign/Index.purs index 43f184e..c45c1a3 100644 --- a/src/Foreign/Index.purs +++ b/src/Foreign/Index.purs @@ -52,18 +52,24 @@ readIndex = unsafeReadProp foreign import unsafeHasOwnProperty :: forall k. Fn2 k Foreign Boolean hasOwnPropertyImpl :: forall k. k -> Foreign -> Boolean -hasOwnPropertyImpl _ value | isNull value = false -hasOwnPropertyImpl _ value | isUndefined value = false -hasOwnPropertyImpl p value | typeOf value == "object" || typeOf value == "function" = runFn2 unsafeHasOwnProperty p value -hasOwnPropertyImpl _ _ = false +hasOwnPropertyImpl p = case _ of + value + | isNull value -> false + | isUndefined value -> false + | typeOf value == "object" || typeOf value == "function" -> + runFn2 unsafeHasOwnProperty p value + | otherwise -> false foreign import unsafeHasProperty :: forall k. Fn2 k Foreign Boolean hasPropertyImpl :: forall k. k -> Foreign -> Boolean -hasPropertyImpl _ value | isNull value = false -hasPropertyImpl _ value | isUndefined value = false -hasPropertyImpl p value | typeOf value == "object" || typeOf value == "function" = runFn2 unsafeHasProperty p value -hasPropertyImpl _ _ = false +hasPropertyImpl p = case _ of + value + | isNull value -> false + | isUndefined value -> false + | typeOf value == "object" || typeOf value == "function" -> + runFn2 unsafeHasProperty p value + | otherwise -> false instance indexString :: Monad m => Index String m where index = flip readProp diff --git a/src/Foreign/Keys.purs b/src/Foreign/Keys.purs index 8f6d1f7..ed463d3 100644 --- a/src/Foreign/Keys.purs +++ b/src/Foreign/Keys.purs @@ -15,8 +15,9 @@ foreign import unsafeKeys :: Foreign -> Array String -- | Get an array of the properties defined on a foreign value keys :: forall m. Monad m => Foreign -> ExceptT (NonEmptyList ForeignError) m (Array String) -keys value - | isNull value = fail $ TypeMismatch "object" "null" - | isUndefined value = fail $ TypeMismatch "object" "undefined" - | typeOf value == "object" = pure $ unsafeKeys value - | otherwise = fail $ TypeMismatch "object" (typeOf value) +keys = case _ of + value + | isNull value -> fail $ TypeMismatch "object" "null" + | isUndefined value -> fail $ TypeMismatch "object" "undefined" + | typeOf value == "object" -> pure $ unsafeKeys value + | otherwise -> fail $ TypeMismatch "object" (typeOf value) From 02d3aa28d8467f9164eedbc277a5d8e9645aab05 Mon Sep 17 00:00:00 2001 From: Thomas Honeyman Date: Sat, 17 Oct 2026 16:30:24 +0000 Subject: [PATCH 9/9] Link the Unreleased changelog section --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb6d6a5..f53819b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ Notable changes to this project are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [Unreleased](https://github.com/purescript/purescript-foreign/compare/v7.0.1...HEAD) Breaking changes: