packages feed

ghc-wasm-bindgen 0.1.0.0 → 0.2.0.0

raw patch · 5 files changed

+39/−81 lines, 5 files

Files

− CHANGELOG.md
@@ -1,15 +0,0 @@-# Changelog--## 0.1.0.0--First release.--- `build`: builds a cabal project into an npm package (JS bindings,-  TypeScript declarations, `.wasm`, runtime and `package.json`).-- `generate`: writes the Haskell and JS bindings for plain source files.-- Standard types: numbers (including `Integer`/`Natural` as `bigint`), `Bool`,-  `Char`, `String`, `Text`, `Day`, `UTCTime`, `Maybe`, `Either`, tuples, lists,-  `Vector`, `NonEmpty`, `Set`/`HashSet`/`IntSet` and `Map`/`HashMap`/`IntMap`.-- User data types: records, positional constructors and enums.-- Arguments are validated before reaching Haskell; Haskell exceptions become-  `HaskellError` without breaking the module.
README.md view
@@ -1,6 +1,6 @@ # ghc-wasm-bindgen -Generates JavaScript/TypeScript bindings for a pure Haskell module compiled+Generate JavaScript/TypeScript bindings for a pure Haskell module compiled with GHC's WASM backend.  ```haskell@@ -48,17 +48,8 @@ | positional                | `{ $tag: "C"; contents: … }` | | all without fields (enum) | `"A" \| "B"`                 | -Constructors are exported as functions: `Rect({ width: 3, height: 4 })` for-records, `Node(left, 3, right)` for positional ones, and constants like `Leaf`-for nullary ones. Names that are not valid in JS get a trailing `_`-(`delete` → `delete_`).- Notes: -- `Int` and `Word` are 32 bits on wasm32.-- Map keys can be strings, numbers, `Bool`, `Char`, dates or your own types.-  `Map` and `Set` compare keys by reference.-- `UTCTime` keeps millisecond precision. - Every type the API uses must be exported with all its constructors. - Not supported yet: `IO`, polymorphic functions, functions as arguments,   operators, types with parameters and GADTs.@@ -70,8 +61,6 @@   before reaching Haskell. - An exception in Haskell throws a `HaskellError`. -Either way, the module keeps working.- ## Usage  ### `build`: cabal projects@@ -79,14 +68,32 @@ From the cabal project that contains the module:  ```sh-ghc-wasm-bindgen build src/ShapeWasm.hs --name shape --out pkg+ghc-wasm-bindgen build src/ShapeWasm.hs --name shape --out pkg/src ```  The module must be exposed by a library, in the same package as the code it-wraps or in one that depends on it. This writes the npm package `pkg/`-(`shape.js`, `shape.d.ts`, `shape.wasm`, the runtime and `package.json`).-Depend on it like any other package and import `shape`, `shape/runtime`-(`init`, `HaskellError`) and `shape/shape.wasm`.+wraps or in one that depends on it. This writes `shape.js`, `shape.d.ts`,+`shape.wasm` and the JS runtime to `pkg/src/`, and nothing else, so the+directory around it can be maintained by hand, even in another repository.++To publish it as an npm package, write its `package.json` yourself, for+example:++```json+{+    "name": "shape",+    "version": "0.1.0",+    "type": "module",+    "exports": {+        ".": { "types": "./src/shape.d.ts", "default": "./src/shape.js" },+        "./runtime": { "types": "./src/ghc_wasm_bindgen_runtime.d.ts", "default": "./src/ghc_wasm_bindgen_runtime.js" },+        "./shape.wasm": "./src/shape.wasm"+    }+}+```++Then import `shape`, `shape/runtime` (`init`, `HaskellError`) and+`shape/shape.wasm`.  ### `generate`: plain source files 
app/Main.hs view
@@ -15,8 +15,8 @@     , "  ghc-wasm-bindgen build MODULE.hs --name NAME --out DIR"     , "  ghc-wasm-bindgen generate MODULE.hs --name NAME --hs-out DIR --js-out DIR [-i DIR]..."     , ""-    , "build     From the cabal project that contains MODULE.hs, builds an npm package:"-    , "          NAME.js, NAME.d.ts, NAME.wasm, the runtime and a package.json."+    , "build     From the cabal project that contains MODULE.hs, writes NAME.js,"+    , "          NAME.d.ts, NAME.wasm and the JS runtime to --out."     , "          Needs cabal, and wasm32-wasi-cabal, wasm32-wasi-ghc and wasm-opt"     , "          (ghc-wasm-meta) on PATH."     , "generate  For plain source files: writes NameWasmBindings.hs and the Haskell"@@ -25,7 +25,7 @@     , ""     , "  MODULE.hs      module whose export list is the API (e.g. src/ShapeWasm.hs)"     , "  --name NAME    package and file name (e.g. shape)"-    , "  --out DIR      output directory of the package (e.g. pkg)"+    , "  --out DIR      output directory (e.g. pkg/src)"     , "  -i DIR         import directory for the modules MODULE.hs imports"     , "                 (MODULE.hs's own source root is added)"     ]
ghc-wasm-bindgen.cabal view
@@ -1,17 +1,12 @@ cabal-version:      3.0 name:               ghc-wasm-bindgen-version:            0.1.0.0+version:            0.2.0.0 synopsis:           JavaScript/TypeScript bindings for GHC's WASM backend description:-    Generates JavaScript and TypeScript bindings for a pure Haskell module-    compiled with GHC's WebAssembly backend. The module's export list is the-    API: functions become typed JS functions, and data types become-    TypeScript types with constructors.--    @ghc-wasm-bindgen build@ builds a cabal project into an npm package (JS-    bindings, TypeScript declarations, the .wasm and a small runtime).-    @ghc-wasm-bindgen generate@ only writes the bindings, for plain source-    files compiled by hand.+    Generate JavaScript and TypeScript bindings for a pure Haskell module+    compiled with GHC's WebAssembly backend. Exported functions are exposed+    as typed JavaScript functions, and exported data types as TypeScript+    types with constructor functions.      See the README for supported types and usage. category:           Web, WebAssembly, JavaScript, Development@@ -26,7 +21,6 @@ tested-with:        GHC == 9.10.3 extra-doc-files:     README.md-    CHANGELOG.md extra-source-files:     runtime-js/ghc_wasm_bindgen_runtime.js     runtime-js/ghc_wasm_bindgen_runtime.d.ts
src/GhcWasmBindgen.hs view
@@ -2,7 +2,7 @@  -- | Bindings for a Haskell API module, in two modes: ----- * 'build' (cabal projects): builds an npm package (JS bindings + .wasm).+-- * 'build' (cabal projects): builds the JS bindings and the .wasm. --   The package that contains the module is built natively, so the module can --   be inspected with its real dependencies; then the Haskell bindings are --   generated, together with the Haskell runtime module, as a package under@@ -25,8 +25,8 @@ import qualified Data.ByteString.Char8 as BC import Data.Char (isSpace, toLower, toUpper) import Data.FileEmbed (embedFile)-import Data.List (intercalate, isSuffixOf, stripPrefix)-import Data.Maybe (fromMaybe, mapMaybe)+import Data.List (isSuffixOf, stripPrefix)+import Data.Maybe (mapMaybe) import qualified Data.Text.Encoding as TE import System.Directory import System.Exit (ExitCode (..))@@ -46,7 +46,7 @@   , optName :: String     -- ^ Base name of the outputs: NAME.js, NAME.d.ts, NAME.wasm.   , optOut :: FilePath-    -- ^ Directory of the npm package to write.+    -- ^ Directory to write the JS bindings, runtime and .wasm to.   }  newtype BuildError = BuildError String@@ -143,8 +143,7 @@   run "wasm-opt" ["-Oz", wasm, "-o", optOut o </> name <.> "wasm"]    -- JS side.-  mapM_ (\(file, contents) -> writeIfChanged (optOut o </> file) contents) $-    ("package.json", packageJson name (pkgVersion pkg)) : jsFiles name api+  mapM_ (\(file, contents) -> writeIfChanged (optOut o </> file) contents) (jsFiles name api)   pure (optOut o)  -- | The JS bindings and runtime, by file name.@@ -167,7 +166,7 @@  -- Cabal -------------------------------------------------------------------- -data Package = Package {pkgName :: String, pkgVersion :: String}+newtype Package = Package {pkgName :: String}  -- | The cabal package that contains the API module: the nearest .cabal file -- above it.@@ -180,7 +179,7 @@         f : _ -> do           fields <- mapMaybe field . lines . BC.unpack <$> BS.readFile (dir </> f)           case lookup "name" fields of-            Just n -> pure (Package n (fromMaybe "0" (lookup "version" fields)))+            Just n -> pure (Package n)             Nothing -> throwIO (BuildError (dir </> f ++ " has no name field"))         [] | takeDirectory dir == dir -> throwIO (BuildError ("no .cabal file found above " ++ file))            | otherwise -> go (takeDirectory dir)@@ -229,33 +228,6 @@ -- | Cabal package and component names allow letters, digits and @-@. cabalName :: String -> String cabalName = map (\c -> if c == '_' then '-' else c)---- npm ------------------------------------------------------------------------packageJson :: String -> String -> ByteString-packageJson name version =-  BC.pack . unlines $-    [ "{"-    , "    \"name\": " ++ show (map toLower name) ++ ","-    , "    \"version\": " ++ show (semver version) ++ ","-    , "    \"type\": \"module\","-    , "    \"main\": " ++ show ("./" ++ name ++ ".js") ++ ","-    , "    \"types\": " ++ show ("./" ++ name ++ ".d.ts") ++ ","-    , "    \"exports\": {"-    , "        \".\": { \"types\": " ++ show ("./" ++ name ++ ".d.ts") ++ ", \"default\": " ++ show ("./" ++ name ++ ".js") ++ " },"-    , "        \"./runtime\": { \"types\": \"./ghc_wasm_bindgen_runtime.d.ts\", \"default\": \"./ghc_wasm_bindgen_runtime.js\" },"-    , "        " ++ show ("./" ++ name ++ ".wasm") ++ ": " ++ show ("./" ++ name ++ ".wasm")-    , "    }"-    , "}"-    ]---- | Cabal versions have any number of components; npm wants exactly three.-semver :: String -> String-semver v = intercalate "." (take 3 (splitOn '.' v ++ repeat "0"))-  where-    splitOn c s = case break (== c) s of-      (a, []) -> [a]-      (a, _ : rest) -> a : splitOn c rest  -- Files and processes ------------------------------------------------------