migration-guides/0.15-Migration-Guide.md
This guide summarizes the changes you may need to make to your code to migrate from PureScript 0.14 to PureScript 0.15. It covers major changes to the compiler, the core libraries, and tooling. For a detailed review of changes to the compiler in this release, please see the compiler release notes for PureScript 0.15.
Compiler releases are often accompanied by breaking changes in the core libraries. While some major library changes are described in this document, you should consult the individual changelogs for any libraries you depend on. See the 0.15 Ecosystem Update for an abbreviated consolidation of all changelog entries for the first 0.15.0 release of all core, contrib, node, and web libraries.
purescript-psa does not need to be updated.spago needs to be updated to v0.20.8.pulp needs to be updated to v16.0.0.purs-tidy:
0.7.2, the latest version as of this writing, will only format your 0.15.0 code if you are not using type-level integers syntax.The biggest feature of PureScript v0.15.0 is that PureScript code now compiles to ES modules, not CommonJS modules. We've dropped all support for CommonJS modules and only support ES modules.
In April, 2021 the Node.js LTS version 10 reached end-of-life, which was the last version that did not yet support ES modules (ESM). This means, that all Node.js LTS and current versions support ES modules. And since all major browsers have supported ESM for a long time, there is no need anymore in the JS ecosystem to support Common JS (CJS) and the JavaScript community is advocating to drop CJS support. The JavaScript community is following suit and is dropping its support for CJS. Some notable examples are remark, node-fetch and framer-motion amongst many others.
Purescript v0.15 is here and supports ESM with all of its advantages:
However, this has a couple of implications that will need you to migrate your code and tooling setup:
v0.15 drops support of CJS
With no real reason to keep supporting CJS, we have decided to drop CJS support alltogether. The maintenance burden would have been just too high to support CJS as well. This means you will need to update your FFI to ESM. More on this here:
v0.15 drops support for Node.js versions < 12
This is just the logical consequence of Node.js versions < 12 having reached EOL and not supporting ESM. More on this here:
v0.15 drops purs bundle and relies on an external bundlers
The Purescript compiler no longer comes with a built-in bundle command. purs bundle was already broken in a couple of ways, didn't do a great job on bundle size, and was basically unmaintained. Updating purs bundle to ESM would have required a considerable amount of work, taking time away from the compiler team to work on more urgent matters in the compiler.
Therefore, v0.15 relies on an external bundler like esbuild, webpack or parcel. And that is good news because these tools are used industry-wide and do a much better job on bundling than purs bundle. You will see significantly improved bundle sizes with v0.15. Using purescript-halogen template, we get the following comparison:
| Bundler | Size |
|---|---|
v0.14 with purs bundle | 259Kb |
v0.14 with purs-bundle and esbuild | 110Kb |
v0.15 with esbuild | 82Kb |
Another advantage is, that bundles are much more readable which facilitates debugging. Compare:
<details> <summary>v0.15 bundle</summary> (() => {
// output/Effect.Console/foreign.js
var log = function(s) {
return function() {
console.log(s);
};
};
// output/Main/index.js
var main = /* @__PURE__ */ function() {
return log("\u{1F35D}");
}();
// <stdin>
main();
})();
// Generated by purs bundle 0.14.5
var PS = {};
(function(exports) {
"use strict";
exports.log = function (s) {
return function () {
console.log(s);
};
};
})(PS["Effect.Console"] = PS["Effect.Console"] || {});
(function($PS) {
// Generated by purs version 0.14.5
"use strict";
$PS["Effect.Console"] = $PS["Effect.Console"] || {};
var exports = $PS["Effect.Console"];
var $foreign = $PS["Effect.Console"];
exports["log"] = $foreign.log;
})(PS);
(function($PS) {
"use strict";
$PS["Main"] = $PS["Main"] || {};
var exports = $PS["Main"];
var Effect_Console = $PS["Effect.Console"];
var main = Effect_Console.log("\ud83c\udf5d");
exports["main"] = main;
})(PS);
module.exports = PS["Main"];
Automating this change works 95% of the time and is described in the next section. This section describes what changes need to be made in more detail.
Below are the most common changes to make:
Importing a module
In v0.14 you had to import a module using require
const mymodule = require('mymodule')
In v0.15 you need to use import
import * as M from "mymodule";
// or import specific items from the module
import { main } from "mymodule";
Exporting variables and functions in your FFI
In v0.14 you had to use exports
exports.world = "🗺"
exports.greet = function() { return "hello " + world }
In v0.15 you need to use export
export const world = "🗺"
export function greet() { return "hello " + world }
// Here is the only example where you might need
// to modify FFI by hand.
//
// Sometimes, defining the function and then exporting it under
// a different name is needed to prevent issues with JavaScript
// keywords. For example, we might use the below FFI
// to export a function named `new`
// foreign import new :: Effect SomeObject
const newImpl = function () { return new SomeObject; }
export { newImpl as new };
Fortunately, there are tools that can automatically perform this conversion for you in most of the cases.
The best migration tool we have evaluated and recommend is lebab. However, there are still two cleanup tasks one should run after using it. See the "Migrate to ES Modules" script used in the ecosystem updates for inspiration.
The rest of this section covers lebab in a bit more detail:
npm i -g lebab
# Replace all *.js files in the src directory by rewriting them from
# CommonJS modules to ES modules
lebab --replace src --transform commonjs
lebab --replace test --transform commonjs
# you can also provide glob patterns, if you would like
lebab --replace 'src/js/**/*.jsx' --transform commonjs
The CommonJS → ES modules transform is considered unsafe, because there are some edge cases the tool is unable to handle. Keep these issues in mind when using it to update your code: https://github.com/lebab/lebab#unsafe-transforms
In general though it works well in most of the cases.
Another option you can try is cjstoesm.
Purescript v0.15 dropped support for Node.js versions below 12. If you are on an older version, you will need to upgrade to at least version 12.
To run your application, you can either use spago run or create an index.js
// index.js
import { main } from 'output/Main/index.js'
main()
and run
node index.js
# or if you are on Node.js 12
node --experimental-modules index.js
As discussed before, v0.15 drops support for purs bundle and therefore relies on an external bundler. We recommend three bundlers, namely esbuild, webpack and parcel. To make the transition easy for you, we have decided to make spago bundle-app and spago bundle-module use esbuild internally. The reasons for this are:
esbuild outperforms the other bundlers when producing a "readable" bundleesbuild is a standalone tool that doesn't require npm or nodeesbuild doesn't require a config in comparison to webpackesbuild is way faster than the othersSo you can keep using spago to bundle, but it requires you to install esbuild. More on this later.
Nonetheless, the other two bundlers are also great options:
webpack - has shown the best results in bundle size, but is also the slowest and most difficult to set up. If you need the smallest bundle size and full flexibility, this is probably the one you want.parcel - a good compromise between ease of use, speed and bundle size. If you need bundling involving html and css but still want a small, simple bundler, this is probably the one you want.For a full discussion see the github issue.
spago to bundleSee spago documentation.
Basic usage:
spago bundle-app # bundle for the browser
spago bundle-app --platform node # bundle for node
spago bundle-app --minify # minified bundle for the browser
spago bundle-app --platform node --minify # minified bundle for node
spago bundle-module # bundle for the browser
spago bundle-module --platform node # bundle for node
spago bundle-module --minify # minified bundle for the browser
spago bundle-module --platform node --minify # minified bundle for node
esbuild to bundleBasic usage:
esbuild --bundle index.js --platform=browser --outfile="bundle.js" # bundle for the browser
esbuild --bundle index.js --platform=node --outfile="bundle.js" # bundle for node
esbuild --bundle index.js --platform=browser --minify --outfile="bundle.minified.js" # minified bundle for the browser
esbuild --bundle index.js --platform=node --minify --outfile="bundle.minified.js" # minified bundle for the node
webpack to bundleBasic usage:
# Create webpack.config.js according to docs
webpack --mode=development # bundle
webpack --mode=production # minified bundle
parcel to bundleSee parcel documentation.
Basic usage:
# Note: in the examples below, the `index.html` file
# refers to a JavaScript file. If you are including your app
# as the entry point, it would have a script tag somewhere in it
# that looks something like this:
# `<script type="module" src="./output/Main/index.js">`
parcel build index.html --no-source-maps --no-optimize --no-scope-hoist --dist-dir "dist/" # bundle for the browser
parcel build index.html --no-source-maps --dist-dir "dist/" # minified bundle for the browser
A new kind Int was introduced that functions similar to the type-level String kind, Symbol. This allows cleaner syntax than the peano-based integers the community was using previously. Moreover, it allows easier representation of negative integers:
-- 0.14.x
data Nat
foreign import data Zero :: Nat
foreign import data Succ :: Nat -> Nat
type Two = Succ (Succ Zero)
addInts :: forall l r. Add l r total => Proxy l -> Proxy r -> Proxy total
addInts _ _ = Proxy
let x = addInts (Proxy :: Proxy (Succ (Succ Zero))) (Proxy :: Proxy (Succ Zero))
x == (Proxy :: Proxy (Succ (Succ (Succ Zero))))
-- 0.15.x
type Two = 2
addInts :: forall l r. Add l r total => Proxy l -> Proxy r -> Proxy total
addInts _ _ = Proxy
let x = addInts (Proxy :: Proxy 2) (Proxy :: Proxy 1)
x == (Proxy :: Proxy 3)
The type-level functions for +, *, and compare are represented via the Add, Mul and Compare type classes in Prim.Int.
At this time, there is no type-level function for converting a type-level Int into a type-level Symbol.
Data.ReflectableThere are now two kinds, Symbol and Int, that have first-class syntax support. While we could provide kind-specific reflection type classes (e.g. IsSymbol for Symbol and IsInt for Int), a kind-generic reflection type class is better since we also have polykinds support.
Thus, a new compiler-solved type class was introduced and can be referenced under the Data.Reflectable module namespace.
class Reflectable typeLevelType valueLevelType | typeLevelType -> valueLevelType where
reflectType :: Proxy typeLevelType -> valueLevelType
-- Since this class is solved by compiler,
-- the below instances are illustrative, not exhaustive.
instance Reflectable 1 Int where
reflectType _ = 1
instance Reflectable "foo" String where
reflectType _ = "foo"
However, when reflecting type-level integers to their value-level counterpart, keep in mind that the JavaScript backend's Int type has limits. Reflecting a type-level integer that is outside of these limits to a value-level one will produce a runtime error.
In v0.16.0, we'll dropping the IsSymbol type class and centralizing on the Reflectable type class.
(_ * 4 + 1)Operator sections only work when used with a single function. For example, ( _ + 1) works because it "desugars" to add 1. (foo _.bar) does not because it "desugars" to (foo <<< _.bar).
In 0.14.x, operator sections involving multiple operators didn't desugar according to those operator precedence.
-- 0.14.x
(_ * 4 + 1) == (\x -> x * (4 + 1)) -- desugared wrong, but still compiled
-- because it "desugars" to
-- (mul (4 + 1) _)
(3 * 2 + _) -- failed to compile due to desugaring to
-- (\x -> 3 * (2 + x))
-- which is equivalent to
-- (mul 3 <<< add 2)
-- 0.15.x
(_ * 4 + 1) -- fails to compile now since it desugars it correctly
-- (\x -> (x * 4) + 1)
-- which is equivalent to
-- (add 1 <<< mul 4)
(3 * 2 + _) == (\x -> 3 * 2 + x) -- desugars correctly and compiles now
-- == (\x -> (3 * 2) + x)
-- which is equivalent to
-- (add (3 * 2))
If you have code that relied on the old behavior, add an extra pair of
parentheses around the expression in the section (i.e. the _ part).
0.14.x deprecation warnings now produce errorsSee the PureScript 0.15 release notes for how to migrate properly, but most should have accounted for these changes by now:
foreign import f :: forall a. Show a => a -> String#0.15.x introduces one new deprecation warningA few years ago, PureScript changed how its parser worked. To ease migration, some ad-hoc indentation-reltaed case _ of syntax was supported awkwardly. This ad-hoc syntax is now being removed. The fix is easy: just indent past the binder.
-- 0.14.x
-- `valid` indicates an indentation level
-- where the case branch's expression
-- could appear and the code would
-- still compile...
case foo of
Foo arg -> {-
|
|
valid
valid
valid
valid
valid... -}
-- 0.14.x
-- `invalid` indicates an indentation level
-- where an appearance of `arg` will cause
-- this deprecation waring to appear:
-- where an appearance of the case
-- branch's expression will cause
-- a compiler error
case foo of
Foo arg -> {-
|
|
invalid
invalid
invalid
firstValidPlace
conventionalValidPlace -}
MonadZero type class and all of its deprecated instances.SProxy, Proxy2, Proxy3, RLProxy, etc.)
Type.Proxy (Proxy(..)).forall proxy. workaround at the bottom of this file.To fix:
Data.Array.group' to Data.Array.groupAllData.Array.NonEmpty.group' to Data.Array.NonEmpty.groupAllData.Array.ST.empty to Data.Array.ST.newData.List.group' to Data.List.groupAllData.List.NonEmpty.group' to Data.List.NonEmpty.groupAllData.List.mapWitIndex to Data.Foldable.mapWithIndexunfoldCofree e n with buildCofree (\s -> Tuple (e s) (n s))Data.Validation.Semigroup.unV with Data.Validation.Semigroup.validationData.Validation.Semiring.unV with Data.Validation.Semiring.validationimport CSS.Display (table) with import CSS.Display (displayTable)Text.Parsing or Text.Parsing.Parser were renamed to just Parsing:
Text.Parsing.Indent -> Parsing.IndentText.Parsing.Parser -> Parsing.ParserText.Parsing.Parser.Combinators -> Parsing.CombinatorsText.Parsing.Parser.Expr -> Parsing.ExprText.Parsing.Parser.Language -> Parsing.LanguageText.Parsing.Parser.String -> Parsing.StringText.Parsing.Parser.String.Basic -> Parsing.String.BasicText.Parsing.Parser.Token -> Parsing.TokenPos module was renamed but the module itself is being deprecated (it currently re-exports Parsing):
Text.Parsing.Parser.Pos -> ParsingText.Parsing.Parser.String module were relocated to Parsing.String.Basic because they are combinators, not primitive parsers:
whitespaceskipSpacesoneOfnoneOfoneOfCodePointsnoneOfCodePointsgroupAllBy replaced equality function with ordering function (purescript-lists)- groupAllBy :: forall a. Ord a => (a -> a -> Boolean) -> List a -> List (NEL.NonEmptyList a)
+ groupAllBy :: forall a. (a -> a -> Ordering) -> List a -> List (NEL.NonEmptyList a)
To fix:
compareon comparisonFunction</code>purescript-affjaxAffjax worked on the Node.js and browser environments by relying on a require
statement within a function. Depending on the environment detected,
either XHR or XmlHttpRequest is used. Since ES modules do not allow
one to call import within a function in a synchronous way,
we cannot continue to use this approach.
Rather, all request-related functions (e.g. request, get, etc.) now take
as their first argument an AffjaxDriver value. Different environments
will pass in their implementation for that driver and re-export
the functionality defined in affjax. Rather than relying upon
affjax directly, end-users will now rely upon a library that defines
the driver and re-exports all the request-related functions from Affjax
with that environment's driver already applied. In other words,
you will only need to update the imported module, nothing else.
To Fix:
spago install affjax-nodeimport Affjax as AX to import Affjax.Node as ANspago install affjax-webimport Affjax as AX to import Affjax.Web as AW<|>/Control.Alt.alt (purescript-control, purescript-parsing, purescript-string-parser)Previously, <|> was left-associative. It is now right-associative. See the issue for more context, but the change improves performance without breaking the Alt laws.
As a result of this change, some operators often used with <|> had to change their direction or their precedence to prevent a compiler error:
<??> became right-associative<?> and <~?> precedence was dropped from 3 to 4<?> was dropped from 3 to 4To fix:
purescript-math was deprecated; code ported to numbers and integersmath was tied too closely to the JavaScript backend. Now that we have the numbers and integers repo, we ported math to numbers and updated integers accordingly. we're deprecating math and deferring to those libraries.
To fix:
- import Math as Math
+ import Data.Number as Number
- foo = Math.pow
+ foo = Number.pow
NoConstructors now newtypes Void (purescript-prelude)The data type, NoConstructors, often used in Generic-related code, was changed to newtype Void, enabling one to unwrap the newtype and use absurd.
This is not a breaking change, but authors of Generic-related libraries can now define type class instances for NoConstructors via absurd.
To fix:
signum zero returns zero (purescript-prelude)This was an oversight that has finally been fixed. Previously, it would return one, unlike practically every other implementation in other languages.
To fix:
signum in case you were relying on the old behaviorshowing Records with duplicate labels fails to compile (purescript-prelude)Record.union defers the need for a Nub constraint to help type inference in some cases. Since Record's Show instance didn't add a Nub constraint, the below code would compile on 0.14.x
let
duplLabels :: { x :: String, x :: Int }
duplLabels = union { x: "a" } { x: 2 }
in show duplLabels
A Nub constraint was added to Show, preventing the above example from compiling.
To fix:
Nub constraint is needed.purescript-ordered-collections: update on Map's Semigroup instanceData.Map.Unbiased - instances left untouchedData.Map's Semigroup instance is changed to Data.Map.Unbiased implementation. A deprecation notice is still shown, warning of the change.Data.Map.Unbiased - deprecate type and its instancesData.Map - warning on Semigroup instance is removedv0.17.0
Data.Map.Unbiased - removedSee Unbiasing the Semigroup instance for Map and purescript/purescript-ordered-collections#38 for more context.
frequency to use NonEmptyArray (purescript-quickcheck)In the 0.14.x ecosystem update, oneOf was changed from using a NonEmptyList to using a NonEmptyArray due to the better syntax support of arrays. However, frequency was not also updated. This change fixes that.
To fix:
- import Data.List.NonEmpty (NonEmptyList(..))
- import Data.NonEmpty (NonEmpty(..), (:|))
+ import Data.Array.NonEmpty as NEA
- foo = frequency $ NonEmptyList $ NonEmpty (Tuple 1 (pure 1)) $
- (Tuple 2 (pure 2))
- : (Tuple 3 (pure 3))
- : Nil
{- If you are using a literal non-empty array -}
+ import Partial.Unsafe (unsafePartial)
+ import Data.Maybe (fromJust)
+ foo = frequency $ unsafePartial $ fromJust $ NEA.fromArray
+ [ Tuple 1 $ pure 1
+ , Tuple 2 $ pure 2
+ , Tuple 3 $ pure 3
+ ]
{- otherwise... -}
+ foo = frequency $ NEA.cons' (Tuple 1 (pure 1)) someArrayOfTupleGen
Maybe wrapper and bounds check in slice (purescript-strings)Data.String.CodeUnits.slice no longer does a bounds check. As such, it no longer returns Maybe String, but just String.
-- 0.14.x
slice 0 10 "0123" == Nothing
slice (-1) 10 "0123" == Nothing
-- 0.15.x
slice 0 10 "0123" == "0123"
slice (-1) 10 "0123" == "3"
To fix:
Maybepurescript-contrib librarieslaunchAff_ only work on Aff Unit (purescript-aff)launchAff_ :: forall a. Aff a -> Effect Unit will silently discard what the Aff computation returns. This behavior isn't always desirable, but the developer won't know otherwise.
Thus, launchAff_'s type signature was changed to Aff Unit -> Effect Unit. By making this change, developers are forced to clarify whether they want this discarding behavior or not. It's a minor annoyance (and breaking change) for most developers but otherwise makes the resulting code much safer.
To fix:
launchAff_ do with launchAff_ $ void dopurescript-csscalc expressions was added, but the change affected the names and number of various constructors. See the PR for more info.box-shadow implementation was updated to reflect Clay, the original inspiration for the library. See the PR for more info.Color.Scheme.* modules were removed (purescript-css)These colors, usually under the Color.Scheme.* module name space were originally defined in purescript-colors (i.e. one module per scheme). A PR (linked below) removed them because each scheme should be defined as its own library. The 'scheme drop' change propagated to this release.
See purescript-contrib/purescript-colors#44 for original definitions of various colors.
To Fix:
purescript-parsingParserT got (up to) 20x performance boostParserT now has a more efficient representation. In addition to the performance, all parser execution is always stack-safe, even monadically, obviating the need to run parsers with Trampoline as the base Monad or to explicitly use MonadRec.
Code that was parametric over the underlying Monad no longer needs to propagate a Monad constraint.
Code that constructs parsers via the underlying representation will need to be updated, but otherwise the interface is unchanged and parsers should just enjoy the speed boost.
To fix:
ParserT's underlying representationfooRec can be replaced with foo versionNow that ParserT is stack-safe automatically, we no longer need functions that impose the MonadRec constraint. As such, all combinators ending in Rec due to the MonadRec constraint have been removed. The complete list is below:
chainlRec -> chainlchainl1Rec -> chainl1chainrRec -> chainrchainr1Rec -> chainr1endByRec -> endByendBy1Rec -> endBy1many1Rec -> many1manyTillRec -> manyTillmanyTillRec_ -> manyTill_many1TillRec -> many1Tillmany1TillRec_ -> many1Till_sepByRec -> sepBysepBy1Rec -> sepBy1sepEndByRec -> sepEndBysepEndBy1Rec -> sepEndBy1skipManyRec -> skipManyskipMany1Rec -> skipMany1Combinators that were defined in the module Text.Parsing.Parser.Combinators are now defined in Parsing.Combinators.
To fix:
Rec part of the combinator name and update importsMonadState is actually usable nowPreviously, ParserT's MonadState instance hardcoded the state type to ParserState. If one wanted to run the parser in the context of their own state monad, they could not do so.
This limitation has been removed, enabling more powerful parsers.
If you still need to get the state of the parser, you must replace get with getParserT
To fix:
get with getParserTregex now reuses the implementation from stringsPreviously, the regex function would use its own custom implementation. This functionality is already exposed in the strings package, so the function was updated to reuse that functionality:
-- old way
foo = do
result <- regex { dotAll: true, global: true, ... } "finding a p[aA]ttern"
-- new way
import Data.String.Regex (dotAll, global)
foo = do
eitherErrOrResult <- regex "finding a p[aA]ttern" (dotAll <> global)
case eitherErrOrResult of
Left e -> -- invalid regex
Right result -> -- usage
Key differences are:
Semigroup rather than a RecordTo fix:
Position now has an index fieldindex is a line/column-independent position within the content being parsed. See the docs and implementation for more details.
To fix:
purescript-node librariesError arg to Stream.write/Stream.writeString (purescript-node-streams`)The Stream.write and Stream.writeString have a callback function. The type signature for this binding was inaccurate because an Error arg is passed to that function but the type signature is Effect Unit rather than Error -> Effect Unit.
This type signature was updated to be more accurate
-write :: forall r. Writable r -> Buffer -> Effect Unit -> Effect Boolean
+write :: forall r. Writable r -> Buffer -> (Error -> Effect Unit) -> Effect Boolean
To fix:
Effect Unit code in const (e.g. pure unit -> const $ pure unit)Error arg, you can use \err -> ...recursive field in mkdir''s options arg (purescript-node-fs/purescript-node-fs-aff)Previously, mkdir did not expose all the fields in the options arg. So, trying to run something like mkdir "foo/bar/baz" { recursive: true } wasn't possible without writing your own FFI to mkdir. The recursive option has now been exposed.
To fix:
mkdir' path perms to mkdir' path { recursive: false, mode: perms }mkdir' path { recursive: true, mode: mkPerms all all all }Async.exists (purescript-node-fs)The async exists version from purescript-node-fs has been removed since the underlying Node.js version has been deprecated since Node.js version 1.
To fix:
exists from the Sync moduleexists (purescript-node-fs-aff)exists has been removed since the underlying Async.exists from purescript-node-fs has been removed.
To fix:
node-fs package's Node.Fs.Sync (exists) function and wrap in liftEffect (e.g. liftEffect $ Sync.exists path)purescript-web librariesArc record type includes field for representing arc direction (purescript-canvas)An arc could only be drawn clockwise due to an options field not being exposed in the FFI bindings. This change exposes that option.
- type Arc = { ... }
+ type Arc = { ..., useCounterClockwise :: Boolean }
To fix:
useCounterClockwise to falseuseCounterClockwise to trueTransform record type's fields renamed (purescript-canvas)The Transform field names were changed because the values referenced by m31 and m32 corresponded to dX and dY in other contexts. MDN docs would use fields a-f to refer to the values in a context-agnostic way.
- { m11, m12, m21, m22, m31, m32 }
+ { a, b, c, d, e, f }
To fix:
CSSStyleDeclaration functions changed (purescript-cssom)By convention, the "thing being operated on" occurs last in functions that take multiple arguments.Functions involving CSSStyleDeclaration now put the CSSStyleDeclaration arg last.
To Fix:
setCssText style str -> setCssText str stylegetPropertyPriority style str -> getPropertyPriority str stylegetPropertyValue style str -> getPropertyValue str styleremoveProperty style key -> removeProperty key stylesetProperty style key name -> setProperty key name styleEffect wrapper for doctype (purescript-web-dom)doctype is a readonly value that doesn't change. Thus, the Effect that wraps the returned value isn't needed and was dropped.
To fix:
foo = do
- ty <- doctype =<< document =<< window
+ ty <- doctype <$> document =<< window
getBoundingClientRect type change and location change (purescript-web-html, purescript-web-dom)getBoundingClientRect was moved from web-html to web-dom. Moreover, its arg was changed from HTMLElement to Element, enabling it to work on more types.
To fix:
- import Web.HTML.HTMLElement (getBoundingClientRect)
+ import Web.DOM.Element (getBoundingClientRect)
foo = do
- getBoundingClientRect $ toHtmlElement someElem
+ getBoundingClientRect $ toHtmlElement someElem
setClassName/getClassName/classList deduplicated (purescript-web-html, purescript-web-dom)These three functions were defined in purescript-web-dom and duplicated in their definitions in purescript-web-html, which depends on purescript-web-dom. Thus, They've been removed from purescript-web-html.
To fix:
- import Web.HTML.HTMLElement (setClassName, getClassName, classList)
+ import Web.DOM.Element (setClassName, getClassName, classList)
forall proxy. workaroundIn 0.13.x, we did not have a kind-polymorphic Proxy type (e.g. data Proxy :: forall k. k -> Type). So, each kind needed its own Proxy type, producing a zoo of such types:
SProxy - Proxy for kind SymbolRProxy - Proxy for kind RowRLProxy - Proxy for kind RowList-- 0.13.x
foo :: forall sym. IsSymbol sym => SProxy sym -> ...
bar :: forall row. RowCons "foo" Int () row => RProxy row -> ...
In 0.14.0, when polykinds were implemented, we got a kind-generic Proxy type. Thus, the zoo of Proxy types were no longer needed. However, to reduce breakage, we used a forall proxy. workaround so that both the kind-specific and kind-generic version worked.
-- 0.14.x
-- `forall proxy.` workaround:
foo :: forall proxy sym. IsSymbol sym => proxy sym -> ...
foo (SProxy :: SProxy "a") -- kind-specific Proxy type works!
foo (Proxy :: Proxy "a") -- kind-generic Proxy type also works!
In 0.15.x, the zoo of Proxy types were removed. Thus, the forall proxy. workaround SHOULD be removed in all libraries as doing so improves type inference.
-foo :: forall proxy sym. IsSymbol sym => proxy sym -> ...
+import Type.Proxy (Proxy(..))
+foo :: forall sym. IsSymbol sym => Proxy sym -> ...
F and FTTo fix:
In purescript-foreign, the F and FT type aliases often do more harm than good. The API has been updated to use those aliases' definitions rather than the aliases themselves.
While this doesn't count as a breaking change, nor are we deprecating those type alises, we encourage people to migrate their usage of it for clarity:
- import Foreign (F, FT)
+ import Foreign (ForeignError(..))
+ import Data.List.Types (NonEmptyList(..))
- type Foo = F a
+ type Foo = Except (NonEmptyList ForeignError) a
- type FooT = FT a
+ type FooT = ExceptT (NonEmptyList ForeignError) m a