diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 81104c4..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, { "SwitchCase": 1 }], - "quotes": [2, "double"], - "semi": [2, "always"] - } -} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c69237a..1a2a70b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,30 +6,30 @@ 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/checkout@v6 - - uses: actions/setup-node@v2 + - 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: Run tests - run: | - bower install - npm run-script test --if-present + run: npm test + + - name: Lint + run: npm run lint + + - 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 7e4e6c5..209935b 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-record/compare/v4.0.1...HEAD) Breaking changes: @@ -12,9 +12,16 @@ Bugfixes: Other improvements: +## [v4.0.1](https://github.com/purescript/purescript-record/releases/tag/v4.0.1) - 2026-10-17 + +Other improvements: + +- Migrate from Bower/Pulp to Spago and update CI (#87 by @thomashoneyman) + ## [v4.0.0](https://github.com/purescript/purescript-record/releases/tag/v4.0.0) - 2022-04-27 Breaking changes: + - Migrate FFI to ES modules (#81 by @kl0tl and @JordanMartinez) - Replaced polymorphic proxies with monomorphic `Proxy` (#81 by @JordanMartinez) @@ -27,17 +34,20 @@ Other improvements: ## [v3.0.0](https://github.com/purescript/purescript-record/releases/tag/v3.0.0) - 2021-02-26 Breaking changes: + - Added support for PureScript 0.14 and dropped support for all previous versions (#66) - Updated `Record.Builder.merge` and `Record.Builder.union` so that they behave like `Record.merge` and `Record.union`: fields from the argument override those of the record being built in case of overlaps. (#73) - Removed `Record.ST` (#78) New features: + - Added `buildFromScratch` for building from an empty record (#53) - Added `flip` function (#73) Bugfixes: Other improvements: + - Replaced monomorphic proxies with `Type.Proxy.Proxy` and polymorphic variants (#67) - Removed `SProxy` from documentation (#70) - Migrated CI to GitHub Actions and updated installation instructions to use Spago (#69) diff --git a/bower.json b/bower.json deleted file mode 100644 index f18b928..0000000 --- a/bower.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "purescript-record", - "homepage": "https://github.com/purescript/purescript-record", - "description": "Functions for working with records and polymorphic labels", - "license": "BSD-3-Clause", - "repository": { - "type": "git", - "url": "https://github.com/purescript/purescript-record.git" - }, - "ignore": [ - "**/.*", - "bower_components", - "node_modules", - "output", - "test", - "bower.json", - "package.json" - ], - "dependencies": { - "purescript-functions": "^6.0.0", - "purescript-prelude": "^6.0.0", - "purescript-unsafe-coerce": "^6.0.0" - }, - "devDependencies": { - "purescript-assert": "^6.0.0" - } -} diff --git a/package.json b/package.json index 8382d60..c0a8ad2 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 test" + "build": "spago build", + "test": "spago test", + "lint": "oxlint --deny-warnings src test", + "format": "purs-tidy format-in-place src test && oxfmt --write .", + "format:check": "purs-tidy check src test && oxfmt --check ." }, "devDependencies": { - "eslint": "^7.15.0", - "purescript-psa": "^0.8.2", - "pulp": "16.0.0-0", - "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..662ce83 --- /dev/null +++ b/spago.yaml @@ -0,0 +1,25 @@ +package: + name: record + description: Functions for working with records and polymorphic labels + build: + strict: true + pedanticPackages: true + publish: + version: 4.0.1 + license: BSD-3-Clause + location: + githubOwner: purescript + githubRepo: purescript-record + dependencies: + - functions: ">=6.0.0 <7.0.0" + - prelude: ">=6.0.0 <7.0.0" + - unsafe-coerce: ">=6.0.0 <7.0.0" + test: + main: Test.Main + strict: true + pedanticPackages: true + dependencies: + - assert: ">=6.0.0 <7.0.0" + - effect: ">=4.0.0 <5.0.0" + +workspace: {} diff --git a/src/Record.purs b/src/Record.purs index 11154ca..4c140a5 100644 --- a/src/Record.purs +++ b/src/Record.purs @@ -18,9 +18,9 @@ import Prelude import Data.Function.Uncurried (runFn2) import Data.Symbol (class IsSymbol, reflectSymbol) -import Prim.Row (class Lacks, class Cons, class Nub, class Union) -import Prim.RowList (class RowToList, RowList, Cons, Nil) -import Record.Unsafe (unsafeGet, unsafeSet, unsafeDelete) +import Prim.Row (class Cons, class Lacks, class Nub, class Union) +import Prim.RowList (class RowToList, Cons, Nil, RowList) +import Record.Unsafe (unsafeDelete, unsafeGet, unsafeSet) import Record.Unsafe.Union (unsafeUnionFn) import Type.Proxy (Proxy(..)) import Unsafe.Coerce (unsafeCoerce) @@ -136,7 +136,8 @@ delete l r = unsafeDelete (reflectSymbol l) r -- | rename (Proxy :: Proxy "x") (Proxy :: Proxy "y") -- | :: forall a r. Lacks "x" r => Lacks "y" r => { x :: a | r} -> { y :: a | r} -- | ``` -rename :: forall prev next ty input inter output +rename + :: forall prev next ty input inter output . IsSymbol prev => IsSymbol next => Cons prev ty inter input @@ -226,17 +227,17 @@ equal a b = equalFields (Proxy :: Proxy rs) a b class EqualFields (rs :: RowList Type) (row :: Row Type) | rs -> row where equalFields :: Proxy rs -> Record row -> Record row -> Boolean -instance equalFieldsCons - :: +instance equalFieldsCons :: ( IsSymbol name , Eq ty , Cons name ty tailRow row , EqualFields tail row - ) => EqualFields (Cons name ty tail) row where + ) => + EqualFields (Cons name ty tail) row where equalFields _ a b = get' a == get' b && equalRest a b where - get' = get (Proxy :: Proxy name) - equalRest = equalFields (Proxy :: Proxy tail) + get' = get (Proxy :: Proxy name) + equalRest = equalFields (Proxy :: Proxy tail) instance equalFieldsNil :: EqualFields Nil row where equalFields _ _ _ = true diff --git a/src/Record/Builder.js b/src/Record/Builder.js index bae6e96..d032fc3 100644 --- a/src/Record/Builder.js +++ b/src/Record/Builder.js @@ -9,8 +9,8 @@ export function copyRecord(rec) { } export function unsafeInsert(l) { - return function(a) { - return function(rec) { + return function (a) { + return function (rec) { rec[l] = a; return rec; }; @@ -19,7 +19,7 @@ export function unsafeInsert(l) { export function unsafeModify(l) { return function (f) { - return function(rec) { + return function (rec) { rec[l] = f(rec[l]); return rec; }; @@ -27,7 +27,7 @@ export function unsafeModify(l) { } export function unsafeDelete(l) { - return function(rec) { + return function (rec) { delete rec[l]; return rec; }; diff --git a/src/Record/Builder.purs b/src/Record/Builder.purs index acc204f..48c4ab3 100644 --- a/src/Record/Builder.purs +++ b/src/Record/Builder.purs @@ -86,14 +86,15 @@ modify l f = Builder \r1 -> unsafeModify (reflectSymbol l) f r1 delete :: forall l a r1 r2 . IsSymbol l - => Row.Lacks l r1 - => Row.Cons l a r1 r2 - => Proxy l - -> Builder (Record r2) (Record r1) + => Row.Lacks l r1 + => Row.Cons l a r1 r2 + => Proxy l + -> Builder (Record r2) (Record r1) delete l = Builder \r2 -> unsafeDelete (reflectSymbol l) r2 -- | Build by renaming an existing field. -rename :: forall l1 l2 a r1 r2 r3 +rename + :: forall l1 l2 a r1 r2 r3 . IsSymbol l1 => IsSymbol l2 => Row.Cons l1 a r2 r1 diff --git a/test/Examples.purs b/test/Examples.purs index 42b7b9d..0dd42e2 100644 --- a/test/Examples.purs +++ b/test/Examples.purs @@ -27,5 +27,5 @@ setX2 = Record.set x_ unit { x: 0 } modifyX :: { x :: Int } modifyX = Record.modify x_ (\value -> value + 1) { x: 0 } -mergedXY :: { x :: Int , y :: Int } +mergedXY :: { x :: Int, y :: Int } mergedXY = Record.merge { x: 1 } { y: 1 } diff --git a/test/Main.purs b/test/Main.purs index 124f3cd..ef80596 100644 --- a/test/Main.purs +++ b/test/Main.purs @@ -11,9 +11,10 @@ import Type.Proxy (Proxy(..)) main :: Effect Unit main = do - let x = Proxy :: Proxy "x" - y = Proxy :: Proxy "y" - z = Proxy :: Proxy "z" + let + x = Proxy :: Proxy "x" + y = Proxy :: Proxy "y" + z = Proxy :: Proxy "z" assert' "insert, get" $ get x (insert x 42 {}) == 42 @@ -30,39 +31,50 @@ main = do assert' "equal" $ equal { a: 1, b: "b", c: true } { a: 1, b: "b", c: true } assert' "equal2" $ - not $ equal { a: 1, b: "b", c: true } { a: 1, b: "b", c: false } + not (equal { a: 1, b: "b", c: true } { a: 1, b: "b", c: false }) assert' "merge" $ equal { x: 1, y: "y" } (merge { y: "y" } { x: 1, y: 2 }) assert' "unsafeHas1" $ unsafeHas "a" { a: 42 } assert' "unsafeHas2" $ - not $ unsafeHas "b" { a: 42 } + not (unsafeHas "b" { a: 42 }) - let testBuilder = Builder.build (Builder.insert x 42 - >>> Builder.merge { y: true, z: "testing" } - >>> Builder.delete y - >>> Builder.modify x show - >>> Builder.rename z y) {} + let + builder = + Builder.insert x 42 + >>> Builder.merge { y: true, z: "testing" } + >>> Builder.delete y + >>> Builder.modify x show + >>> Builder.rename z y + testBuilder = Builder.build builder {} assert' "Record.Builder" $ testBuilder.x == "42" && testBuilder.y == "testing" + let + merged = + Builder.build (Builder.merge { x: 1, y: "y" }) { y: 2, z: true } + :: { x :: Int, y :: String, z :: Boolean } assert' "Record.Builder.merge" $ - let { x, y, z } = Builder.build (Builder.merge { x: 1, y: "y" }) { y: 2, z: true } - :: { x :: Int, y :: String, z :: Boolean } - in x == 1 && y == "y" && z + merged.x == 1 && merged.y == "y" && merged.z + let + unioned = + Builder.build (Builder.union { x: 1, y: "y" }) { y: 2, z: true } + :: { x :: Int, y :: String, y :: Int, z :: Boolean } assert' "Record.Builder.union" $ - let { x, y, z } = Builder.build (Builder.union { x: 1, y: "y" }) { y: 2, z: true } - :: { x :: Int, y :: String, y :: Int, z :: Boolean } - in x == 1 && y == "y" && z + unioned.x == 1 && unioned.y == "y" && unioned.z + let + flipMerged = + Builder.build (Builder.flip Builder.merge { x: 1, y: "y" }) { y: 2, z: true } + :: { x :: Int, y :: Int, z :: Boolean } assert' "Record.Builder.flip merge" $ - let { x, y, z } = Builder.build (Builder.flip Builder.merge { x: 1, y: "y" }) { y: 2, z: true } - :: { x :: Int, y :: Int, z :: Boolean } - in x == 1 && y == 2 && z + flipMerged.x == 1 && flipMerged.y == 2 && flipMerged.z + let + flipUnioned = + Builder.build (Builder.flip Builder.union { x: 1, y: "y" }) { y: 2, z: true } + :: { x :: Int, y :: Int, y :: String, z :: Boolean } assert' "Record.Builder.flip union" $ - let { x, y, z } = Builder.build (Builder.flip Builder.union { x: 1, y: "y" }) { y: 2, z: true } - :: { x :: Int, y :: Int, y :: String, z :: Boolean } - in x == 1 && y == 2 && z + flipUnioned.x == 1 && flipUnioned.y == 2 && flipUnioned.z