From 15c7a7ed4fce17d3625b7cf19b53d9459f2f4171 Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Sat, 26 Apr 2025 17:44:32 +0700 Subject: [PATCH 1/2] feat: update to latest spago --- .editorconfig | 13 + .github/ISSUE_TEMPLATE/bug-report.md | 19 ++ .github/ISSUE_TEMPLATE/change-request.md | 21 ++ .github/ISSUE_TEMPLATE/config.yml | 8 + .github/PULL_REQUEST_TEMPLATE.md | 11 + .github/workflows/ci.yml | 37 +++ .gitignore | 23 +- .tidyrc.json | 10 + CHANGELOG.md | 17 ++ CONTRIBUTING.md | 5 + README.md | 106 ++++++- bower.json | 24 -- docs/README.md | 3 + eslint.config.mjs | 17 ++ examples/spago.yaml | 15 + examples/src/Main.purs | 11 + examples/src/QuickStart.js | 8 + examples/src/QuickStart.purs | 24 ++ package.json | 11 +- spago.yaml | 23 ++ src/Data/Undefinable.js | 14 +- src/Data/Undefinable.purs | 78 +++-- test/Main.purs | 19 -- test/Test/Main.purs | 27 ++ yarn.lock | 373 ----------------------- 25 files changed, 457 insertions(+), 460 deletions(-) create mode 100644 .editorconfig create mode 100644 .github/ISSUE_TEMPLATE/bug-report.md create mode 100644 .github/ISSUE_TEMPLATE/change-request.md create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/workflows/ci.yml create mode 100644 .tidyrc.json create mode 100644 CHANGELOG.md create mode 100644 CONTRIBUTING.md delete mode 100644 bower.json create mode 100644 docs/README.md create mode 100644 eslint.config.mjs create mode 100644 examples/spago.yaml create mode 100644 examples/src/Main.purs create mode 100644 examples/src/QuickStart.js create mode 100644 examples/src/QuickStart.purs create mode 100644 spago.yaml delete mode 100644 test/Main.purs create mode 100644 test/Test/Main.purs delete mode 100644 yarn.lock diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..7c68b07 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +# https://editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md new file mode 100644 index 0000000..b79b995 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -0,0 +1,19 @@ +--- +name: Bug report +about: Report an issue +title: "" +labels: bug +assignees: "" +--- + +**Describe the bug** +A clear and concise description of the bug. + +**To Reproduce** +A minimal code example (preferably a runnable example on [Try PureScript](https://try.purescript.org)!) or steps to reproduce the issue. + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/change-request.md b/.github/ISSUE_TEMPLATE/change-request.md new file mode 100644 index 0000000..a2ee685 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/change-request.md @@ -0,0 +1,21 @@ +--- +name: Change request +about: Propose an improvement to this library +title: "" +labels: "" +assignees: "" +--- + +**Is your change request related to a problem? Please describe.** +A clear and concise description of the problem. + +Examples: + +- It's frustrating to have to [...] +- I was looking for a function to [...] + +**Describe the solution you'd like** +A clear and concise description of what a good solution to you looks like, including any solutions you've already considered. + +**Additional context** +Add any other context about the change request here. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..8d7661e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: PureScript Discourse + url: https://discourse.purescript.org/ + about: Ask and answer questions on the PureScript discussion forum. + - name: PureScript Discord + url: https://purescript.org/chat + about: Ask and answer questions on the PureScript chat. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..d8780f7 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,11 @@ +**Description of the change** +Clearly and concisely describe the purpose of the pull request. If this PR relates to an existing issue or change proposal, please link to it. Include any other background context that would help reviewers understand the motivation for this PR. + +--- + +**Checklist:** + +- [ ] Added the change to the changelog's "Unreleased" section with a link to this PR and your username +- [ ] Linked any existing issues or proposals that this pull request should close +- [ ] Updated or added relevant documentation in the README and/or documentation directory +- [ ] Added a test for the contribution (if applicable) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..9c1cebb --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,37 @@ +name: CI + +on: + push: + branches: [master, main] + pull_request: + branches: [master, main] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up a PureScript toolchain + uses: purescript-contrib/setup-purescript@main + with: + purescript: "latest" + purs-tidy: "0.11.0" # "latest" + spago: "unstable" + + - name: Cache PureScript dependencies + uses: actions/cache@v4 + with: + key: ${{ runner.os }}-spago-${{ hashFiles('**/spago.lock') }} + path: | + .spago + output + + - name: Build source + run: spago build --censor-stats --strict --ensure-ranges --pedantic-packages + + - name: Run tests + run: spago test --offline --censor-stats --strict --pedantic-packages + + - name: Verify formatting + run: purs-tidy check src test examples/src diff --git a/.gitignore b/.gitignore index f643725..6a45203 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,14 @@ -.DS_Store -.psci -.psci_modules -.pulp-cache/ -npm-debug.log -node_modules/ -bower_components/ -tmp/ -output/ +.* +!.gitignore +!.github +!.editorconfig +!.tidyrc.json +!.eslintrc.json + +output +generated-docs +bower_components + +node_modules +package-lock.json +*.lock diff --git a/.tidyrc.json b/.tidyrc.json new file mode 100644 index 0000000..4f013c1 --- /dev/null +++ b/.tidyrc.json @@ -0,0 +1,10 @@ +{ + "importSort": "source", + "importWrap": "source", + "indent": 2, + "operatorsFile": null, + "ribbon": 1, + "typeArrowPlacement": "first", + "unicode": "never", + "width": null +} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..c7ee1eb --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,17 @@ +# Changelog + +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: + +Other improvements: + +## [v4.0.0](https://github.com/ethul/purescript-undefinable/releases/tag/v4.0.0) - 2019-01-26 + +- Initial release diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..3da0d8d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,5 @@ +# Contributing to Undefinable + +Thanks for your interest in contributing to `undefinable`! We welcome new contributions regardless of your level of experience or familiarity with PureScript. + +Every library in the Contributors organization shares a simple handbook that helps new contributors get started. With that in mind, please [read the short contributing guide on ethul/governance](https://github.com/ethul/governance/blob/main/contributing.md) before contributing to this library. diff --git a/README.md b/README.md index df66c97..1ebf402 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,107 @@ -# purescript-undefinable +# Undefinable -A library for handling `undefined` values. +[![CI](https://github.com/ethul/purescript-undefinable/workflows/CI/badge.svg?branch=main)](https://github.com/ethul/purescript-undefinable/actions?query=workflow%3ACI+branch%3Amain) +[![Release](https://img.shields.io/github/release/ethul/purescript-undefinable.svg)](https://github.com/ethul/purescript-undefinable/releases) +[![Pursuit](https://pursuit.purescript.org/packages/purescript-undefinable/badge)](https://pursuit.purescript.org/packages/purescript-undefinable) + +A library for dealing with undefined values in foreign libraries. + +`undefinable` is intended to be used with PureScript's [Foreign Function Interface (FFI)](https://github.com/purescript/documentation/blob/master/guides/FFI.md). If you are looking for general-purpose optional values, use [`Maybe`](https://github.com/purescript/purescript-maybe) instead. ## Installation -```bash -bower install --save purescript-undefinable +Install `undefinable` with [Spago](https://github.com/purescript/spago): + +```sh +spago install undefinable +``` + +## Quick start + +> The following example lives in [`examples`](./examples) and can be built and run using `spago -x examples.dhall run`. + +Here we have a little JavaScript function that we can use to determine whether a number is unlucky. We give it some number and it will either return `undefined` if the number is considered "unlucky" or just return the number otherwise: + +```js +export function unluckyImpl(n) { + // Unlucky number 13! + if (n === 13) { + return undefined; // but not null + } + + return n; +} +``` + +If we want to use this function from PureScript we'll need to go through the FFI: + +```purescript +module QuickStart + ( unlucky -- We only want to expose our "safe" `unlucky` function outside of + -- this module and keep the backing implementation (`unluckyImpl`) + -- hidden. + ) where + +import Prelude +import Data.Function.Uncurried (Fn1, runFn1) +import Data.Maybe (Maybe) +import Data.Undefinable (Undefinable, toMaybe) + +-- Here we declare a binding to a foreign JavaScript function that we'll call +-- out to using the FFI. +-- +-- This function takes an `Int` and then returns either an integer or a `undefined` +-- based on the given value. We use `Undefinable Int` to indicate that we could +-- get a `undefined` back from this function. +foreign import unluckyImpl :: Fn1 Int (Undefinable Int) + +-- We don't want to have to use `Undefinable` in our PureScript code, so we can use +-- `toMaybe` to convert our `Undefinable Int` into a `Maybe Int` which will then be +-- part of the API visible outside of this module. +unlucky :: Int -> Maybe Int +unlucky n = toMaybe $ runFn1 unluckyImpl n +``` + +You can run the following to load this example up in the REPL: + ``` +cd examples && spago repl +``` + +Once the REPL is loaded, go ahead and add the following imports: + +```purescript +import Prelude +import Data.Maybe +import QuickStart +``` + +You can now test out our `unlucky` function in the REPL: + +```purescript +unlucky 7 == Just 7 +unlucky 13 == Nothing +``` + +## Documentation + +`undefinable` documentation is stored in a few places: + +1. Module documentation is [published on Pursuit](https://pursuit.purescript.org/packages/purescript-undefinable). +2. Written documentation is kept in the [docs directory](./docs). +3. Usage examples can be found in [the test suite](./test). + +If you get stuck, there are several ways to get help: + +- [Open an issue](https://github.com/ethul/purescript-undefinable/issues) if you have encountered a bug or problem. +- Ask general questions on the [PureScript Discourse](https://discourse.purescript.org) forum or the [PureScript Discord](https://purescript.org/chat) chat. + +## Contributing + +You can contribute to `undefinable` in several ways: + +1. If you encounter a problem or have a question, please [open an issue](https://github.com/ethul/purescript-undefinable/issues). We'll do our best to work with you to resolve or answer it. + +2. If you would like to contribute code, tests, or documentation, please [read the contributor guide](./CONTRIBUTING.md). It's a short, helpful introduction to contributing to this library, including development instructions. + +3. If you have written a library, tutorial, guide, or other resource based on this package, please share it on the [PureScript Discourse](https://discourse.purescript.org)! Writing libraries and learning resources are a great way to help this library succeed. diff --git a/bower.json b/bower.json deleted file mode 100644 index c3397d3..0000000 --- a/bower.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "purescript-undefinable", - "description": "PureScript Undefinable", - "keywords": [ - "purescript" - ], - "license": "MIT", - "repository": { - "type": "git", - "url": "git://github.com/ethul/purescript-undefinable.git" - }, - "ignore": [ - "*", - "!src/**/*", - "!LICENSE" - ], - "dependencies": { - "purescript-maybe": "^4.0.0", - "purescript-functions": "^4.0.0" - }, - "devDependencies": { - "purescript-console": "^4.0.0" - } -} diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..9082f0d --- /dev/null +++ b/docs/README.md @@ -0,0 +1,3 @@ +# Undefinable Documentation + +This directory contains documentation for `undefinable`. If you are interested in contributing new documentation, please read the [contributor guidelines](../CONTRIBUTING.md) and [What Nobody Tells You About Documentation](https://documentation.divio.com) for help getting started. diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..78061b1 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,17 @@ +import js from "@eslint/js"; +import globals from "globals"; +import { defineConfig } from "eslint/config"; +import { includeIgnoreFile } from "@eslint/compat"; +import { fileURLToPath } from "node:url"; + +const gitignorePath = fileURLToPath(new URL(".gitignore", import.meta.url)); + +export default defineConfig([ + includeIgnoreFile(gitignorePath), + { + files: ["**/*.{js,mjs,cjs}"], + plugins: { js }, + extends: ["js/recommended"], + languageOptions: { globals: globals.browser } + }, +]); diff --git a/examples/spago.yaml b/examples/spago.yaml new file mode 100644 index 0000000..52782c7 --- /dev/null +++ b/examples/spago.yaml @@ -0,0 +1,15 @@ +package: + name: undefinable-example + dependencies: + - effect + - prelude + - maybe + - functions + - undefinable + - console +workspace: + packageSet: + registry: 64.4.0 + extraPackages: + undefinable: + path: .. diff --git a/examples/src/Main.purs b/examples/src/Main.purs new file mode 100644 index 0000000..4e3a3da --- /dev/null +++ b/examples/src/Main.purs @@ -0,0 +1,11 @@ +module Main where + +import Prelude +import Effect (Effect) +import Effect.Console (logShow) +import QuickStart (unlucky) + +main :: Effect Unit +main = do + logShow $ unlucky 7 + logShow $ unlucky 13 diff --git a/examples/src/QuickStart.js b/examples/src/QuickStart.js new file mode 100644 index 0000000..96eca3d --- /dev/null +++ b/examples/src/QuickStart.js @@ -0,0 +1,8 @@ +export function unluckyImpl(n) { + // Unlucky number 13! + if (n === 13) { + return undefined; + } + + return n; +} diff --git a/examples/src/QuickStart.purs b/examples/src/QuickStart.purs new file mode 100644 index 0000000..5c07fd0 --- /dev/null +++ b/examples/src/QuickStart.purs @@ -0,0 +1,24 @@ +module QuickStart + ( unlucky -- We only want to expose our "safe" `unlucky` function outside of + -- this module and keep the backing implementation (`unluckyImpl`) + -- hidden. + ) where + +import Prelude +import Data.Function.Uncurried (Fn1, runFn1) +import Data.Maybe (Maybe) +import Data.Undefinable (Undefinable, toMaybe) + +-- Here we declare a binding to a foreign JavaScript function that we'll call +-- out to using the FFI. +-- +-- This function takes an `Int` and then returns either an integer or a `undefined` +-- based on the given value. We use `Undefinable Int` to indicate that we could +-- get a `undefined` back from this function. +foreign import unluckyImpl :: Fn1 Int (Undefinable Int) + +-- We don't want to have to use `Undefinable` in our PureScript code, so we can use +-- `toMaybe` to convert our `Undefinable Int` into a `Maybe Int` which will then be +-- part of the API visible outside of this module. +unlucky :: Int -> Maybe Int +unlucky n = toMaybe $ runFn1 unluckyImpl n diff --git a/package.json b/package.json index a9d7e1e..7baf879 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,14 @@ "private": true, "license": "MIT", "scripts": { - "purs:compile": "purs compile 'src/**/*.purs' 'test/**/*.purs' 'bower_components/purescript-*/src/**/*.purs' 2>&1", - "test": "node -e 'require(\"./output/Test.Main\").main()'" + "build": "eslint src examples && spago build --censor-stats --strict --ensure-ranges --pedantic-packages", + "test": "spago test --offline --strict --pedantic-packages", + "build:example": "spago build --censor-stats --strict --ensure-ranges --pedantic-packages" + }, + "devDependencies": { + "@eslint/js": "^9.25.1", + "eslint": "^9.25.1", + "globals": "^16.0.0", + "@eslint/compat": "^1.2.8" } } diff --git a/spago.yaml b/spago.yaml new file mode 100644 index 0000000..f49a952 --- /dev/null +++ b/spago.yaml @@ -0,0 +1,23 @@ +package: + name: undefinable + description: A library for dealing with undefined javascript variables + publish: + license: MIT + version: 4.0.0 + location: + githubOwner: ethul + githubRepo: purescript-undefinable + dependencies: + - effect + - prelude + - maybe + - functions + test: + main: Test.Main + dependencies: + - console + - assert +workspace: + packageSet: + registry: 64.4.0 + extraPackages: {} diff --git a/src/Data/Undefinable.js b/src/Data/Undefinable.js index fa76447..b9d07d7 100644 --- a/src/Data/Undefinable.js +++ b/src/Data/Undefinable.js @@ -1,11 +1,3 @@ -'use strict'; - -exports['undefined'] = undefined; - -exports.undefinable = function undefinable(nothing, just, value){ - return value === undefined ? nothing : just(value); -}; - -exports.notUndefined = function notUndefined(value){ - return value; -}; +const undefinedImpl = undefined; +export { undefinedImpl as undefined }; +export const undefinable = (a, nothing, just) => a === undefined ? nothing : just(a); diff --git a/src/Data/Undefinable.purs b/src/Data/Undefinable.purs index 32e47ed..d021c7d 100644 --- a/src/Data/Undefinable.purs +++ b/src/Data/Undefinable.purs @@ -1,39 +1,81 @@ --- | This module defines a representation for undefined. +-- | This module defines types and functions for working with undefinable types +-- | using the FFI. + module Data.Undefinable ( Undefinable + , undefined + , notUndefined , toMaybe , toUndefinable ) where -import Prelude (class Eq, class Ord, class Show, (<<<), compare, eq, show) +import Prelude +import Data.Eq (class Eq1) import Data.Function (on) import Data.Function.Uncurried (Fn3, runFn3) -import Data.Maybe (Maybe(Just,Nothing), maybe) +import Data.Maybe (Maybe(..), maybe) +import Data.Ord (class Ord1) +import Unsafe.Coerce (unsafeCoerce) --- | This type constructor defines a representation for a value that may --- | or may not be undefined. +-- | A undefinable type. This type constructor is intended to be used for +-- | interoperating with JavaScript functions which accept or return undefined +-- | values. +-- | +-- | The runtime representation of `Undefinable T` is the same as that of `T`, +-- | except that it may also be `undefined`. For example, the JavaScript values +-- | `undefined`, `[]`, and `[1,2,3]` may all be given the type +-- | `Undefinable (Array Int)`. Similarly, the JavaScript values `[]`, `[undefined]`, +-- | and `[1,2,undefined,3]` may all be given the type `Array (Undefinable Int)`. +-- | +-- | There is one pitfall with `Undefinable`, which is that values of the type +-- | `Undefinable T` will not function as you might expect if the type `T` happens +-- | to itself permit `undefined` as a valid runtime representation. +-- | +-- | In particular, values of the type `Undefinable (Undefinable T)` will ‘collapse’, +-- | in the sense that the PureScript expressions `notUndefined undefined` and `undefined` +-- | will both leave you with a value whose runtime representation is just +-- | `undefined`. Therefore it is important to avoid using `Undefinable T` in +-- | situations where `T` itself can take `undefined` as a runtime representation. +-- | If in doubt, use `Maybe` instead. +-- | +-- | `Undefinable` does not permit lawful `Functor`, `Applicative`, or `Monad` +-- | instances as a result of this pitfall, which is why these instances are +-- | not provided. foreign import data Undefinable :: Type -> Type --- | Takes `undefined` to `Nothing` and a `value` to `Just value`. -toMaybe :: forall value. Undefinable value -> Maybe value -toMaybe = runFn3 undefinable Nothing Just +type role Undefinable representational + +-- | The undefined value. +foreign import undefined :: forall a. Undefinable a + +foreign import undefinable :: forall a r. Fn3 (Undefinable a) r (a -> r) r + +-- | Wrap a non-undefined value. +notUndefined :: forall a. a -> Undefinable a +notUndefined = unsafeCoerce --- | Takes `Nothing` to `undefined` and `Just value` to `value`. -toUndefinable :: forall value. Maybe value -> Undefinable value +-- | Takes `Nothing` to `undefined`, and `Just a` to `a`. +toUndefinable :: forall a. Maybe a -> Undefinable a toUndefinable = maybe undefined notUndefined -instance showUndefinable :: (Show a) => Show (Undefinable a) where +-- | Represent `undefined` using `Maybe a` as `Nothing`. Note that this function +-- | can violate parametricity, as it inspects the runtime representation of +-- | its argument (see the warning about the pitfall of `Undefinable` above). +toMaybe :: forall a. Undefinable a -> Maybe a +toMaybe n = runFn3 undefinable n Nothing Just + +instance showUndefinable :: Show a => Show (Undefinable a) where show = maybe "undefined" show <<< toMaybe -instance eqUndefinable :: (Eq a) => Eq (Undefinable a) where +instance eqUndefinable :: Eq a => Eq (Undefinable a) where eq = eq `on` toMaybe -instance ordUndefinable :: (Ord a) => Ord (Undefinable a) where - compare = compare `on` toMaybe - -foreign import undefined :: forall value. Undefinable value +instance eq1Undefinable :: Eq1 Undefinable where + eq1 = eq -foreign import undefinable :: forall value. Fn3 (Maybe value) (value -> Maybe value) (Undefinable value) (Maybe value) +instance ordUndefinable :: Ord a => Ord (Undefinable a) where + compare = compare `on` toMaybe -foreign import notUndefined :: forall value. value -> Undefinable value +instance ord1Undefinable :: Ord1 Undefinable where + compare1 = compare diff --git a/test/Main.purs b/test/Main.purs deleted file mode 100644 index 4d0e7f0..0000000 --- a/test/Main.purs +++ /dev/null @@ -1,19 +0,0 @@ -module Test.Main where - -import Prelude - -import Effect (Effect) -import Effect.Console (logShow) -import Data.Maybe (Maybe(..)) -import Data.Undefinable (toUndefinable, toMaybe) - -main :: Effect Unit -main = do - logShow $ toUndefinable (Nothing :: Maybe Number) - logShow $ toUndefinable (Just 42) - - logShow $ toMaybe $ toUndefinable (Nothing :: Maybe Number) - logShow $ toMaybe $ toUndefinable (Just 42) - - logShow $ toUndefinable Nothing == toUndefinable (Just 42) - logShow $ toUndefinable Nothing `compare` toUndefinable (Just 42) diff --git a/test/Test/Main.purs b/test/Test/Main.purs new file mode 100644 index 0000000..f76ffaa --- /dev/null +++ b/test/Test/Main.purs @@ -0,0 +1,27 @@ +module Test.Main where + +import Prelude + +import Data.Maybe (Maybe(..)) +import Data.Undefinable (toUndefinable, toMaybe) +import Effect (Effect) +import Test.Assert (assertEqual) + +main :: Effect Unit +main = do + assertEqual + { actual: toMaybe $ toUndefinable (Nothing :: Maybe Number) + , expected: Nothing + } + assertEqual + { actual: toMaybe $ toUndefinable (Just 42) + , expected: Just 42 + } + assertEqual + { actual: toUndefinable Nothing == toUndefinable (Just 42) + , expected: false + } + assertEqual + { actual: toUndefinable Nothing `compare` toUndefinable (Just 42) + , expected: LT + } diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index 72936a8..0000000 --- a/yarn.lock +++ /dev/null @@ -1,373 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - -balanced-match@^0.4.1: - version "0.4.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" - -brace-expansion@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.7.tgz#3effc3c50e000531fb720eaff80f0ae8ef23cf59" - dependencies: - balanced-match "^0.4.1" - concat-map "0.0.1" - -builtin-modules@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" - -camelcase@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" - -cliui@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - wrap-ansi "^2.0.0" - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - -decamelize@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - -error-ex@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" - dependencies: - is-arrayish "^0.2.1" - -find-up@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" - dependencies: - path-exists "^2.0.0" - pinkie-promise "^2.0.0" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - -gaze@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.2.tgz#847224677adb8870d679257ed3388fdb61e40105" - dependencies: - globule "^1.0.0" - -get-caller-file@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" - -glob@^7.1.1, glob@~7.1.1: - version "7.1.2" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globule@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/globule/-/globule-1.1.0.tgz#c49352e4dc183d85893ee825385eb994bb6df45f" - dependencies: - glob "~7.1.1" - lodash "~4.16.4" - minimatch "~3.0.2" - -graceful-fs@^4.1.2: - version "4.1.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" - -hosted-git-info@^2.1.4: - version "2.4.2" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.4.2.tgz#0076b9f46a270506ddbaaea56496897460612a67" - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - -invert-kv@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - -is-builtin-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" - dependencies: - builtin-modules "^1.0.0" - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - dependencies: - number-is-nan "^1.0.0" - -is-utf8@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - -keypress@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/keypress/-/keypress-0.2.1.tgz#1e80454250018dbad4c3fe94497d6e67b6269c77" - -lcid@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" - dependencies: - invert-kv "^1.0.0" - -load-json-file@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - pinkie-promise "^2.0.0" - strip-bom "^2.0.0" - -lodash.assign@^4.0.3, lodash.assign@^4.0.6: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" - -lodash@~4.16.4: - version "4.16.6" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.16.6.tgz#d22c9ac660288f3843e16ba7d2b5d06cca27d777" - -minimatch@^3.0.4, minimatch@~3.0.2: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - dependencies: - brace-expansion "^1.1.7" - -normalize-package-data@^2.3.2: - version "2.3.8" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.8.tgz#d819eda2a9dedbd1ffa563ea4071d936782295bb" - dependencies: - hosted-git-info "^2.1.4" - is-builtin-module "^1.0.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - dependencies: - wrappy "1" - -os-locale@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" - dependencies: - lcid "^1.0.0" - -parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - dependencies: - error-ex "^1.2.0" - -path-exists@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" - dependencies: - pinkie-promise "^2.0.0" - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - -path-type@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" - dependencies: - graceful-fs "^4.1.2" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -pify@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - -pscid@^1.12.1: - version "1.12.1" - resolved "https://registry.yarnpkg.com/pscid/-/pscid-1.12.1.tgz#4cbef8def7401eade0e56f96baff03fc19823308" - dependencies: - gaze "^1.1.2" - glob "^7.1.1" - keypress "^0.2.1" - which "^1.2.12" - yargs "^4.6.0" - -read-pkg-up@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" - dependencies: - find-up "^1.0.0" - read-pkg "^1.0.0" - -read-pkg@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" - dependencies: - load-json-file "^1.0.0" - normalize-package-data "^2.3.2" - path-type "^1.0.0" - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - -require-main-filename@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" - -"semver@2 || 3 || 4 || 5": - version "5.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" - -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - -spdx-correct@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" - dependencies: - spdx-license-ids "^1.0.2" - -spdx-expression-parse@~1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" - -spdx-license-ids@^1.0.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" - -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - dependencies: - ansi-regex "^2.0.0" - -strip-bom@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" - dependencies: - is-utf8 "^0.2.0" - -validate-npm-package-license@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" - dependencies: - spdx-correct "~1.0.0" - spdx-expression-parse "~1.0.0" - -which-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" - -which@^1.2.12: - version "1.2.14" - resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" - dependencies: - isexe "^2.0.0" - -window-size@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" - -wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - -y18n@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" - -yargs-parser@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-2.4.1.tgz#85568de3cf150ff49fa51825f03a8c880ddcc5c4" - dependencies: - camelcase "^3.0.0" - lodash.assign "^4.0.6" - -yargs@^4.6.0: - version "4.8.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-4.8.1.tgz#c0c42924ca4aaa6b0e6da1739dfb216439f9ddc0" - dependencies: - cliui "^3.2.0" - decamelize "^1.1.1" - get-caller-file "^1.0.1" - lodash.assign "^4.0.3" - os-locale "^1.4.0" - read-pkg-up "^1.0.1" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^1.0.1" - which-module "^1.0.0" - window-size "^0.2.0" - y18n "^3.2.1" - yargs-parser "^2.4.1" From 3691147911b0891457da4d8dc1eb8979a33e76e1 Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Sat, 26 Apr 2025 17:51:08 +0700 Subject: [PATCH 2/2] feat: add more tests from previous tests --- spago.yaml | 8 ++++---- test/Test/Main.purs | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/spago.yaml b/spago.yaml index f49a952..a58a490 100644 --- a/spago.yaml +++ b/spago.yaml @@ -8,15 +8,15 @@ package: githubOwner: ethul githubRepo: purescript-undefinable dependencies: - - effect - - prelude - - maybe - functions + - maybe + - prelude + - unsafe-coerce test: main: Test.Main dependencies: - - console - assert + - effect workspace: packageSet: registry: 64.4.0 diff --git a/test/Test/Main.purs b/test/Test/Main.purs index f76ffaa..51787da 100644 --- a/test/Test/Main.purs +++ b/test/Test/Main.purs @@ -9,6 +9,14 @@ import Test.Assert (assertEqual) main :: Effect Unit main = do + assertEqual + { actual: show $ toUndefinable (Nothing :: Maybe Number) + , expected: "undefined" + } + assertEqual + { actual: show $ toUndefinable (Just 42) + , expected: "42" + } assertEqual { actual: toMaybe $ toUndefinable (Nothing :: Maybe Number) , expected: Nothing