From 791cefef177de5ead13b57039c252df44c9578d4 Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Fri, 4 Oct 2024 18:34:39 +0700 Subject: [PATCH 01/32] feat: implement glob, cp, opendir and other methods --- .github/workflows/ci.yml | 4 +- CHANGELOG.md | 97 ++- bower.json | 44 -- package.json | 12 +- spago.lock | 1380 ++++++++++++++++++++++++++++++++++++++ spago.yaml | 167 +++++ src/Node/FS/Aff.purs | 212 ++++++ src/Node/FS/Aff/Dir.purs | 82 +++ src/Node/FS/Async.js | 22 +- src/Node/FS/Async.purs | 318 ++++++++- src/Node/FS/Dir.js | 5 + src/Node/FS/Dir.purs | 49 ++ src/Node/FS/Dirent.js | 11 + src/Node/FS/Dirent.purs | 58 ++ src/Node/FS/Sync.js | 20 +- test/Main.purs | 2 + test/Test.purs | 6 +- test/TestDirEntries.purs | 111 +++ 18 files changed, 2525 insertions(+), 75 deletions(-) delete mode 100644 bower.json create mode 100644 spago.lock create mode 100644 spago.yaml create mode 100644 src/Node/FS/Aff/Dir.purs create mode 100644 src/Node/FS/Dir.js create mode 100644 src/Node/FS/Dir.purs create mode 100644 src/Node/FS/Dirent.js create mode 100644 src/Node/FS/Dirent.purs create mode 100644 test/TestDirEntries.purs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a39bce1..00e2e2c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,14 +10,14 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: purescript-contrib/setup-purescript@main with: purescript: "unstable" purs-tidy: "latest" - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: node-version: "lts/*" diff --git a/CHANGELOG.md b/CHANGELOG.md index 0732021..771a510 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,71 @@ 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: +- Add functions to `Node.FS.Async` + + - readdir' + - readdirBuffer + - readdirBuffer' + - readdirDirent + - readdirDirent' + - readdirDirentBuffer + - readdirDirentBuffer' + - cp + - cp' + - fchmod + - fchown + - fdatasync + - fstat + - fsync + - ftruncate + - futimes + - glob + - glob' + - globDirent + - globDirent' + - lchmod + - lchown + - lutimes + - opendir + - opendir' + - readv + - statfs + - writev + +- Add functions to `Node.FS.Aff` + + - cp + - cp' + - fchmod + - fchown + - fdatasync + - fstat + - fsync + - ftruncate + - futimes + - glob + - glob' + - globDirent + - globDirent' + - lchmod + - lchown + - lutimes + - opendir + - opendir' + - readv + - statfs + - writev + +- Add modules `Dir`, `Dir.Aff`, `Dirent` + +- Fix tests - it was creating lot of `./test/fixturesASDFSDF` directories, now - create in `tmp` like `./tmp/test/fixturesASDFSDF` + Bugfixes: Other improvements: @@ -16,22 +74,27 @@ Other improvements: ## [v9.2.0](https://github.com/purescript-node/purescript-node-fs/releases/tag/v9.2.0) - 2024-06-23 New features: + - Add `lstat` to `Node.FS.Aff` (#85 by @artemisSystem) Bugfixes: + - Fixed internal reference to `rmdir` that should have been `rm` (#83 by @MonoidMusician) ## [v9.1.0](https://github.com/purescript-node/purescript-node-fs/releases/tag/v9.1.0) - 2023-07-26 Bugfixes: + - Update `node-streams` to `v9.0.0` to fix FFI issues (#78 by @JordanMartinez) ## [v9.0.0](https://github.com/purescript-node/purescript-node-fs/releases/tag/v9.0.0) - 2023-07-19 Breaking changes: + - Remove `StatsObj` and reimplement bindings to `Stats` object (#76 by @JordanMartinez) Previously, one could write the following to get a value on the `Stats` object: + ```purs getGid :: Stats -> Number getGid (Stats obj) = obj.gid @@ -39,21 +102,24 @@ Breaking changes: This record interface was removed as the underlying value is not a record that can be copied and modified as such. Now, one must call the corresponding function: + ```purs getGid :: Stats -> Number getGid s = Stats.gid s ``` + - Update `[fd]createReadStream`/`[fd]createWriteStream` to allow more options (#77 by @JordanMartinez) - | Removes... | ...in favor of | - | - | - | - | `createReadStreamWith` | `createReadStream'` | - | `fdCreateReadStreamWith` | `fdCreateReadStream'` | - | `createWriteStreamWith` | `createWriteStream'` | + | Removes... | ...in favor of | + | ------------------------- | ---------------------- | + | `createReadStreamWith` | `createReadStream'` | + | `fdCreateReadStreamWith` | `fdCreateReadStream'` | + | `createWriteStreamWith` | `createWriteStream'` | | `fdCreateWriteStreamWith` | `fdCreateWriteStream'` | - - In the new APIs, all options are exposed and may require converting + + In the new APIs, all options are exposed and may require converting PureScript values to JavaScript ones. + ```purs filePath # createWriteStream' { flags: fileFlagsToNode R @@ -63,11 +129,13 @@ Breaking changes: ``` New features: + - Integrate `node-fs-aff` into library (#75 by @JordanMartinez) Bugfixes: Other improvements: + - Update `node-buffer` to next breaking release: `v9.0.0` (#74 by @JordanMartinez) - Update `node-streams` to next breaking release: `TODO` (#74 by @JordanMartinez) - Update CI actions to v3 (#74 by @JordanMartinez) @@ -77,16 +145,19 @@ Other improvements: ## [v8.2.0](https://github.com/purescript-node/purescript-node-fs/releases/tag/v8.2.0) - 2023-03-23 New features: -- Add FFI for `access`, `copyFile` and `mkdtemp` (#73 by @JordanMartinez) + +- Add FFI for `access`, `copyFile` and `mkdtemp` (#73 by @JordanMartinez) ## [v8.1.1](https://github.com/purescript-node/purescript-node-fs/releases/tag/v8.1.1) - 2022-10-24 Other improvements: + - Use `EffectFn` throughout instead of unsafe `mkEffect` utility (#70 by @colinwahl) ## [v8.1.0](https://github.com/purescript-node/purescript-node-fs/releases/tag/v8.1.0) - 2022-06-10 New features: + - Add `lstat` (#66 by @artemisSystem) - Add rmdir', which takes an take options arg (#67 by @wclr) - Added rm and rm' version with and without options arg (#67 by @wclr) @@ -94,11 +165,13 @@ New features: ## [v8.0.0](https://github.com/purescript-node/purescript-node-fs/releases/tag/v8.0.0) - 2022-04-29 Breaking changes: + - Remove `Async.exists` (#61 by @sigma-andex) - Update `mkdir` to take an options record arg, exposing `recursive` option (#53, #55, #58 by @JordanMartinez) To get back the old behavior of `mkdir'`, you would call `mkdir' { recursive: false, mode: mkPerms all all all }` New features: + - Update project and deps to PureScript v0.15.0 (#59 by @JordanMartinez, @thomashoneyman, @sigma-andex) - Remove duplicate `node-buffer` from bower.json (@thomashoneyman) @@ -115,6 +188,7 @@ Due to an incorrectly-implemented breaking change, use v8.0.0 Breaking changes: New features: + - Add bindings to `mkdir(path, { recursive: true })` via `mkdirRecursive` (#53, #55 by @JordanMartinez) Bugfixes: @@ -124,18 +198,22 @@ Other improvements: ## [v6.1.0](https://github.com/purescript-node/purescript-node-fs/releases/tag/v6.1.0) - 2021-05-06 New features: + - Exported `mkPerm` (#42 by @JordanMartinez) Other improvements: + - Fixed warnings revealed by v0.14.1 PS release (#42 by @JordanMartinez) ## [v6.0.0](https://github.com/purescript-node/purescript-node-fs/releases/tag/v6.0.0) - 2021-02-26 Breaking changes: + - Added support for PureScript 0.14 and dropped support for all previous versions (#46) - Dropped deprecated `globals` dependency (#47) Other improvements: + - Migrated CI to GitHub Actions, updated installation instructions to use Spago, and migrated from `jshint` to `eslint` (#45) - Added a changelog and pull request template (#49) @@ -230,6 +308,7 @@ Fix type of `Async.exists`. ## [v0.4.0](https://github.com/purescript-node/purescript-node-fs/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-node/purescript-node-fs/releases/tag/v0.3.0) - 2015-01-29 diff --git a/bower.json b/bower.json deleted file mode 100644 index 1fc30b8..0000000 --- a/bower.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "name": "purescript-node-fs", - "homepage": "https://github.com/purescript-contrib/purescript-node-fs", - "description": "Node.js file system operations", - "keywords": [ - "purescript" - ], - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/purescript-node/purescript-node-fs.git" - }, - "ignore": [ - "**/.*", - "bower_components", - "node_modules", - "tmp", - "output", - "bower.json", - "package.json" - ], - "dependencies": { - "purescript-datetime": "^6.0.0", - "purescript-effect": "^4.0.0", - "purescript-either": "^6.0.0", - "purescript-enums": "^6.0.0", - "purescript-exceptions": "^6.0.0", - "purescript-functions": "^6.0.0", - "purescript-integers": "^6.0.0", - "purescript-js-date": "^8.0.0", - "purescript-maybe": "^6.0.0", - "purescript-node-buffer": "^9.0.0", - "purescript-node-path": "^5.0.0", - "purescript-node-streams": "^9.0.0", - "purescript-nullable": "^6.0.0", - "purescript-partial": "^4.0.0", - "purescript-prelude": "^6.0.0", - "purescript-strings": "^6.0.0", - "purescript-unsafe-coerce": "^6.0.0" - }, - "devDependencies": { - "purescript-console": "^6.0.0" - } -} diff --git a/package.json b/package.json index c08ce8f..8833a7e 100644 --- a/package.json +++ b/package.json @@ -2,13 +2,13 @@ "private": true, "scripts": { "clean": "rimraf output && rimraf .pulp-cache", - "build": "eslint src && pulp build -- --censor-lib --strict", - "test": "pulp test -- --censor-lib" + "build": "eslint src && spago build --censor-stats --strict --pedantic-packages", + "test": "spago test --censor-stats --strict --pedantic-packages" }, "devDependencies": { - "eslint": "^7.15.0", - "pulp": "16.0.0-0", - "purescript-psa": "^0.8.2", - "rimraf": "^3.0.2" + "eslint": "^9.11.1", + "pulp": "16.0.2", + "purescript-psa": "^0.9.0", + "rimraf": "^6.0.1" } } diff --git a/spago.lock b/spago.lock new file mode 100644 index 0000000..419c254 --- /dev/null +++ b/spago.lock @@ -0,0 +1,1380 @@ +workspace: + packages: + node-fs: + path: ./ + core: + dependencies: + - datetime + - effect + - either + - enums + - exceptions + - functions + - integers + - js-date + - maybe + - node-buffer + - node-buffer-blob + - node-path + - node-streams + - nullable + - partial + - prelude + - refs + - strings + - unsafe-coerce + build_plan: + - aff + - aff-promise + - arraybuffer-types + - arrays + - bifunctors + - const + - contravariant + - control + - datetime + - distributive + - effect + - either + - enums + - exceptions + - exists + - foldable-traversable + - foreign + - functions + - functors + - gen + - identity + - integers + - invariant + - js-date + - js-promise + - lazy + - lists + - maybe + - media-types + - newtype + - node-buffer + - node-buffer-blob + - node-event-emitter + - node-path + - node-streams + - nonempty + - now + - nullable + - numbers + - ordered-collections + - orders + - parallel + - partial + - prelude + - profunctor + - refs + - safe-coerce + - st + - strings + - tailrec + - transformers + - tuples + - type-equality + - unfoldable + - unsafe-coerce + - web-streams + test: + dependencies: + - aff + - arrays + - assert + - console + build_plan: + - aff + - arrays + - assert + - bifunctors + - console + - const + - contravariant + - control + - datetime + - distributive + - effect + - either + - enums + - exceptions + - exists + - foldable-traversable + - functions + - functors + - gen + - identity + - integers + - invariant + - lazy + - lists + - maybe + - newtype + - nonempty + - numbers + - ordered-collections + - orders + - parallel + - partial + - prelude + - profunctor + - refs + - safe-coerce + - st + - tailrec + - transformers + - tuples + - type-equality + - unfoldable + - unsafe-coerce + package_set: + address: + registry: 60.2.1 + compiler: ">=0.15.15 <0.16.0" + content: + abc-parser: 2.0.1 + ace: 9.1.0 + address-rfc2821: 0.1.1 + aff: 8.0.0 + aff-bus: 6.0.0 + aff-coroutines: 9.0.0 + aff-promise: 4.0.0 + aff-retry: 2.0.0 + affjax: 13.0.0 + affjax-node: 1.0.0 + affjax-web: 1.0.0 + ansi: 7.0.0 + apexcharts: 0.5.0 + applicative-phases: 1.0.0 + argonaut: 9.0.0 + argonaut-aeson-generic: 0.4.1 + argonaut-codecs: 9.1.0 + argonaut-core: 7.0.0 + argonaut-generic: 8.0.0 + argonaut-traversals: 10.0.0 + argparse-basic: 2.0.0 + array-builder: 0.1.2 + array-search: 0.6.0 + arraybuffer: 13.2.0 + arraybuffer-builder: 3.1.0 + arraybuffer-types: 3.0.2 + arrays: 7.3.0 + arrays-extra: 0.6.1 + arrays-zipper: 2.0.1 + ask: 1.0.0 + assert: 6.0.0 + assert-multiple: 0.4.0 + avar: 5.0.0 + b64: 0.0.8 + barbies: 1.0.1 + barlow-lens: 0.9.0 + bifunctors: 6.0.0 + bigints: 7.0.1 + bolson: 0.3.9 + bookhound: 0.1.7 + bower-json: 3.0.0 + call-by-name: 4.0.1 + canvas: 6.0.0 + canvas-action: 9.0.0 + cartesian: 1.0.6 + catenable-lists: 7.0.0 + cbor-stream: 1.3.0 + chameleon: 1.0.0 + chameleon-halogen: 1.0.3 + chameleon-react-basic: 1.1.0 + chameleon-styled: 2.5.0 + chameleon-transformers: 1.0.0 + channel: 1.0.0 + checked-exceptions: 3.1.1 + choku: 1.0.1 + classless: 0.1.1 + classless-arbitrary: 0.1.1 + classless-decode-json: 0.1.1 + classless-encode-json: 0.1.3 + classnames: 2.0.0 + codec: 6.1.0 + codec-argonaut: 10.0.0 + codec-json: 2.0.0 + colors: 7.0.1 + concur-core: 0.5.0 + concur-react: 0.5.0 + concurrent-queues: 3.0.0 + console: 6.1.0 + const: 6.0.0 + contravariant: 6.0.0 + control: 6.0.0 + convertable-options: 1.0.0 + coroutines: 7.0.0 + css: 6.0.0 + css-frameworks: 1.0.1 + csv-stream: 2.3.0 + data-mvc: 0.0.2 + datetime: 6.1.0 + datetime-parsing: 0.2.0 + debounce: 0.1.0 + debug: 6.0.2 + decimals: 7.1.0 + default-values: 1.0.1 + deku: 0.9.23 + deno: 0.0.5 + dissect: 1.0.0 + distributive: 6.0.0 + dom-filereader: 7.0.0 + dom-indexed: 12.0.0 + dom-simple: 0.4.0 + dotenv: 4.0.3 + droplet: 0.6.0 + dts: 1.0.0 + dual-numbers: 1.0.3 + dynamic-buffer: 3.0.1 + echarts-simple: 0.0.1 + effect: 4.0.0 + either: 6.1.0 + elmish: 0.13.0 + elmish-enzyme: 0.1.1 + elmish-hooks: 0.10.3 + elmish-html: 0.9.0 + elmish-testing-library: 0.3.2 + email-validate: 7.0.0 + encoding: 0.0.9 + enums: 6.0.1 + env-names: 0.4.0 + error: 2.0.0 + eta-conversion: 0.3.2 + exceptions: 6.1.0 + exists: 6.0.0 + exitcodes: 4.0.0 + expect-inferred: 3.0.0 + ezfetch: 1.0.0 + fahrtwind: 2.0.0 + fallback: 0.1.0 + fast-vect: 1.2.0 + fetch: 4.1.0 + fetch-argonaut: 1.0.1 + fetch-core: 5.1.0 + fetch-yoga-json: 1.1.0 + ffi-simple: 0.5.1 + fft-js: 0.1.0 + filterable: 5.0.0 + fix-functor: 0.1.0 + fixed-points: 7.0.0 + fixed-precision: 5.0.0 + flame: 1.3.0 + float32: 2.0.0 + fmt: 0.2.1 + foldable-traversable: 6.0.0 + foldable-traversable-extra: 0.0.6 + foreign: 7.0.0 + foreign-object: 4.1.0 + foreign-readwrite: 3.4.0 + forgetmenot: 0.1.0 + fork: 6.0.0 + form-urlencoded: 7.0.0 + formatters: 7.0.0 + framer-motion: 1.0.1 + free: 7.1.0 + freeap: 7.0.0 + freer-free: 0.0.1 + freet: 7.0.0 + functions: 6.0.0 + functor1: 3.0.0 + functors: 5.0.0 + fuzzy: 0.4.0 + gen: 4.0.0 + generate-values: 1.0.1 + generic-router: 0.0.1 + geojson: 0.0.5 + geometria: 2.2.0 + gojs: 0.1.1 + grain: 3.0.0 + grain-router: 3.0.0 + grain-virtualized: 3.0.0 + graphs: 8.1.0 + group: 4.1.1 + halogen: 7.0.0 + halogen-bootstrap5: 5.3.2 + halogen-canvas: 1.0.0 + halogen-css: 10.0.0 + halogen-echarts-simple: 0.0.4 + halogen-formless: 4.0.3 + halogen-helix: 1.0.1 + halogen-hooks: 0.6.3 + halogen-hooks-extra: 0.9.0 + halogen-infinite-scroll: 1.1.0 + halogen-store: 0.5.4 + halogen-storybook: 2.0.0 + halogen-subscriptions: 2.0.0 + halogen-svg-elems: 8.0.0 + halogen-typewriter: 1.0.4 + halogen-vdom: 8.0.0 + halogen-vdom-string-renderer: 0.5.0 + halogen-xterm: 2.0.0 + heckin: 2.0.1 + heterogeneous: 0.6.0 + homogeneous: 0.4.0 + http-methods: 6.0.0 + httpurple: 4.0.0 + huffman: 0.4.0 + humdrum: 0.0.1 + hyrule: 2.3.8 + identity: 6.0.0 + identy: 4.0.1 + indexed-db: 1.0.0 + indexed-monad: 3.0.0 + int64: 3.0.0 + integers: 6.0.0 + interpolate: 5.0.2 + intersection-observer: 1.0.1 + invariant: 6.0.0 + jarilo: 1.0.1 + jelly: 0.10.0 + jelly-router: 0.3.0 + jelly-signal: 0.4.0 + jest: 1.0.0 + js-abort-controller: 1.0.0 + js-bigints: 2.2.1 + js-date: 8.0.0 + js-fetch: 0.2.1 + js-fileio: 3.0.0 + js-intl: 1.0.4 + js-iterators: 0.1.1 + js-maps: 0.1.2 + js-promise: 1.0.0 + js-promise-aff: 1.0.0 + js-timers: 6.1.0 + js-uri: 3.1.0 + json: 1.1.0 + json-codecs: 5.0.0 + justifill: 0.5.0 + jwt: 0.0.9 + labeled-data: 0.2.0 + language-cst-parser: 0.14.0 + lazy: 6.0.0 + lazy-joe: 1.0.0 + lcg: 4.0.0 + leibniz: 5.0.0 + leveldb: 1.0.1 + liminal: 1.0.1 + linalg: 6.0.0 + lists: 7.0.0 + literals: 1.0.2 + logging: 3.0.0 + logging-journald: 0.4.0 + lumi-components: 18.0.0 + machines: 7.0.0 + maps-eager: 0.5.0 + marionette: 1.0.0 + marionette-react-basic-hooks: 0.1.1 + marked: 0.1.0 + matrices: 5.0.1 + matryoshka: 1.0.0 + maybe: 6.0.0 + media-types: 6.0.0 + meowclient: 1.0.0 + midi: 4.0.0 + milkis: 9.0.0 + minibench: 4.0.1 + mmorph: 7.0.0 + monad-control: 5.0.0 + monad-logger: 1.3.1 + monad-loops: 0.5.0 + monad-unlift: 1.0.1 + monoid-extras: 0.0.1 + monoidal: 0.16.0 + morello: 0.4.0 + mote: 3.0.0 + motsunabe: 2.0.0 + mvc: 0.0.1 + mysql: 6.0.1 + n3: 0.1.0 + nano-id: 1.1.0 + nanoid: 0.1.0 + naturals: 3.0.0 + nested-functor: 0.2.1 + newtype: 5.0.0 + nextjs: 0.1.1 + nextui: 0.2.0 + node-buffer: 9.0.0 + node-child-process: 11.1.0 + node-event-emitter: 3.0.0 + node-execa: 5.0.0 + node-fs: 9.2.0 + node-glob-basic: 1.3.0 + node-http: 9.1.0 + node-http2: 1.1.1 + node-human-signals: 1.0.0 + node-net: 5.1.0 + node-os: 5.1.0 + node-path: 5.0.0 + node-process: 11.2.0 + node-readline: 8.1.1 + node-sqlite3: 8.0.0 + node-stream-pipes: 2.1.6 + node-streams: 9.0.0 + node-tls: 0.3.1 + node-url: 7.0.1 + node-zlib: 0.4.0 + nonempty: 7.0.0 + now: 6.0.0 + npm-package-json: 2.0.0 + nullable: 6.0.0 + numberfield: 0.2.2 + numbers: 9.0.1 + oak: 3.1.1 + oak-debug: 1.2.2 + object-maps: 0.3.0 + ocarina: 1.5.4 + oooooooooorrrrrrrmm-lib: 0.0.1 + open-folds: 6.4.0 + open-foreign-generic: 11.0.3 + open-memoize: 6.2.0 + open-mkdirp-aff: 1.2.0 + open-pairing: 6.2.0 + open-smolder: 12.0.2 + options: 7.0.0 + optparse: 5.0.1 + ordered-collections: 3.2.0 + ordered-set: 0.4.0 + orders: 6.0.0 + owoify: 1.2.0 + pairs: 9.0.1 + parallel: 7.0.0 + parsing: 10.2.0 + parsing-dataview: 3.2.4 + partial: 4.0.0 + pathy: 9.0.0 + pha: 0.13.0 + phaser: 0.7.0 + phylio: 1.1.2 + pipes: 8.0.0 + pirates-charm: 0.0.1 + pmock: 0.9.0 + point-free: 1.0.0 + pointed-list: 0.5.1 + polymorphic-vectors: 4.0.0 + posix-types: 6.0.0 + postgresql: 2.0.19 + precise: 6.0.0 + precise-datetime: 7.0.0 + prelude: 6.0.1 + prettier-printer: 3.0.0 + priority-queue: 0.1.2 + profunctor: 6.0.1 + profunctor-lenses: 8.0.0 + protobuf: 4.3.0 + psa-utils: 8.0.0 + psci-support: 6.0.0 + punycode: 1.0.0 + qualified-do: 2.2.0 + quantities: 12.2.0 + quickcheck: 8.0.1 + quickcheck-combinators: 0.1.3 + quickcheck-laws: 7.0.0 + quickcheck-utf8: 0.0.0 + random: 6.0.0 + rationals: 6.0.0 + rdf: 0.1.0 + react: 11.0.0 + react-aria: 0.2.0 + react-basic: 17.0.0 + react-basic-classic: 3.0.0 + react-basic-dnd: 10.1.0 + react-basic-dom: 6.1.0 + react-basic-emotion: 7.1.0 + react-basic-hooks: 8.2.0 + react-basic-storybook: 2.0.0 + react-dom: 8.0.0 + react-halo: 3.0.0 + react-icons: 1.1.5 + react-markdown: 0.1.0 + react-testing-library: 4.0.1 + react-virtuoso: 1.0.0 + reactix: 0.6.1 + read: 1.0.1 + recharts: 1.1.0 + record: 4.0.0 + record-extra: 5.0.1 + record-ptional-fields: 0.1.2 + record-studio: 1.0.4 + refs: 6.0.0 + remotedata: 5.0.1 + repr: 0.5.0 + resize-observer: 1.0.0 + resource: 2.0.1 + resourcet: 1.0.0 + result: 1.0.3 + return: 0.2.0 + ring-modules: 5.0.1 + rito: 0.3.4 + roman: 0.4.0 + rough-notation: 1.0.2 + routing: 11.0.0 + routing-duplex: 0.7.0 + run: 5.0.0 + safe-coerce: 2.0.0 + safely: 4.0.1 + school-of-music: 1.3.0 + selection-foldable: 0.2.0 + selective-functors: 1.0.1 + semirings: 7.0.0 + signal: 13.0.0 + simple-emitter: 3.0.1 + simple-i18n: 2.0.1 + simple-json: 9.0.0 + simple-json-generics: 0.2.1 + simple-ulid: 3.0.0 + sized-matrices: 1.0.0 + sized-vectors: 5.0.2 + slug: 3.1.0 + small-ffi: 4.0.1 + soundfonts: 4.1.0 + sparse-matrices: 2.0.1 + sparse-polynomials: 3.0.1 + spec: 8.0.0 + spec-discovery: 8.3.0 + spec-mocha: 5.1.1 + spec-node: 0.0.2 + spec-quickcheck: 5.0.2 + spec-reporter-xunit: 0.7.1 + splitmix: 2.1.0 + ssrs: 1.0.0 + st: 6.2.0 + statistics: 0.3.2 + strictlypositiveint: 1.0.1 + string-parsers: 8.0.0 + strings: 6.0.1 + strings-extra: 4.0.0 + stringutils: 0.0.12 + substitute: 0.2.3 + supply: 0.2.0 + svg-parser: 3.0.0 + systemd-journald: 0.3.0 + tagged: 4.0.2 + tailrec: 6.1.0 + tecton: 0.2.1 + tecton-halogen: 0.2.0 + test-unit: 17.0.0 + thermite: 6.3.1 + thermite-dom: 0.3.1 + these: 6.0.0 + threading: 0.0.3 + tldr: 0.0.0 + toestand: 0.9.0 + transformation-matrix: 1.0.1 + transformers: 6.1.0 + tree-rose: 4.0.2 + ts-bridge: 4.0.0 + tuples: 7.0.0 + two-or-more: 1.0.0 + type-equality: 4.0.1 + typedenv: 2.0.1 + typelevel: 6.0.0 + typelevel-lists: 2.1.0 + typelevel-peano: 1.0.1 + typelevel-prelude: 7.0.0 + typelevel-regex: 0.0.3 + typelevel-rows: 0.1.0 + typisch: 0.4.0 + uint: 7.0.0 + ulid: 3.0.1 + uncurried-transformers: 1.1.0 + undefined: 2.0.0 + undefined-is-not-a-problem: 1.1.0 + unfoldable: 6.0.0 + unicode: 6.0.0 + unique: 0.6.1 + unlift: 1.0.1 + unordered-collections: 3.1.0 + unsafe-coerce: 6.0.0 + unsafe-reference: 5.0.0 + untagged-to-tagged: 0.1.4 + untagged-union: 1.0.0 + uri: 9.0.0 + url-immutable: 1.0.0 + uuid: 9.0.0 + uuidv4: 1.0.0 + validation: 6.0.0 + variant: 8.0.0 + variant-encodings: 2.0.0 + vectorfield: 1.0.1 + vectors: 2.1.0 + versions: 7.0.0 + visx: 0.0.2 + web-clipboard: 6.0.0 + web-cssom: 2.0.0 + web-cssom-view: 0.1.0 + web-dom: 6.0.0 + web-dom-parser: 8.0.0 + web-dom-xpath: 3.0.0 + web-encoding: 3.0.0 + web-events: 4.0.0 + web-fetch: 4.0.1 + web-file: 4.0.0 + web-geometry: 0.1.0 + web-html: 4.1.0 + web-pointerevents: 2.0.0 + web-proletarian: 1.0.0 + web-promise: 3.2.0 + web-resize-observer: 2.1.0 + web-router: 1.0.0 + web-socket: 4.0.0 + web-storage: 5.0.0 + web-streams: 4.0.0 + web-touchevents: 4.0.0 + web-uievents: 5.0.0 + web-url: 2.0.0 + web-workers: 1.1.0 + web-xhr: 5.0.1 + webextension-polyfill: 0.1.0 + webgpu: 0.0.1 + which: 2.0.0 + xterm: 1.0.0 + yoga-fetch: 1.0.1 + yoga-json: 5.1.0 + yoga-om: 0.1.0 + yoga-postgres: 6.0.0 + yoga-tree: 1.0.0 + z3: 0.0.2 + zipperarray: 2.0.0 + extra_packages: + bench: + path: /home/srghma/projects/purescript-language-cst-parser/bench + bin: + path: /home/srghma/projects/purescript-overlay/generate/bin + bolson: + path: /home/srghma/projects/purescript-bolson + codegen: + path: /home/srghma/projects/purescript-deku/codegen + deku: + path: /home/srghma/projects/purescript-deku/deku + deku-core: + path: /home/srghma/projects/purescript-deku/deku-core + deku-css: + path: /home/srghma/projects/purescript-deku/deku-css + deku-documentation: + path: /home/srghma/projects/deku-documentation + deku-dom: + path: /home/srghma/projects/purescript-deku/deku-dom + deku-nextui: + path: /home/srghma/projects/purescript-deku-nextui + dodo-printer: + path: /home/srghma/projects/purescript-dodo-printer + express: + path: /home/srghma/projects/purescript-express + faker: + path: /home/srghma/projects/purescript-faker + foreign-generic: + path: /home/srghma/projects/purescript-foreign-generic + foreign-js-map: + path: /home/srghma/projects/purescript-foreign-js-map + github-actions-toolkit: + path: /home/srghma/projects/purescript-github-actions-toolkit + homogeneous-records: + path: /home/srghma/projects/purescript-homogeneous-records + html2deku: + path: /home/srghma/projects/html2deku + hyper: + path: /home/srghma/projects/hyper + hyrule: + path: /home/srghma/projects/purescript-hyrule + hyrule-demo: + path: /home/srghma/projects/purescript-hyrule-demo + jsdom: + path: /home/srghma/projects/purescript-jsdom + language-cst-parser: + path: /home/srghma/projects/purescript-language-cst-parser/lib + lib: + path: /home/srghma/projects/purescript-overlay/generate/lib + lumi-components: + path: /home/srghma/projects/purescript-lumi-components + lunapark: + path: /home/srghma/projects/purescript-lunapark + myapp-api-server: + path: /home/srghma/projects/nativescript-testapp/packages/api-server + myapp-common: + path: /home/srghma/projects/nativescript-testapp/packages/common + node-buffer-blob: + path: /home/srghma/projects/purescript-node-buffer-blob + node-workerbees: + path: /home/srghma/projects/purescript-node-workerbees + nodemailer: + path: /home/srghma/projects/purescript-nodemailer + open-drawing: + path: /home/srghma/projects/purescript-open-drawing/lib + open-drawing-example: + path: /home/srghma/projects/purescript-open-drawing/example + open-express-passport: + path: /home/srghma/projects/purescript-open-express-passport + open-folds: + path: /home/srghma/projects/purescript-open-folds + open-foreign-generic: + path: /home/srghma/projects/purescript-open-foreign-generic + open-memoize: + path: /home/srghma/projects/purescript-open-memoize + open-mkdirp-aff: + path: /home/srghma/projects/purescript-open-mkdirp-aff + open-pairing: + path: /home/srghma/projects/purescript-open-pairing_ + open-smolder: + path: /home/srghma/projects/purescript-open-smolder + parse-package-set: + path: /home/srghma/projects/purescript-language-cst-parser/parse-package-set + parsing: + path: /home/srghma/projects/purescript-parsing + pathy-node-fs: + path: /home/srghma/projects/purescript-pathy-node-fs + postgresql-client: + path: /home/srghma/projects/purescript-postgresql-client + profunctor: + path: /home/srghma/projects/purescript-profunctor + protolude: + path: /home/srghma/projects/purescript-protolude + record-extra-srghma: + path: /home/srghma/projects/purescript-record-extra-srghma + routing-duplex-variant: + path: /home/srghma/projects/purescript-routing-duplex-variant + simple: + path: /home/srghma/projects/purescript-overlay/nix/examples/simple + simple-codegen: + path: /home/srghma/projects/purescript-overlay/nix/examples/simple-codegen + simple-ffi: + path: /home/srghma/projects/purescript-overlay/nix/examples/simple-ffi + spago: + path: /home/srghma/projects/spago + spago-bin: + path: /home/srghma/projects/spago/bin + spago-core: + path: /home/srghma/projects/spago/core + spec-discovery: + path: /home/srghma/projects/purescript-spec-discovery + tidy: + path: /home/srghma/projects/purescript-tidy/lib + tidy-cli: + path: /home/srghma/projects/purescript-tidy/bin + tidy-codegen: + path: /home/srghma/projects/purescript-tidy-codegen + tidy-script: + path: /home/srghma/projects/purescript-tidy/script + tldr: + path: /home/srghma/projects/purescript-tldr + web-intersection-observer: + path: /home/srghma/projects/purescript-web-intersection-observer + webpack-loader-api: + path: /home/srghma/projects/purescript-webpack-loader-api + websocket-simple: + path: /home/srghma/projects/purescript-websocket-simple + yarn: + path: /home/srghma/projects/purescript-yarn +packages: + aff: + type: registry + version: 8.0.0 + integrity: sha256-5MmdI4+0RHBtSBy+YlU3/Cq4R5W2ih3OaRedJIrVHdk= + dependencies: + - bifunctors + - control + - datetime + - effect + - either + - exceptions + - foldable-traversable + - functions + - maybe + - newtype + - parallel + - prelude + - refs + - tailrec + - transformers + - unsafe-coerce + aff-promise: + type: registry + version: 4.0.0 + integrity: sha256-Kq5EupbUpXeUXx4JqGQE7/RTTz/H6idzWhsocwlEFhM= + dependencies: + - aff + - foreign + arraybuffer-types: + type: registry + version: 3.0.2 + integrity: sha256-mQKokysYVkooS4uXbO+yovmV/s8b138Ws3zQvOwIHRA= + dependencies: [] + arrays: + type: registry + version: 7.3.0 + integrity: sha256-tmcklBlc/muUtUfr9RapdCPwnlQeB3aSrC4dK85gQlc= + dependencies: + - bifunctors + - control + - foldable-traversable + - functions + - maybe + - nonempty + - partial + - prelude + - safe-coerce + - st + - tailrec + - tuples + - unfoldable + - unsafe-coerce + assert: + type: registry + version: 6.0.0 + integrity: sha256-hCSYcCw9kj3qujoDcriWhCdmrpPZoguSPDZhEMnTl3A= + dependencies: + - console + - effect + - prelude + bifunctors: + type: registry + version: 6.0.0 + integrity: sha256-/gZwC9YhNxZNQpnHa5BIYerCGM2jeX9ukZiEvYxm5Nw= + dependencies: + - const + - either + - newtype + - prelude + - tuples + console: + type: registry + version: 6.1.0 + integrity: sha256-CxmAzjgyuGDmt9FZW51VhV6rBPwR6o0YeKUzA9rSzcM= + dependencies: + - effect + - prelude + const: + type: registry + version: 6.0.0 + integrity: sha256-tNrxDW8D8H4jdHE2HiPzpLy08zkzJMmGHdRqt5BQuTc= + dependencies: + - invariant + - newtype + - prelude + contravariant: + type: registry + version: 6.0.0 + integrity: sha256-TP+ooAp3vvmdjfQsQJSichF5B4BPDHp3wAJoWchip6c= + dependencies: + - const + - either + - newtype + - prelude + - tuples + control: + type: registry + version: 6.0.0 + integrity: sha256-sH7Pg9E96JCPF9PIA6oQ8+BjTyO/BH1ZuE/bOcyj4Jk= + dependencies: + - newtype + - prelude + datetime: + type: registry + version: 6.1.0 + integrity: sha256-g/5X5BBegQWLpI9IWD+sY6mcaYpzzlW5lz5NBzaMtyI= + dependencies: + - bifunctors + - control + - either + - enums + - foldable-traversable + - functions + - gen + - integers + - lists + - maybe + - newtype + - numbers + - ordered-collections + - partial + - prelude + - tuples + distributive: + type: registry + version: 6.0.0 + integrity: sha256-HTDdmEnzigMl+02SJB88j+gAXDx9VKsbvR4MJGDPbOQ= + dependencies: + - identity + - newtype + - prelude + - tuples + - type-equality + effect: + type: registry + version: 4.0.0 + integrity: sha256-eBtZu+HZcMa5HilvI6kaDyVX3ji8p0W9MGKy2K4T6+M= + dependencies: + - prelude + either: + type: registry + version: 6.1.0 + integrity: sha256-6hgTPisnMWVwQivOu2PKYcH8uqjEOOqDyaDQVUchTpY= + dependencies: + - control + - invariant + - maybe + - prelude + enums: + type: registry + version: 6.0.1 + integrity: sha256-HWaD73JFLorc4A6trKIRUeDMdzE+GpkJaEOM1nTNkC8= + dependencies: + - control + - either + - gen + - maybe + - newtype + - nonempty + - partial + - prelude + - tuples + - unfoldable + exceptions: + type: registry + version: 6.1.0 + integrity: sha256-K0T89IHtF3vBY7eSAO7eDOqSb2J9kZGAcDN5+IKsF8E= + dependencies: + - effect + - either + - maybe + - prelude + exists: + type: registry + version: 6.0.0 + integrity: sha256-A0JQHpTfo1dNOj9U5/Fd3xndlRSE0g2IQWOGor2yXn8= + dependencies: + - unsafe-coerce + foldable-traversable: + type: registry + version: 6.0.0 + integrity: sha256-fLeqRYM4jUrZD5H4WqcwUgzU7XfYkzO4zhgtNc3jcWM= + dependencies: + - bifunctors + - const + - control + - either + - functors + - identity + - maybe + - newtype + - orders + - prelude + - tuples + foreign: + type: registry + version: 7.0.0 + integrity: sha256-1ORiqoS3HW+qfwSZAppHPWy4/6AQysxZ2t29jcdUMNA= + dependencies: + - either + - functions + - identity + - integers + - lists + - maybe + - prelude + - strings + - transformers + functions: + type: registry + version: 6.0.0 + integrity: sha256-adMyJNEnhGde2unHHAP79gPtlNjNqzgLB8arEOn9hLI= + dependencies: + - prelude + functors: + type: registry + version: 5.0.0 + integrity: sha256-zfPWWYisbD84MqwpJSZFlvM6v86McM68ob8p9s27ywU= + dependencies: + - bifunctors + - const + - contravariant + - control + - distributive + - either + - invariant + - maybe + - newtype + - prelude + - profunctor + - tuples + - unsafe-coerce + gen: + type: registry + version: 4.0.0 + integrity: sha256-f7yzAXWwr+xnaqEOcvyO3ezKdoes8+WXWdXIHDBCAPI= + dependencies: + - either + - foldable-traversable + - identity + - maybe + - newtype + - nonempty + - prelude + - tailrec + - tuples + - unfoldable + identity: + type: registry + version: 6.0.0 + integrity: sha256-4wY0XZbAksjY6UAg99WkuKyJlQlWAfTi2ssadH0wVMY= + dependencies: + - control + - invariant + - newtype + - prelude + integers: + type: registry + version: 6.0.0 + integrity: sha256-sf+sK26R1hzwl3NhXR7WAu9zCDjQnfoXwcyGoseX158= + dependencies: + - maybe + - numbers + - prelude + invariant: + type: registry + version: 6.0.0 + integrity: sha256-RGWWyYrz0Hs1KjPDA+87Kia67ZFBhfJ5lMGOMCEFoLo= + dependencies: + - control + - prelude + js-date: + type: registry + version: 8.0.0 + integrity: sha256-6TVF4DWg5JL+jRAsoMssYw8rgOVALMUHT1CuNZt8NRo= + dependencies: + - datetime + - effect + - exceptions + - foreign + - integers + - now + js-promise: + type: registry + version: 1.0.0 + integrity: sha256-kXNo5g9RJgPdrTuKRe5oG2kBIwPp+j5VDPDplqZBJzQ= + dependencies: + - effect + - exceptions + - foldable-traversable + - functions + - maybe + - prelude + lazy: + type: registry + version: 6.0.0 + integrity: sha256-lMsfFOnlqfe4KzRRiW8ot5ge6HtcU3Eyh2XkXcP5IgU= + dependencies: + - control + - foldable-traversable + - invariant + - prelude + lists: + type: registry + version: 7.0.0 + integrity: sha256-EKF15qYqucuXP2lT/xPxhqy58f0FFT6KHdIB/yBOayI= + dependencies: + - bifunctors + - control + - foldable-traversable + - lazy + - maybe + - newtype + - nonempty + - partial + - prelude + - tailrec + - tuples + - unfoldable + maybe: + type: registry + version: 6.0.0 + integrity: sha256-5cCIb0wPwbat2PRkQhUeZO0jcAmf8jCt2qE0wbC3v2Q= + dependencies: + - control + - invariant + - newtype + - prelude + media-types: + type: registry + version: 6.0.0 + integrity: sha256-n/4FoGBasbVSYscGVRSyBunQ6CZbL3jsYL+Lp01mc9k= + dependencies: + - newtype + - prelude + newtype: + type: registry + version: 5.0.0 + integrity: sha256-gdrQu8oGe9eZE6L3wOI8ql/igOg+zEGB5ITh2g+uttw= + dependencies: + - prelude + - safe-coerce + node-buffer: + type: registry + version: 9.0.0 + integrity: sha256-PWE2DJ5ruBLCmeA/fUiuySEFmUJ/VuRfyrnCuVZBlu4= + dependencies: + - arraybuffer-types + - effect + - maybe + - nullable + - st + - unsafe-coerce + node-buffer-blob: + type: local + path: /home/srghma/projects/purescript-node-buffer-blob + dependencies: + - aff-promise + - arraybuffer-types + - arrays + - effect + - maybe + - media-types + - newtype + - node-buffer + - nullable + - prelude + - web-streams + node-event-emitter: + type: registry + version: 3.0.0 + integrity: sha256-Qw0MjsT4xRH2j2i4K8JmRjcMKnH5z1Cw39t00q4LE4w= + dependencies: + - effect + - either + - functions + - maybe + - nullable + - prelude + - unsafe-coerce + node-path: + type: registry + version: 5.0.0 + integrity: sha256-pd82nQ+2l5UThzaxPdKttgDt7xlsgIDLpPG0yxDEdyE= + dependencies: + - effect + node-streams: + type: registry + version: 9.0.0 + integrity: sha256-2n6dq7YWleTDmD1Kur/ul7Cn08IvWrScgPf+0PgX2TQ= + dependencies: + - aff + - effect + - either + - exceptions + - node-buffer + - node-event-emitter + - nullable + - prelude + nonempty: + type: registry + version: 7.0.0 + integrity: sha256-54ablJZUHGvvlTJzi3oXyPCuvY6zsrWJuH/dMJ/MFLs= + dependencies: + - control + - foldable-traversable + - maybe + - prelude + - tuples + - unfoldable + now: + type: registry + version: 6.0.0 + integrity: sha256-xZ7x37ZMREfs6GCDw/h+FaKHV/3sPWmtqBZRGTxybQY= + dependencies: + - datetime + - effect + nullable: + type: registry + version: 6.0.0 + integrity: sha256-yiGBVl3AD+Guy4kNWWeN+zl1gCiJK+oeIFtZtPCw4+o= + dependencies: + - effect + - functions + - maybe + numbers: + type: registry + version: 9.0.1 + integrity: sha256-/9M6aeMDBdB4cwYDeJvLFprAHZ49EbtKQLIJsneXLIk= + dependencies: + - functions + - maybe + ordered-collections: + type: registry + version: 3.2.0 + integrity: sha256-o9jqsj5rpJmMdoe/zyufWHFjYYFTTsJpgcuCnqCO6PM= + dependencies: + - arrays + - foldable-traversable + - gen + - lists + - maybe + - partial + - prelude + - st + - tailrec + - tuples + - unfoldable + orders: + type: registry + version: 6.0.0 + integrity: sha256-nBA0g3/ai0euH8q9pSbGqk53W2q6agm/dECZTHcoink= + dependencies: + - newtype + - prelude + parallel: + type: registry + version: 7.0.0 + integrity: sha256-gUC9i4Txnx9K9RcMLsjujbwZz6BB1bnE2MLvw4GIw5o= + dependencies: + - control + - effect + - either + - foldable-traversable + - functors + - maybe + - newtype + - prelude + - profunctor + - refs + - transformers + partial: + type: registry + version: 4.0.0 + integrity: sha256-fwXerld6Xw1VkReh8yeQsdtLVrjfGiVuC5bA1Wyo/J4= + dependencies: [] + prelude: + type: registry + version: 6.0.1 + integrity: sha256-o8p6SLYmVPqzXZhQFd2hGAWEwBoXl1swxLG/scpJ0V0= + dependencies: [] + profunctor: + type: local + path: /home/srghma/projects/purescript-profunctor + dependencies: + - control + - distributive + - either + - exists + - invariant + - newtype + - prelude + - tuples + refs: + type: registry + version: 6.0.0 + integrity: sha256-Vgwne7jIbD3ZMoLNNETLT8Litw6lIYo3MfYNdtYWj9s= + dependencies: + - effect + - prelude + safe-coerce: + type: registry + version: 2.0.0 + integrity: sha256-a1ibQkiUcbODbLE/WAq7Ttbbh9ex+x33VCQ7GngKudU= + dependencies: + - unsafe-coerce + st: + type: registry + version: 6.2.0 + integrity: sha256-z9X0WsOUlPwNx9GlCC+YccCyz8MejC8Wb0C4+9fiBRY= + dependencies: + - partial + - prelude + - tailrec + - unsafe-coerce + strings: + type: registry + version: 6.0.1 + integrity: sha256-WssD3DbX4OPzxSdjvRMX0yvc9+pS7n5gyPv5I2Trb7k= + dependencies: + - arrays + - control + - either + - enums + - foldable-traversable + - gen + - integers + - maybe + - newtype + - nonempty + - partial + - prelude + - tailrec + - tuples + - unfoldable + - unsafe-coerce + tailrec: + type: registry + version: 6.1.0 + integrity: sha256-Xx19ECVDRrDWpz9D2GxQHHV89vd61dnXxQm0IcYQHGk= + dependencies: + - bifunctors + - effect + - either + - identity + - maybe + - partial + - prelude + - refs + transformers: + type: registry + version: 6.1.0 + integrity: sha256-3Bm+Z6tsC/paG888XkywDngJ2JMos+JfOhRlkVfb7gI= + dependencies: + - control + - distributive + - effect + - either + - exceptions + - foldable-traversable + - identity + - lazy + - maybe + - newtype + - prelude + - st + - tailrec + - tuples + - unfoldable + tuples: + type: registry + version: 7.0.0 + integrity: sha256-1rXgTomes9105BjgXqIw0FL6Fz1lqqUTLWOumhWec1M= + dependencies: + - control + - invariant + - prelude + type-equality: + type: registry + version: 4.0.1 + integrity: sha256-Hs9D6Y71zFi/b+qu5NSbuadUQXe5iv5iWx0226vOHUw= + dependencies: [] + unfoldable: + type: registry + version: 6.0.0 + integrity: sha256-JtikvJdktRap7vr/K4ITlxUX1QexpnqBq0G/InLr6eg= + dependencies: + - foldable-traversable + - maybe + - partial + - prelude + - tuples + unsafe-coerce: + type: registry + version: 6.0.0 + integrity: sha256-IqIYW4Vkevn8sI+6aUwRGvd87tVL36BBeOr0cGAE7t0= + dependencies: [] + web-streams: + type: registry + version: 4.0.0 + integrity: sha256-02HgXIk6R+pU9fWOX42krukAI1QkCbLKcCv3b4Jq6WI= + dependencies: + - arraybuffer-types + - effect + - exceptions + - js-promise + - nullable + - prelude + - tuples diff --git a/spago.yaml b/spago.yaml new file mode 100644 index 0000000..67bd253 --- /dev/null +++ b/spago.yaml @@ -0,0 +1,167 @@ +package: + name: node-fs + publish: + license: MIT + version: 9.2.0 + location: + githubOwner: purescript-node + githubRepo: purescript-node-fs + dependencies: + - datetime + - effect + - either + - enums + - exceptions + - functions + - integers + - js-date + - maybe + - node-buffer + - node-path + - node-streams + - nullable + - partial + - prelude + - strings + - unsafe-coerce + - node-buffer-blob + - refs + test: + main: Test.Main + dependencies: + - console + - aff + - arrays + - assert +workspace: + packageSet: + registry: 60.2.1 + extraPackages: + bench: + path: /home/srghma/projects/purescript-language-cst-parser/bench + bin: + path: /home/srghma/projects/purescript-overlay/generate/bin + bolson: + path: /home/srghma/projects/purescript-bolson + codegen: + path: /home/srghma/projects/purescript-deku/codegen + deku: + path: /home/srghma/projects/purescript-deku/deku + deku-core: + path: /home/srghma/projects/purescript-deku/deku-core + deku-css: + path: /home/srghma/projects/purescript-deku/deku-css + deku-documentation: + path: /home/srghma/projects/deku-documentation + deku-dom: + path: /home/srghma/projects/purescript-deku/deku-dom + deku-nextui: + path: /home/srghma/projects/purescript-deku-nextui + dodo-printer: + path: /home/srghma/projects/purescript-dodo-printer + express: + path: /home/srghma/projects/purescript-express + faker: + path: /home/srghma/projects/purescript-faker + foreign-generic: + path: /home/srghma/projects/purescript-foreign-generic + foreign-js-map: + path: /home/srghma/projects/purescript-foreign-js-map + github-actions-toolkit: + path: /home/srghma/projects/purescript-github-actions-toolkit + homogeneous-records: + path: /home/srghma/projects/purescript-homogeneous-records + html2deku: + path: /home/srghma/projects/html2deku + hyper: + path: /home/srghma/projects/hyper + hyrule: + path: /home/srghma/projects/purescript-hyrule + hyrule-demo: + path: /home/srghma/projects/purescript-hyrule-demo + jsdom: + path: /home/srghma/projects/purescript-jsdom + language-cst-parser: + path: /home/srghma/projects/purescript-language-cst-parser/lib + lib: + path: /home/srghma/projects/purescript-overlay/generate/lib + lumi-components: + path: /home/srghma/projects/purescript-lumi-components + lunapark: + path: /home/srghma/projects/purescript-lunapark + myapp-api-server: + path: /home/srghma/projects/nativescript-testapp/packages/api-server + myapp-common: + path: /home/srghma/projects/nativescript-testapp/packages/common + node-buffer-blob: + path: /home/srghma/projects/purescript-node-buffer-blob + node-workerbees: + path: /home/srghma/projects/purescript-node-workerbees + nodemailer: + path: /home/srghma/projects/purescript-nodemailer + open-drawing: + path: /home/srghma/projects/purescript-open-drawing/lib + open-drawing-example: + path: /home/srghma/projects/purescript-open-drawing/example + open-express-passport: + path: /home/srghma/projects/purescript-open-express-passport + open-folds: + path: /home/srghma/projects/purescript-open-folds + open-foreign-generic: + path: /home/srghma/projects/purescript-open-foreign-generic + open-memoize: + path: /home/srghma/projects/purescript-open-memoize + open-mkdirp-aff: + path: /home/srghma/projects/purescript-open-mkdirp-aff + open-pairing: + path: /home/srghma/projects/purescript-open-pairing_ + open-smolder: + path: /home/srghma/projects/purescript-open-smolder + parse-package-set: + path: /home/srghma/projects/purescript-language-cst-parser/parse-package-set + parsing: + path: /home/srghma/projects/purescript-parsing + pathy-node-fs: + path: /home/srghma/projects/purescript-pathy-node-fs + postgresql-client: + path: /home/srghma/projects/purescript-postgresql-client + profunctor: + path: /home/srghma/projects/purescript-profunctor + protolude: + path: /home/srghma/projects/purescript-protolude + record-extra-srghma: + path: /home/srghma/projects/purescript-record-extra-srghma + routing-duplex-variant: + path: /home/srghma/projects/purescript-routing-duplex-variant + simple: + path: /home/srghma/projects/purescript-overlay/nix/examples/simple + simple-codegen: + path: /home/srghma/projects/purescript-overlay/nix/examples/simple-codegen + simple-ffi: + path: /home/srghma/projects/purescript-overlay/nix/examples/simple-ffi + spago: + path: /home/srghma/projects/spago + spago-bin: + path: /home/srghma/projects/spago/bin + spago-core: + path: /home/srghma/projects/spago/core + spec-discovery: + path: /home/srghma/projects/purescript-spec-discovery + tidy: + path: /home/srghma/projects/purescript-tidy/lib + tidy-cli: + path: /home/srghma/projects/purescript-tidy/bin + tidy-codegen: + path: /home/srghma/projects/purescript-tidy-codegen + tidy-script: + path: /home/srghma/projects/purescript-tidy/script + tldr: + path: /home/srghma/projects/purescript-tldr + web-intersection-observer: + path: /home/srghma/projects/purescript-web-intersection-observer + webpack-loader-api: + path: /home/srghma/projects/purescript-webpack-loader-api + websocket-simple: + path: /home/srghma/projects/purescript-websocket-simple + yarn: + path: /home/srghma/projects/purescript-yarn diff --git a/src/Node/FS/Aff.purs b/src/Node/FS/Aff.purs index 8de7b8a..583cd51 100644 --- a/src/Node/FS/Aff.purs +++ b/src/Node/FS/Aff.purs @@ -24,6 +24,13 @@ module Node.FS.Aff , mkdir , mkdir' , readdir + , readdir' + , readdirBuffer + , readdirBuffer' + , readdirDirent + , readdirDirent' + , readdirDirentBuffer + , readdirDirentBuffer' , utimes , readFile , readTextFile @@ -37,6 +44,32 @@ module Node.FS.Aff , fdWrite , fdAppend , fdClose + , cp + , cp' + , fchmod + , fchown + , fdatasync + , fstat + , fsync + , ftruncate + , futimes + , glob + , glob' + , globDirent + , globDirent' + , lchmod + , lchown + , lutimes + -- , openAsBlob + , opendir + , opendir' + , readv + , statfs + -- , unwatchFile + -- , watch + -- , watchFile + , writev + , module Exports ) where import Prelude @@ -44,13 +77,18 @@ import Prelude import Data.DateTime (DateTime) import Data.Either (Either(..)) import Data.Maybe (Maybe) +import Data.Tuple (Tuple) import Effect (Effect) import Effect.Aff (Aff, Error, makeAff, nonCanceler) import Node.Buffer (Buffer) import Node.Encoding (Encoding) import Node.FS as F +import Node.FS.Async (CpOptions) +import Node.FS.Async (CpOptions, CpForce(..), cpOptionsDefault) as Exports import Node.FS.Async as A import Node.FS.Constants (AccessMode, CopyMode) +import Node.FS.Dir (Dir) +import Node.FS.Dirent (Dirent, DirentNameTypeBuffer, DirentNameTypeString) import Node.FS.Perms (Perms) import Node.FS.Stats (Stats) import Node.Path (FilePath) @@ -85,6 +123,16 @@ toAff3 -> Aff a toAff3 f a b c = toAff (f a b c) +-- toAff4 +-- :: forall a x y z +-- . (x -> y -> z -> y -> A.Callback a -> Effect Unit) +-- -> x +-- -> y +-- -> z +-- -> y +-- -> Aff a +-- toAff4 f a b c d = toAff (f a b c d) + toAff5 :: forall a w v x y z . (w -> v -> x -> y -> z -> A.Callback a -> Effect Unit) @@ -96,6 +144,18 @@ toAff5 -> Aff a toAff5 f a b c d e = toAff (f a b c d e) +-- toAff6 +-- :: forall a w v x y z t +-- . (w -> v -> x -> y -> z -> t -> A.Callback a -> Effect Unit) +-- -> w +-- -> v +-- -> x +-- -> y +-- -> z +-- -> t +-- -> Aff a +-- toAff6 f a b c d e t = toAff (f a b c d e t) + access :: String -> Aff (Maybe Error) access path = makeAff \k -> do A.access path (k <<< Right) @@ -237,6 +297,39 @@ mkdir' = toAff2 A.mkdir' readdir :: FilePath -> Aff (Array FilePath) readdir = toAff1 A.readdir +-- | Reads the contents of a directory with options. +readdir' :: FilePath -> { recursive :: Boolean, encoding :: Encoding } -> Aff (Array FilePath) +readdir' = toAff2 A.readdir' + +-- | Reads the contents of a directory and returns an Aff (Array Buffer). +readdirBuffer :: FilePath -> Aff (Array Buffer) +readdirBuffer = toAff1 A.readdirBuffer + +-- | Reads the contents of a directory with options and returns Aff (Array Buffer). +readdirBuffer' :: FilePath -> { recursive :: Boolean } -> Aff (Array Buffer) +readdirBuffer' = toAff2 A.readdirBuffer' + +-- | Reads the contents of a directory and returns an Aff (Array (Dirent DirentNameTypeString)). +readdirDirent :: FilePath -> Aff (Array (Dirent DirentNameTypeString)) +readdirDirent = toAff1 A.readdirDirent + +-- | Reads the contents of a directory with options and returns Aff (Array (Dirent DirentNameTypeString)). +readdirDirent' :: FilePath -> { recursive :: Boolean, encoding :: Encoding } -> Aff (Array (Dirent DirentNameTypeString)) +readdirDirent' = toAff2 A.readdirDirent' + +-- | Reads the contents of a directory. +readdirDirentBuffer + :: FilePath + -> Aff (Array (Dirent DirentNameTypeBuffer)) +readdirDirentBuffer = toAff1 A.readdirDirentBuffer + +-- | Reads the contents of a directory. +readdirDirentBuffer' + :: FilePath + -> { recursive :: Boolean } + -> Aff (Array (Dirent DirentNameTypeBuffer)) +readdirDirentBuffer' = toAff2 A.readdirDirentBuffer' + -- | -- | Sets the accessed and modified times for the specified file. -- | @@ -324,3 +417,122 @@ fdAppend = toAff2 A.fdAppend -- | for details. fdClose :: F.FileDescriptor -> Aff Unit fdClose = toAff1 A.fdClose + +-- | Copy a file asynchronously. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fspromises_copyfile_src_dest_mode) +-- | for details. +cp :: FilePath -> FilePath -> Aff Unit +cp = toAff2 A.cp + +cp' :: FilePath -> FilePath -> CpOptions -> Aff Unit +cp' = toAff3 A.cp' + +-- | Change permissions on a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fchmod_fd_mode_callback) +-- | for details. +fchmod :: F.FileDescriptor -> Perms -> Aff Unit +fchmod = toAff2 A.fchmod + +-- | Change ownership of a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fchown_fd_uid_gid_callback) +-- | for details. +fchown :: F.FileDescriptor -> Int -> Int -> Aff Unit +fchown = toAff3 A.fchown + +-- | Synchronize a file's in-core state with storage. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fdatasync_fd_callback) +-- | for details. +fdatasync :: F.FileDescriptor -> Aff Unit +fdatasync = toAff1 A.fdatasync + +-- | Get file status information. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fstat_fd_callback) +-- | for details. +fstat :: F.FileDescriptor -> Aff Stats +fstat = toAff1 A.fstat + +-- | Flushes a file descriptor to disk. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fsync_fd_callback) +-- | for details. +fsync :: F.FileDescriptor -> Aff Unit +fsync = toAff1 A.fsync + +-- | Truncate a file to a specified length. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_ftruncate_fd_len_callback) +-- | for details. +ftruncate :: F.FileDescriptor -> Int -> Aff Unit +ftruncate = toAff2 A.ftruncate + +-- | Change file timestamps for a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_futimes_fd_atime_mtime_callback) +-- | for details. +futimes :: FilePath -> DateTime -> DateTime -> Aff Unit +futimes = toAff3 A.futimes + +-- | Perform pattern matching in file paths. See the [Node Documentation](https://nodejs.org/api/glob.html#globglob_pattern_options_callback) +-- | for details. +glob :: Array FilePath -> Aff (Array FilePath) +glob = toAff1 A.glob + +glob' :: Array FilePath -> { cwd :: Maybe FilePath, exclude :: Maybe (FilePath -> Boolean) } -> Aff (Array FilePath) +glob' = toAff2 A.glob' + +globDirent :: Array FilePath -> Aff (Array (Dirent DirentNameTypeString)) +globDirent = toAff1 A.globDirent + +globDirent' :: Array FilePath -> { cwd :: Maybe FilePath, exclude :: Maybe (Dirent DirentNameTypeString -> Boolean) } -> Aff (Array (Dirent DirentNameTypeString)) +globDirent' = toAff2 A.globDirent' + +-- | Change permissions on a symbolic link. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_lchmod_path_mode_callback) +-- | for details. +lchmod :: FilePath -> Perms -> Aff Unit +lchmod = toAff2 A.lchmod + +-- | Change ownership of a symbolic link. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_lchown_path_uid_gid_callback) +-- | for details. +lchown :: FilePath -> Int -> Int -> Aff Unit +lchown = toAff3 A.lchown + +-- | Change timestamps for a symbolic link. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_lutimes_path_atime_mtime_callback) +-- | for details. +lutimes :: FilePath -> DateTime -> DateTime -> Aff Unit +lutimes = toAff3 A.lutimes + +-- | Open a file as a blob. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_class_filehandle) +-- | for details. +-- openAsBlob :: FilePath -> Aff Blob +-- openAsBlob = toAff1 A.openAsBlob + +-- | Open a directory. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_opendir_path_options_callback) +-- | for details. +opendir :: FilePath -> Aff Dir +opendir = toAff1 A.opendir + +-- | Open a directory. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_opendir_path_options_callback) +-- | for details. +opendir' :: FilePath -> { bufferSize :: Int, recursive :: Boolean, encoding :: Encoding } -> Aff Dir +opendir' = toAff2 A.opendir' + +-- | Read from a file descriptor into a buffer array. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_readv_fd_buffers_position_callback) +-- | for details. +readv :: F.FileDescriptor -> Array Buffer -> Maybe F.FilePosition -> Aff (Tuple F.ByteCount (Array Buffer)) +readv = toAff3 A.readv + +-- | TODO: bigint, path Buffer Url +-- | Get file system statistics. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_statfs_path_callback) +-- | for details. +statfs :: FilePath -> Aff Stats +statfs = toAff1 A.statfs + +-- | TODO: implement +-- | Stop watching a file for changes. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_unwatchfile_filename_listener) +-- | for details. +-- unwatchFile :: FilePath -> Effect Unit +-- unwatchFile = toAff1 A.unwatchFile + +-- | Watch for changes in a file or directory. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_watch_filename_options_listener) +-- | for details. +-- watch :: FilePath -> (String -> Effect Unit) -> Effect Unit +-- watch = toAff2 A.watch + +-- | Watch for changes in a file and trigger a callback. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_watchfile_filename_options_listener) +-- | for details. +-- watchFile :: FilePath -> (Stats -> Stats -> Effect Unit) -> Effect Unit +-- watchFile = toAff2 A.watchFile + +-- | Write from an array of buffers to a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_writev_fd_buffers_position_callback) +-- | for details. +writev :: F.FileDescriptor -> Array Buffer -> Maybe F.FilePosition -> Aff (Tuple F.ByteCount (Array Buffer)) +writev = toAff3 A.writev diff --git a/src/Node/FS/Aff/Dir.purs b/src/Node/FS/Aff/Dir.purs new file mode 100644 index 0000000..f72ef2b --- /dev/null +++ b/src/Node/FS/Aff/Dir.purs @@ -0,0 +1,82 @@ +module Node.FS.Aff.Dir + ( read + , close + , entries + , entriesIterate + ) where + +import Prelude + +import Data.Array as Array +import Data.Either (Either(..)) +import Data.Maybe (Maybe(..)) +import Effect (Effect) +import Effect.Aff (Aff, effectCanceler, finally, makeAff, nonCanceler) +import Effect.Class (liftEffect) +import Effect.Exception (Error) +import Effect.Ref (Ref) +import Effect.Ref as Ref +import Node.FS.Dir (Callback2, Dir) +import Node.FS.Dir as Dir +import Node.FS.Dirent (Dirent, DirentNameTypeString) + +toAff + :: forall a + . (Callback2 a -> Effect Unit) + -> Aff a +toAff p = makeAff \k -> p k $> nonCanceler + +toAff1 + :: forall a x + . (x -> Callback2 a -> Effect Unit) + -> x + -> Aff a +toAff1 f a = toAff (f a) + +read :: Dir -> Aff (Maybe (Dirent DirentNameTypeString)) +read = toAff1 Dir.read + +close :: Dir -> Aff (Maybe Error) +close dir = makeAff \k -> do + Dir.close dir (k <<< Right) + pure nonCanceler + +entries :: Dir -> Aff (Array (Dirent DirentNameTypeString)) +entries dir = do + direntArrayRef <- liftEffect $ Ref.new [] + let + handleDirent :: Dirent DirentNameTypeString -> Effect Unit + handleDirent dirent = Ref.modify_ (flip Array.snoc dirent) direntArrayRef + entriesIterate dir handleDirent + liftEffect $ Ref.read direntArrayRef + +-- | Implementation of `dir[Symbol.asyncIterator]()` +-- | Documentation - https://nodejs.org/docs/latest/api/fs.html#dirsymbolasynciterator +-- | Implementation - https://github.com/nodejs/node/blob/b2161d3a137e5a2582c71c798e140d2ba8f7c1d4/lib/internal/fs/dir.js#L257 +-- | +-- | Nodejs version ignores errors on read, doesnt ignore errors on close. +-- | This purs version ignores error at close, doesnt ignore errors at read. +-- | But in reality - behavior should be the same (proved in tests). +-- | +-- | Possible errors: +-- | - if dir is closed already - `read` and `close` will throw "Directory handle was closed" +entriesIterate :: Dir -> ((Dirent DirentNameTypeString) -> Effect Unit) -> Aff Unit +entriesIterate dir handleDirent = finally (void $ close dir) $ makeAff \(k :: Either Error Unit -> Effect Unit) -> do + stopRef <- Ref.new false + go k stopRef + pure $ effectCanceler $ Ref.write true stopRef + where + go :: (Either Error Unit -> Effect Unit) -> Ref Boolean -> Effect Unit + go callback stopRef = do + stopped <- Ref.read stopRef + if stopped then do + callback $ Right unit + else Dir.read dir case _ of + Left error -> callback $ Left error + Right maybeDirent -> + case maybeDirent of + Nothing -> do + callback $ Right unit + Just dirent -> do + handleDirent dirent + go callback stopRef diff --git a/src/Node/FS/Async.js b/src/Node/FS/Async.js index cf935da..018a675 100644 --- a/src/Node/FS/Async.js +++ b/src/Node/FS/Async.js @@ -24,5 +24,25 @@ export { open as openImpl, read as readImpl, write as writeImpl, - close as closeImpl + close as closeImpl, + cp as cpImpl, + fchmod as fchmodImpl, + fchown as fchownImpl, + fdatasync as fdatasyncImpl, + fstat as fstatImpl, + fsync as fsyncImpl, + ftruncate as ftruncateImpl, + futimes as futimesImpl, + glob as globImpl, + lchmod as lchmodImpl, + lchown as lchownImpl, + lutimes as lutimesImpl, + // openAsBlob as openAsBlobImpl, + opendir as opendirImpl, + readv as readvImpl, + statfs as statfsImpl, + // unwatchFile as unwatchFileImpl, + // watch as watchImpl, + // watchFile as watchFileImpl, + writev as writevImpl } from "node:fs"; diff --git a/src/Node/FS/Async.purs b/src/Node/FS/Async.purs index cfab806..6d9615a 100644 --- a/src/Node/FS/Async.purs +++ b/src/Node/FS/Async.purs @@ -25,6 +25,13 @@ module Node.FS.Async , mkdir , mkdir' , readdir + , readdir' + , readdirBuffer + , readdirBuffer' + , readdirDirent + , readdirDirent' + , readdirDirentBuffer + , readdirDirentBuffer' , utimes , readFile , readTextFile @@ -38,6 +45,34 @@ module Node.FS.Async , fdWrite , fdAppend , fdClose + , cp + , cp' + , cpOptionsDefault + , CpOptions + , CpForce(..) + , fchmod + , fchown + , fdatasync + , fstat + , fsync + , ftruncate + , futimes + , glob + , glob' + , globDirent + , globDirent' + , lchmod + , lchown + , lutimes + -- , openAsBlob + , opendir' + , opendir + , readv + , statfs + -- , unwatchFile + -- , watch + -- , watchFile + , writev ) where import Prelude @@ -45,28 +80,45 @@ import Prelude import Data.DateTime (DateTime) import Data.DateTime.Instant (fromDateTime, unInstant) import Data.Either (Either(..)) +import Data.Function.Uncurried (Fn2, mkFn2) import Data.Int (round) import Data.Maybe (Maybe(..)) import Data.Nullable (Nullable, toMaybe, toNullable) import Data.Time.Duration (Milliseconds(..)) +import Data.Tuple (Tuple(..)) import Effect (Effect) import Effect.Exception (Error) -import Effect.Uncurried (EffectFn1, EffectFn2, EffectFn3, EffectFn4, EffectFn6, mkEffectFn1, mkEffectFn2, runEffectFn2, runEffectFn3, runEffectFn4, runEffectFn6) +import Effect.Uncurried (EffectFn1, EffectFn2, EffectFn3, EffectFn4, EffectFn6, mkEffectFn1, mkEffectFn2, mkEffectFn3, runEffectFn2, runEffectFn3, runEffectFn4, runEffectFn6) import Node.Buffer (Buffer, size) import Node.Encoding (Encoding(..), encodingToNode) import Node.FS (FileDescriptor, ByteCount, FilePosition, BufferLength, BufferOffset, FileMode, SymlinkType, symlinkTypeToNode) import Node.FS.Constants (FileFlags, fileFlagsToNode, AccessMode, CopyMode, defaultAccessMode, defaultCopyMode) +import Node.FS.Dir (Dir) +import Node.FS.Dirent (Dirent, DirentNameTypeBuffer, DirentNameTypeString) import Node.FS.Perms (Perms, permsToString, all, mkPerms) import Node.FS.Stats (Stats) import Node.Path (FilePath) +datetimeToUnixEpochTimeInSeconds :: DateTime -> Int +datetimeToUnixEpochTimeInSeconds date = ms (toEpochMilliseconds date) / 1000 + where + ms (Milliseconds n) = round n + toEpochMilliseconds = unInstant <<< fromDateTime + type JSCallback a = EffectFn2 (Nullable Error) a Unit +type JSCallback2 a b = EffectFn3 (Nullable Error) a b Unit + handleCallback :: forall a. Callback a -> JSCallback a handleCallback cb = mkEffectFn2 \err a -> case toMaybe err of Nothing -> cb (Right a) Just err' -> cb (Left err') +handleCallback2 :: forall a b. Callback (Tuple a b) -> JSCallback2 a b +handleCallback2 cb = mkEffectFn3 \err a b -> case toMaybe err of + Nothing -> cb (Right (Tuple a b)) + Just err' -> cb (Left err') + -- | Type synonym for callback functions. type Callback a = Either Error a -> Effect Unit @@ -109,7 +161,9 @@ foreign import unlinkImpl :: EffectFn2 FilePath (JSCallback Unit) Unit foreign import rmdirImpl :: EffectFn3 FilePath { maxRetries :: Int, retryDelay :: Int } (JSCallback Unit) Unit foreign import rmImpl :: EffectFn3 FilePath { force :: Boolean, maxRetries :: Int, recursive :: Boolean, retryDelay :: Int } (JSCallback Unit) Unit foreign import mkdirImpl :: EffectFn3 FilePath { recursive :: Boolean, mode :: String } (JSCallback Unit) Unit -foreign import readdirImpl :: EffectFn2 FilePath (JSCallback (Array FilePath)) Unit +-- if { withFileTypes: false, recursive: false } => ['Tidy'] +-- if { withFileTypes: false, recursive: true } => [ 'Tidy', 'Tidy/Codegen', 'Tidy/Codegen.purs', 'Tidy/Codegen/Class.purs', .. ] +foreign import readdirImpl :: forall filepathOrDirentOrBuffer stringOrBuffer. EffectFn3 FilePath { encoding :: stringOrBuffer, recursive :: Boolean, withFileTypes :: Boolean } (JSCallback (Array filepathOrDirentOrBuffer)) Unit foreign import utimesImpl :: EffectFn4 FilePath Int Int (JSCallback Unit) Unit foreign import readFileImpl :: forall a opts. EffectFn3 FilePath { | opts } (JSCallback a) Unit foreign import writeFileImpl :: forall a opts. EffectFn4 FilePath a { | opts } (JSCallback Unit) Unit @@ -118,6 +172,26 @@ foreign import openImpl :: EffectFn4 FilePath String (Nullable FileMode) (JSCall foreign import readImpl :: EffectFn6 FileDescriptor Buffer BufferOffset BufferLength (Nullable FilePosition) (JSCallback ByteCount) Unit foreign import writeImpl :: EffectFn6 FileDescriptor Buffer BufferOffset BufferLength (Nullable FilePosition) (JSCallback ByteCount) Unit foreign import closeImpl :: EffectFn2 FileDescriptor (JSCallback Unit) Unit +foreign import cpImpl :: EffectFn4 FilePath FilePath CpOptionsInternal (JSCallback Unit) Unit +foreign import fchmodImpl :: EffectFn3 FileDescriptor String (JSCallback Unit) Unit +foreign import fchownImpl :: EffectFn4 FileDescriptor Int Int (JSCallback Unit) Unit +foreign import fdatasyncImpl :: EffectFn2 FileDescriptor (JSCallback Unit) Unit +foreign import fstatImpl :: EffectFn2 FileDescriptor (JSCallback Stats) Unit +foreign import fsyncImpl :: EffectFn2 FileDescriptor (JSCallback Unit) Unit +foreign import ftruncateImpl :: EffectFn3 FileDescriptor Int (JSCallback Unit) Unit +foreign import futimesImpl :: EffectFn4 FileDescriptor Int Int (JSCallback Unit) Unit +foreign import globImpl :: forall filepathOrDirent. EffectFn3 (Array String) { cwd :: Nullable FilePath, exclude :: Nullable (filepathOrDirent -> Boolean), withFileTypes :: Boolean } (JSCallback (Array filepathOrDirent)) Unit +foreign import lchmodImpl :: EffectFn3 FilePath String (JSCallback Unit) Unit +foreign import lchownImpl :: EffectFn4 FilePath Int Int (JSCallback Unit) Unit +foreign import lutimesImpl :: EffectFn4 FilePath Int Int (JSCallback Unit) Unit +-- foreign import openAsBlobImpl :: EffectFn2 FilePath (Promise Blob) Unit +foreign import opendirImpl :: EffectFn3 FilePath { bufferSize :: Int, recursive :: Boolean, encoding :: String } (JSCallback Dir) Unit +foreign import readvImpl :: EffectFn4 FileDescriptor (Array Buffer) (Nullable FilePosition) (JSCallback2 ByteCount (Array Buffer)) Unit +foreign import statfsImpl :: EffectFn2 FilePath (JSCallback Stats) Unit +-- foreign import unwatchFileImpl :: EffectFn1 FilePath Unit +-- foreign import watchImpl :: EffectFn2 FilePath (EffectFn1 String Unit) Unit +-- foreign import watchFileImpl :: EffectFn2 FilePath (EffectFn2 Stats Stats Unit) Unit +foreign import writevImpl :: EffectFn4 FileDescriptor (Array Buffer) (Nullable FilePosition) (JSCallback2 ByteCount (Array Buffer)) Unit -- | Renames a file. rename @@ -266,7 +340,60 @@ readdir :: FilePath -> Callback (Array FilePath) -> Effect Unit -readdir file cb = runEffectFn2 readdirImpl file (handleCallback cb) +readdir file = readdir' file { recursive: false, encoding: UTF8 } + +-- | Reads the contents of a directory. +readdir' + :: FilePath + -> { recursive :: Boolean, encoding :: Encoding } + -> Callback (Array FilePath) + -> Effect Unit +readdir' file { recursive, encoding } cb = runEffectFn3 readdirImpl file { recursive, encoding: encodingToNode encoding, withFileTypes: false } (handleCallback cb) + +-- | Reads the contents of a directory. +readdirBuffer + :: FilePath + -> Callback (Array Buffer) + -> Effect Unit +readdirBuffer file = readdirBuffer' file { recursive: false } + +-- | Reads the contents of a directory. +readdirBuffer' + :: FilePath + -> { recursive :: Boolean } + -> Callback (Array Buffer) + -> Effect Unit +readdirBuffer' file { recursive } cb = runEffectFn3 readdirImpl file { recursive, encoding: "buffer", withFileTypes: false } (handleCallback cb) + +-- | Reads the contents of a directory. +readdirDirent + :: FilePath + -> Callback (Array (Dirent DirentNameTypeString)) + -> Effect Unit +readdirDirent file = readdirDirent' file { recursive: false, encoding: UTF8 } + +-- | Reads the contents of a directory. +readdirDirent' + :: FilePath + -> { recursive :: Boolean, encoding :: Encoding } + -> Callback (Array (Dirent DirentNameTypeString)) + -> Effect Unit +readdirDirent' file { recursive, encoding } cb = runEffectFn3 readdirImpl file { recursive, encoding: encodingToNode encoding, withFileTypes: true } (handleCallback cb) + +-- | Reads the contents of a directory. +readdirDirentBuffer + :: FilePath + -> Callback (Array (Dirent DirentNameTypeBuffer)) + -> Effect Unit +readdirDirentBuffer file = readdirDirentBuffer' file { recursive: false } + +-- | Reads the contents of a directory. +readdirDirentBuffer' + :: FilePath + -> { recursive :: Boolean } + -> Callback (Array (Dirent DirentNameTypeBuffer)) + -> Effect Unit +readdirDirentBuffer' file { recursive } cb = runEffectFn3 readdirImpl file { recursive, encoding: "buffer", withFileTypes: true } (handleCallback cb) -- | Sets the accessed and modified times for the specified file. utimes @@ -275,11 +402,7 @@ utimes -> DateTime -> Callback Unit -> Effect Unit -utimes file atime mtime cb = runEffectFn4 utimesImpl file (fromDate atime) (fromDate mtime) (handleCallback cb) - where - fromDate date = ms (toEpochMilliseconds date) / 1000 - ms (Milliseconds n) = round n - toEpochMilliseconds = unInstant <<< fromDateTime +utimes file atime mtime cb = runEffectFn4 utimesImpl file (datetimeToUnixEpochTimeInSeconds atime) (datetimeToUnixEpochTimeInSeconds mtime) (handleCallback cb) -- | Reads the entire contents of a file returning the result as a raw buffer. readFile @@ -393,3 +516,182 @@ fdClose -> Callback Unit -> Effect Unit fdClose fd cb = runEffectFn2 closeImpl fd (handleCallback cb) + +data CpForce = CpForce_False | CpForce_TrueWithoutErrorOnExit | CpForce_TrueWithErrorOnExit + +type CpOptionsInternal = + { dereference :: Boolean + , errorOnExist :: Boolean + , filter :: Nullable (Fn2 FilePath FilePath Boolean) + , force :: Boolean + , mode :: FileMode + , preserveTimestamps :: Boolean + , recursive :: Boolean + , verbatimSymlinks :: Boolean + } + +type CpOptions = + { dereference :: Boolean -- Whether to dereference symlinks + , filter :: Maybe (FilePath -> FilePath -> Boolean) + , force :: CpForce + , mode :: FileMode -- Modifiers for copy operation + , preserveTimestamps :: Boolean -- Preserve timestamps from source + , recursive :: Boolean -- Copy directories recursively + , verbatimSymlinks :: Boolean -- Skip path resolution for symlinks + } + +cpOptionsToCpOptionsInternal :: CpOptions -> CpOptionsInternal +cpOptionsToCpOptionsInternal opts = + { dereference: opts.dereference + , errorOnExist: case opts.force of + CpForce_TrueWithErrorOnExit -> true + _ -> false + , filter: toNullable $ map mkFn2 (opts.filter) + , force: case opts.force of + CpForce_False -> false + _ -> true + , mode: opts.mode + , preserveTimestamps: opts.preserveTimestamps + , recursive: opts.recursive + , verbatimSymlinks: opts.verbatimSymlinks + } + +cpOptionsDefault :: CpOptions +cpOptionsDefault = + { dereference: false + , filter: Nothing + , force: CpForce_TrueWithoutErrorOnExit + , mode: 0 + , preserveTimestamps: false + , recursive: false + , verbatimSymlinks: false + } + +-- | Copy a file asynchronously. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fspromises_copyfile_src_dest_mode) +-- | for details. +cp :: FilePath -> FilePath -> Callback Unit -> Effect Unit +cp src dest = cp' src dest cpOptionsDefault + +cp' :: FilePath -> FilePath -> CpOptions -> Callback Unit -> Effect Unit +cp' src dest opts cb = runEffectFn4 cpImpl src dest (cpOptionsToCpOptionsInternal opts) (handleCallback cb) + +-- | Change permissions on a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fchmod_fd_mode_callback) +-- | for details. +fchmod :: FileDescriptor -> Perms -> Callback Unit -> Effect Unit +fchmod fd perms cb = runEffectFn3 fchmodImpl fd (permsToString perms) (handleCallback cb) + +-- | Change ownership of a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fchown_fd_uid_gid_callback) +-- | for details. +fchown :: FileDescriptor -> Int -> Int -> Callback Unit -> Effect Unit +fchown fd uid gid cb = runEffectFn4 fchownImpl fd uid gid (handleCallback cb) + +-- | Synchronize a file's in-core state with storage. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fdatasync_fd_callback) +-- | for details. +fdatasync :: FileDescriptor -> Callback Unit -> Effect Unit +fdatasync fd cb = runEffectFn2 fdatasyncImpl fd (handleCallback cb) + +-- | Get file status information. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fstat_fd_callback) +-- | for details. +fstat :: FileDescriptor -> Callback Stats -> Effect Unit +fstat fd cb = runEffectFn2 fstatImpl fd (handleCallback cb) + +-- | Flushes a file descriptor to disk. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fsync_fd_callback) +-- | for details. +fsync :: FileDescriptor -> Callback Unit -> Effect Unit +fsync fd cb = runEffectFn2 fsyncImpl fd (handleCallback cb) + +-- | Truncate a file to a specified length. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_ftruncate_fd_len_callback) +-- | for details. +ftruncate :: FileDescriptor -> Int -> Callback Unit -> Effect Unit +ftruncate fd len cb = runEffectFn3 ftruncateImpl fd len (handleCallback cb) + +-- | Change file timestamps for a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_futimes_fd_atime_mtime_callback) +-- | for details. +futimes + :: FilePath + -> DateTime + -> DateTime + -> Callback Unit + -> Effect Unit +futimes file atime mtime cb = runEffectFn4 lutimesImpl file (datetimeToUnixEpochTimeInSeconds atime) (datetimeToUnixEpochTimeInSeconds mtime) (handleCallback cb) + +-- | Perform pattern matching in file paths. See the [Node Documentation](https://nodejs.org/api/glob.html#globglob_pattern_options_callback) +-- | for details. +glob :: Array FilePath -> Callback (Array FilePath) -> Effect Unit +glob pattern = glob' pattern { cwd: Nothing, exclude: Nothing } + +glob' :: Array FilePath -> { cwd :: Maybe FilePath, exclude :: Maybe (FilePath -> Boolean) } -> Callback (Array FilePath) -> Effect Unit +glob' pattern { cwd, exclude } cb = runEffectFn3 globImpl pattern { cwd: toNullable cwd, exclude: toNullable exclude, withFileTypes: false } (handleCallback cb) + +globDirent :: Array FilePath -> Callback (Array (Dirent DirentNameTypeString)) -> Effect Unit +globDirent pattern = globDirent' pattern { cwd: Nothing, exclude: Nothing } + +globDirent' :: Array FilePath -> { cwd :: Maybe FilePath, exclude :: Maybe (Dirent DirentNameTypeString -> Boolean) } -> Callback (Array (Dirent DirentNameTypeString)) -> Effect Unit +globDirent' pattern { cwd, exclude } cb = runEffectFn3 globImpl pattern { cwd: toNullable cwd, exclude: toNullable exclude, withFileTypes: true } (handleCallback cb) + +-- | Change permissions on a symbolic link. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_lchmod_path_mode_callback) +-- | for details. +lchmod :: FilePath -> Perms -> Callback Unit -> Effect Unit +lchmod path perms cb = runEffectFn3 lchmodImpl path (permsToString perms) (handleCallback cb) + +-- | Change ownership of a symbolic link. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_lchown_path_uid_gid_callback) +-- | for details. +lchown :: FilePath -> Int -> Int -> Callback Unit -> Effect Unit +lchown path uid gid cb = runEffectFn4 lchownImpl path uid gid (handleCallback cb) + +-- | Change timestamps for a symbolic link. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_lutimes_path_atime_mtime_callback) +-- | for details. +lutimes + :: FilePath + -> DateTime + -> DateTime + -> Callback Unit + -> Effect Unit +lutimes file atime mtime cb = runEffectFn4 lutimesImpl file (datetimeToUnixEpochTimeInSeconds atime) (datetimeToUnixEpochTimeInSeconds mtime) (handleCallback cb) + +-- | TODO: path - Buffer Url, returns Promise +-- | Open a file as a blob. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_class_filehandle) +-- | for details. +-- openAsBlob :: FilePath -> Promise Blob -> Effect Unit +-- openAsBlob path cb = runEffectFn2 openAsBlobImpl path (handleCallback cb) + +-- | Open a directory. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_opendir_path_options_callback) +-- | for details. +opendir' :: FilePath -> { encoding :: Encoding, bufferSize :: Int, recursive :: Boolean } -> Callback Dir -> Effect Unit +opendir' path { encoding, bufferSize, recursive } cb = runEffectFn3 opendirImpl path { encoding: encodingToNode encoding, bufferSize, recursive } (handleCallback cb) + +-- | Open a directory. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_opendir_path_options_callback) +-- | for details. +-- | NOTE: encoding: 'buffer' is not supported, will throw error "TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received an instance of Buffer" +opendir :: FilePath -> Callback Dir -> Effect Unit +opendir path = opendir' path { bufferSize: 32, recursive: false, encoding: UTF8 } + +-- | Read from a file descriptor into a buffer array. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_readv_fd_buffers_position_callback) +-- | for details. +readv :: FileDescriptor -> Array Buffer -> Maybe FilePosition -> Callback (Tuple ByteCount (Array Buffer)) -> Effect Unit +readv fd buffers position cb = runEffectFn4 readvImpl fd buffers (toNullable position) (handleCallback2 cb) + +-- | Get file system statistics. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_statfs_path_callback) +-- | for details. +statfs :: FilePath -> Callback Stats -> Effect Unit +statfs path cb = runEffectFn2 statfsImpl path (handleCallback cb) + +-- -- | Stop watching a file for changes. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_unwatchfile_filename_listener) +-- -- | for details. +-- unwatchFile :: FilePath -> Effect Unit +-- unwatchFile path = runEffectFn1 unwatchFileImpl path +-- +-- -- | Watch for changes in a file or directory. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_watch_filename_options_listener) +-- -- | for details. +-- watch :: FilePath -> (String -> Effect Unit) -> Effect Unit +-- watch path cb = runEffectFn2 watchImpl path (mkEffectFn1 cb) +-- +-- -- | Watch for changes in a file and trigger a callback. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_watchfile_filename_options_listener) +-- -- | for details. +-- watchFile :: FilePath -> (Stats -> Stats -> Effect Unit) -> Effect Unit +-- watchFile path cb = runEffectFn2 watchFileImpl path (mkEffectFn2 cb) + +-- | Write from an array of buffers to a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_writev_fd_buffers_position_callback) +-- | for details. +writev :: FileDescriptor -> Array Buffer -> Maybe FilePosition -> Callback (Tuple ByteCount (Array Buffer)) -> Effect Unit +writev fd buffers position cb = runEffectFn4 writevImpl fd buffers (toNullable position) (handleCallback2 cb) diff --git a/src/Node/FS/Dir.js b/src/Node/FS/Dir.js new file mode 100644 index 0000000..38e76c0 --- /dev/null +++ b/src/Node/FS/Dir.js @@ -0,0 +1,5 @@ +export const closeImpl = (dir, callback) => dir.close(callback); +export const closeSyncImpl = (dir) => dir.close(); +export const path = (dir) => dir.path; +export const readImpl = (dir, callback) => dir.read(callback); +export const readSyncImpl = (dir) => dir.read(); diff --git a/src/Node/FS/Dir.purs b/src/Node/FS/Dir.purs new file mode 100644 index 0000000..1ccd30b --- /dev/null +++ b/src/Node/FS/Dir.purs @@ -0,0 +1,49 @@ +module Node.FS.Dir where + +import Prelude + +import Data.Either (Either(..)) +import Data.Maybe (Maybe(..)) +import Data.Nullable (Nullable, toMaybe) +import Effect (Effect) +import Effect.Exception (Error) +import Effect.Uncurried (EffectFn1, EffectFn2, mkEffectFn1, mkEffectFn2, runEffectFn1, runEffectFn2) +import Node.FS.Dirent (Dirent, DirentNameTypeString) +import Node.Path (FilePath) + +type JSCallback1 = EffectFn1 (Nullable Error) Unit +type JSCallback2 a = EffectFn2 (Nullable Error) a Unit +type Callback1 = Maybe Error -> Effect Unit +type Callback2 a = Either Error a -> Effect Unit + +handleCallback2 :: forall a. Callback2 a -> JSCallback2 a +handleCallback2 cb = mkEffectFn2 \err a -> case toMaybe err of + Nothing -> cb (Right a) + Just err' -> cb (Left err') + +-- Foreign imports for the Dir class +foreign import data Dir :: Type + +foreign import closeImpl :: EffectFn2 Dir JSCallback1 Unit +foreign import closeSyncImpl :: EffectFn1 Dir Unit +foreign import readImpl :: EffectFn2 Dir (JSCallback2 (Nullable (Dirent DirentNameTypeString))) Unit +foreign import readSyncImpl :: EffectFn1 Dir (Nullable (Dirent DirentNameTypeString)) + +-- | Get the path of this directory as was provided to fs.opendir(), fs.opendirSync(), or fsPromises.opendir(). +foreign import path :: Dir -> FilePath + +-- | Asynchronously close the directory's underlying resource handle. +close :: Dir -> Callback1 -> Effect Unit +close dir callback = runEffectFn2 closeImpl dir (mkEffectFn1 $ (callback <<< toMaybe)) + +-- | Synchronously close the directory's underlying resource handle. +closeSync :: Dir -> Effect Unit +closeSync = runEffectFn1 closeSyncImpl + +-- | Asynchronously read the next directory entry. +read :: Dir -> (Either Error (Maybe (Dirent DirentNameTypeString)) -> Effect Unit) -> Effect Unit +read dir callback = runEffectFn2 readImpl dir (handleCallback2 (callback <<< map toMaybe)) + +-- | Synchronously read the next directory entry. +readSync :: Dir -> Effect (Maybe (Dirent DirentNameTypeString)) +readSync dir = toMaybe <$> runEffectFn1 readSyncImpl dir diff --git a/src/Node/FS/Dirent.js b/src/Node/FS/Dirent.js new file mode 100644 index 0000000..d8799eb --- /dev/null +++ b/src/Node/FS/Dirent.js @@ -0,0 +1,11 @@ +export { inspect as showDirentObj } from "util"; + +export const isBlockDevice = dirent => dirent.isBlockDevice(); +export const isCharacterDevice = dirent => dirent.isCharacterDevice(); +export const isDirectory = dirent => dirent.isDirectory(); +export const isFIFO = dirent => dirent.isFIFO(); +export const isFile = dirent => dirent.isFile(); +export const isSocket = dirent => dirent.isSocket(); +export const isSymbolicLink = dirent => dirent.isSymbolicLink(); +export const nameImpl = dirent => dirent.name; +export const parentPath = dirent => dirent.parentPath; diff --git a/src/Node/FS/Dirent.purs b/src/Node/FS/Dirent.purs new file mode 100644 index 0000000..a11ba98 --- /dev/null +++ b/src/Node/FS/Dirent.purs @@ -0,0 +1,58 @@ +module Node.FS.Dirent where + +import Prelude + +import Node.Buffer (Buffer) +import Node.Path (FilePath) +import Unsafe.Coerce (unsafeCoerce) + +data DirentNameType + +foreign import data DirentNameTypeString :: DirentNameType +foreign import data DirentNameTypeBuffer :: DirentNameType + +foreign import data Dirent :: DirentNameType -> Type + +-- | Check if the Dirent object describes a block device. +foreign import isBlockDevice :: forall direntnametype. Dirent direntnametype -> Boolean + +-- | Check if the Dirent object describes a character device. +foreign import isCharacterDevice :: forall direntnametype. Dirent direntnametype -> Boolean + +-- | Check if the Dirent object describes a directory. +foreign import isDirectory :: forall direntnametype. Dirent direntnametype -> Boolean + +-- | Check if the Dirent object describes a FIFO pipe. +foreign import isFIFO :: forall direntnametype. Dirent direntnametype -> Boolean + +-- | Check if the Dirent object describes a regular file. +foreign import isFile :: forall direntnametype. Dirent direntnametype -> Boolean + +-- | Check if the Dirent object describes a socket. +foreign import isSocket :: forall direntnametype. Dirent direntnametype -> Boolean + +-- | Check if the Dirent object describes a symbolic link. +foreign import isSymbolicLink :: forall direntnametype. Dirent direntnametype -> Boolean + +foreign import nameImpl :: forall direntnametype nametype. Dirent direntnametype -> nametype + +class IsDirentNameForDirent direntnametype stringOrBuffer | direntnametype -> stringOrBuffer where + -- | The file name that this object refers to. The type of this value is determined by the options.encoding passed to fs.readdir() or fs.readdirSync(). + name :: Dirent direntnametype -> stringOrBuffer + +instance IsDirentNameForDirent DirentNameTypeString String where + name :: Dirent DirentNameTypeString -> String + name = unsafeCoerce nameImpl +else instance IsDirentNameForDirent DirentNameTypeBuffer Buffer where + name :: Dirent DirentNameTypeBuffer -> Buffer + name = unsafeCoerce nameImpl + +-- | Get the parent directory path of the file this Dirent object refers to. +-- | Added in: v21.4.0, v20.12.0, v18.20.0 +-- | TODO: support for old node version? `Nullable FilePath`? +foreign import parentPath :: forall direntnametype. Dirent direntnametype -> FilePath + +foreign import showDirentObj :: forall direntnametype. Dirent direntnametype -> String + +instance Show (Dirent direntnametype) where + show s = "Dirent " <> showDirentObj s diff --git a/src/Node/FS/Sync.js b/src/Node/FS/Sync.js index acddc23..166b656 100644 --- a/src/Node/FS/Sync.js +++ b/src/Node/FS/Sync.js @@ -1,4 +1,4 @@ -export { +export { accessSync as accessImpl, copyFileSync as copyFileImpl, mkdtempSync as mkdtempImpl, @@ -26,5 +26,21 @@ export { readSync as readSyncImpl, writeSync as writeSyncImpl, fsyncSync as fsyncSyncImpl, - closeSync as closeSyncImpl + closeSync as closeSyncImpl, + // TODO: implement + // cpSync as cpSyncImpl, + // fchmodSync as fchmodSyncImpl, + // fchownSync as fchownSyncImpl, + // fdatasyncSync as fdatasyncSyncImpl, + // fstatSync as fstatSyncImpl, + // ftruncateSync as ftruncateSyncImpl, + // futimesSync as futimesSyncImpl, + // globSync as globSyncImpl, + // lchmodSync as lchmodSyncImpl, + // lchownSync as lchownSyncImpl, + // lutimesSync as lutimesSyncImpl, + // opendirSync as opendirSyncImpl, + // readvSync as readvSyncImpl, + // statfsSync as statfsSyncImpl, + // writevSync as writevSyncImpl } from "node:fs"; diff --git a/test/Main.purs b/test/Main.purs index 95f1cea..c2e36e1 100644 --- a/test/Main.purs +++ b/test/Main.purs @@ -7,6 +7,7 @@ import Test as Test import Test.Streams as Streams import TestAff as TestAff import TestAsync as TestAsync +import TestDirEntries as TestDirEntries main :: Effect Unit main = do @@ -14,3 +15,4 @@ main = do TestAsync.main Streams.main TestAff.main + TestDirEntries.main diff --git a/test/Test.purs b/test/Test.purs index 16a591a..1d1d2aa 100644 --- a/test/Test.purs +++ b/test/Test.purs @@ -150,12 +150,12 @@ main = do let fdFile = fp [ "tmp", "FD.json" ] fd0 <- S.fdOpen fdFile W (Just 420) buf0 <- Buffer.fromString "[ 42 ]" UTF8 - bytes0 <- S.fdAppend fd0 buf0 + _bytes0 <- S.fdAppend fd0 buf0 S.fdFlush fd0 S.fdClose fd0 fd1 <- S.fdOpen fdFile R Nothing buf1 <- Buffer.create =<< Buffer.size buf0 - bytes1 <- S.fdNext fd1 buf1 + _bytes2 <- S.fdNext fd1 buf1 S.fdClose fd1 log "statSync on a non-existing file should be catchable" @@ -182,7 +182,7 @@ main = do Nothing -> throw $ "`access \"" <> readableFixturePath <> "\" W_OK` should produce error" log "copy tests" - let outerTmpDir = "./test/node-fs-tests" + let outerTmpDir = "./tmp/test/node-fs-tests" S.mkdir' outerTmpDir { recursive: true, mode: permsAll } tempDir <- S.mkdtemp outerTmpDir S.mkdir' tempDir { recursive: true, mode: permsAll } diff --git a/test/TestDirEntries.purs b/test/TestDirEntries.purs new file mode 100644 index 0000000..5f4f177 --- /dev/null +++ b/test/TestDirEntries.purs @@ -0,0 +1,111 @@ +module TestDirEntries where + +import Prelude + +import Data.Either (Either) +import Data.Maybe (Maybe) +import Data.String as String +import Effect (Effect) +import Effect.Aff (Aff, launchAff_, try) +import Effect.Class (liftEffect) +import Effect.Console (log) +import Effect.Exception (Error) +import Node.Encoding (Encoding(..)) +import Node.FS.Aff as A +import Node.FS.Aff.Dir (close, entries, read) +import Node.FS.Dirent (Dirent, DirentNameTypeString) +import Node.FS.Perms (permsAll) +import Node.Path (FilePath) +import Node.Path as Path +import Test.Assert (assertEqual) + +outerTmpDir :: FilePath +outerTmpDir = "./tmp/dir-entries-test" + +prepare :: Aff Unit +prepare = do + A.rm' outerTmpDir { force: true, maxRetries: 100, recursive: true, retryDelay: 1000 } + A.mkdir' outerTmpDir { recursive: true, mode: permsAll } + A.writeTextFile UTF8 (Path.concat [ outerTmpDir, "1.txt" ]) "1" + A.writeTextFile UTF8 (Path.concat [ outerTmpDir, "2.txt" ]) "2" + A.mkdir $ Path.concat [ outerTmpDir, "dir1" ] + A.writeTextFile UTF8 (Path.concat [ outerTmpDir, "dir1", "3.txt" ]) "3" + A.writeTextFile UTF8 (Path.concat [ outerTmpDir, "dir1", "4.txt" ]) "4" + +test1 :: Aff Unit +test1 = do + dir <- A.opendir' outerTmpDir { bufferSize: 32, recursive: true, encoding: UTF8 } + files' <- entries dir + liftEffect $ assertEqual + { actual: show files' + , expected: + """[Dirent Dirent { + name: 'dir1', + parentPath: './tmp/dir-entries-test', + path: './tmp/dir-entries-test', + [Symbol(type)]: 2 +},Dirent Dirent { + name: '1.txt', + parentPath: './tmp/dir-entries-test', + path: './tmp/dir-entries-test', + [Symbol(type)]: 1 +},Dirent Dirent { + name: '2.txt', + parentPath: './tmp/dir-entries-test', + path: './tmp/dir-entries-test', + [Symbol(type)]: 1 +},Dirent Dirent { + name: '3.txt', + parentPath: 'tmp/dir-entries-test/dir1', + path: 'tmp/dir-entries-test/dir1', + [Symbol(type)]: 1 +},Dirent Dirent { + name: '4.txt', + parentPath: 'tmp/dir-entries-test/dir1', + path: 'tmp/dir-entries-test/dir1', + [Symbol(type)]: 1 +}]""" + } + liftEffect $ log $ show files' + try (entries dir) >>= \(eitherFile :: Either Error (Array (Dirent DirentNameTypeString))) -> liftEffect $ assertEqual + { actual: String.take 74 $ show eitherFile + , expected: "(Left Error [ERR_DIR_CLOSED]: Directory handle was closed\n at #readImpl" + } + +test2 :: Aff Unit +test2 = do + dir <- A.opendir' outerTmpDir { bufferSize: 32, recursive: false, encoding: UTF8 } + read dir >>= \file -> liftEffect $ assertEqual + { actual: show file + , expected: "(Just Dirent Dirent {\n name: 'dir1',\n parentPath: './tmp/dir-entries-test',\n path: './tmp/dir-entries-test',\n [Symbol(type)]: 2\n})" + } + read dir >>= \file -> liftEffect $ assertEqual + { actual: show file + , expected: "(Just Dirent Dirent {\n name: '1.txt',\n parentPath: './tmp/dir-entries-test',\n path: './tmp/dir-entries-test',\n [Symbol(type)]: 1\n})" + } + read dir >>= \file -> liftEffect $ assertEqual + { actual: show file + , expected: "(Just Dirent Dirent {\n name: '2.txt',\n parentPath: './tmp/dir-entries-test',\n path: './tmp/dir-entries-test',\n [Symbol(type)]: 1\n})" + } + read dir >>= \file -> liftEffect $ assertEqual + { actual: show file + , expected: "Nothing" + } + close dir >>= \file -> liftEffect $ assertEqual + { actual: show file + , expected: "Nothing" + } + close dir >>= \maybeError -> liftEffect $ assertEqual + { actual: String.take 74 $ show maybeError + , expected: "(Just Error [ERR_DIR_CLOSED]: Directory handle was closed\n at Dir.close" + } + try (read dir) >>= \(eitherFile :: Either Error (Maybe (Dirent DirentNameTypeString))) -> liftEffect $ assertEqual + { actual: String.take 74 $ show eitherFile + , expected: "(Left Error [ERR_DIR_CLOSED]: Directory handle was closed\n at #readImpl" + } + +main :: Effect Unit +main = launchAff_ do + prepare + test1 + test2 From 86c67eb477c2bb756c63f435372a24db626b5a1f Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Fri, 4 Oct 2024 18:59:14 +0700 Subject: [PATCH 02/32] feat: use FilePath instead of String where needed, AutodetectLink --- src/Node/FS.purs | 14 +++++++++----- src/Node/FS/Aff.purs | 12 ++++++------ src/Node/FS/Async.purs | 10 +++++----- src/Node/FS/Sync.purs | 2 +- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/Node/FS.purs b/src/Node/FS.purs index 2bb3c56..9db38cb 100644 --- a/src/Node/FS.purs +++ b/src/Node/FS.purs @@ -12,6 +12,8 @@ module Node.FS import Prelude +import Data.Nullable (Nullable) +import Data.Nullable as Nullable import Node.FS.Constants (FileFlags(..), fileFlagsToNode) as Exports foreign import data FileDescriptor :: Type @@ -23,19 +25,21 @@ type BufferOffset = Int type ByteCount = Int -- | Symlink varieties. -data SymlinkType = FileLink | DirLink | JunctionLink +data SymlinkType = FileLink | DirLink | JunctionLink | AutodetectLink -- | Convert a `SymlinkType` to a `String` in the format expected by the -- | Node.js filesystem API. -symlinkTypeToNode :: SymlinkType -> String +symlinkTypeToNode :: SymlinkType -> Nullable String symlinkTypeToNode ty = case ty of - FileLink -> "file" - DirLink -> "dir" - JunctionLink -> "junction" + FileLink -> Nullable.notNull "file" + DirLink -> Nullable.notNull "dir" + JunctionLink -> Nullable.notNull "junction" + AutodetectLink -> Nullable.null instance showSymlinkType :: Show SymlinkType where show FileLink = "FileLink" show DirLink = "DirLink" show JunctionLink = "JunctionLink" + show AutodetectLink = "AutodetectLink" derive instance eqSymlinkType :: Eq SymlinkType diff --git a/src/Node/FS/Aff.purs b/src/Node/FS/Aff.purs index 583cd51..8417ce9 100644 --- a/src/Node/FS/Aff.purs +++ b/src/Node/FS/Aff.purs @@ -156,26 +156,26 @@ toAff5 f a b c d e = toAff (f a b c d e) -- -> Aff a -- toAff6 f a b c d e t = toAff (f a b c d e t) -access :: String -> Aff (Maybe Error) +access :: FilePath -> Aff (Maybe Error) access path = makeAff \k -> do A.access path (k <<< Right) pure nonCanceler -access' :: String -> AccessMode -> Aff (Maybe Error) +access' :: FilePath -> AccessMode -> Aff (Maybe Error) access' path mode = makeAff \k -> do A.access' path mode (k <<< Right) pure nonCanceler -copyFile :: String -> String -> Aff Unit +copyFile :: FilePath -> FilePath -> Aff Unit copyFile = toAff2 A.copyFile -copyFile' :: String -> String -> CopyMode -> Aff Unit +copyFile' :: FilePath -> FilePath -> CopyMode -> Aff Unit copyFile' = toAff3 A.copyFile' -mkdtemp :: String -> Aff String +mkdtemp :: FilePath -> Aff FilePath mkdtemp = toAff1 A.mkdtemp -mkdtemp' :: String -> Encoding -> Aff String +mkdtemp' :: FilePath -> Encoding -> Aff FilePath mkdtemp' = toAff2 A.mkdtemp' -- | diff --git a/src/Node/FS/Async.purs b/src/Node/FS/Async.purs index 6d9615a..d725037 100644 --- a/src/Node/FS/Async.purs +++ b/src/Node/FS/Async.purs @@ -139,13 +139,13 @@ copyFile' src dest mode cb = runEffectFn4 copyFileImpl src dest mode (handleCall foreign import copyFileImpl :: EffectFn4 FilePath FilePath CopyMode (JSCallback Unit) Unit -mkdtemp :: String -> Callback String -> Effect Unit +mkdtemp :: FilePath -> Callback FilePath -> Effect Unit mkdtemp prefix = mkdtemp' prefix UTF8 -mkdtemp' :: String -> Encoding -> Callback String -> Effect Unit +mkdtemp' :: FilePath -> Encoding -> Callback FilePath -> Effect Unit mkdtemp' prefix encoding cb = runEffectFn3 mkdtempImpl prefix (encodingToNode encoding) (handleCallback cb) -foreign import mkdtempImpl :: EffectFn3 FilePath String (JSCallback String) Unit +foreign import mkdtempImpl :: EffectFn3 FilePath FilePath (JSCallback FilePath) Unit foreign import renameImpl :: EffectFn3 FilePath FilePath (JSCallback Unit) Unit foreign import truncateImpl :: EffectFn3 FilePath Int (JSCallback Unit) Unit @@ -154,7 +154,7 @@ foreign import chmodImpl :: EffectFn3 FilePath String (JSCallback Unit) Unit foreign import statImpl :: EffectFn2 FilePath (JSCallback Stats) Unit foreign import lstatImpl :: EffectFn2 FilePath (JSCallback Stats) Unit foreign import linkImpl :: EffectFn3 FilePath FilePath (JSCallback Unit) Unit -foreign import symlinkImpl :: EffectFn4 FilePath FilePath String (JSCallback Unit) Unit +foreign import symlinkImpl :: EffectFn4 FilePath FilePath (Nullable String) (JSCallback Unit) Unit foreign import readlinkImpl :: EffectFn2 FilePath (JSCallback FilePath) Unit foreign import realpathImpl :: forall cache. EffectFn3 FilePath { | cache } (JSCallback FilePath) Unit foreign import unlinkImpl :: EffectFn2 FilePath (JSCallback Unit) Unit @@ -180,7 +180,7 @@ foreign import fstatImpl :: EffectFn2 FileDescriptor (JSCallback Stats) Unit foreign import fsyncImpl :: EffectFn2 FileDescriptor (JSCallback Unit) Unit foreign import ftruncateImpl :: EffectFn3 FileDescriptor Int (JSCallback Unit) Unit foreign import futimesImpl :: EffectFn4 FileDescriptor Int Int (JSCallback Unit) Unit -foreign import globImpl :: forall filepathOrDirent. EffectFn3 (Array String) { cwd :: Nullable FilePath, exclude :: Nullable (filepathOrDirent -> Boolean), withFileTypes :: Boolean } (JSCallback (Array filepathOrDirent)) Unit +foreign import globImpl :: forall filepathOrDirent. EffectFn3 (Array FilePath) { cwd :: Nullable FilePath, exclude :: Nullable (filepathOrDirent -> Boolean), withFileTypes :: Boolean } (JSCallback (Array filepathOrDirent)) Unit foreign import lchmodImpl :: EffectFn3 FilePath String (JSCallback Unit) Unit foreign import lchownImpl :: EffectFn4 FilePath Int Int (JSCallback Unit) Unit foreign import lutimesImpl :: EffectFn4 FilePath Int Int (JSCallback Unit) Unit diff --git a/src/Node/FS/Sync.purs b/src/Node/FS/Sync.purs index 25fe268..4a17b62 100644 --- a/src/Node/FS/Sync.purs +++ b/src/Node/FS/Sync.purs @@ -93,7 +93,7 @@ foreign import chmodSyncImpl :: EffectFn2 FilePath String Unit foreign import statSyncImpl :: EffectFn1 FilePath Stats foreign import lstatSyncImpl :: EffectFn1 FilePath Stats foreign import linkSyncImpl :: EffectFn2 FilePath FilePath Unit -foreign import symlinkSyncImpl :: EffectFn3 FilePath FilePath String Unit +foreign import symlinkSyncImpl :: EffectFn3 FilePath FilePath (Nullable String) Unit foreign import readlinkSyncImpl :: EffectFn1 FilePath FilePath foreign import realpathSyncImpl :: forall cache. EffectFn2 FilePath { | cache } FilePath foreign import unlinkSyncImpl :: EffectFn1 FilePath Unit From efebe33ddf9be9e660694b1bf35e7dab6c2341a4 Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Fri, 4 Oct 2024 19:26:37 +0700 Subject: [PATCH 03/32] feat: node-buffer-blob --- spago.lock | 193 ++--------------------------------------------------- spago.yaml | 131 +----------------------------------- 2 files changed, 5 insertions(+), 319 deletions(-) diff --git a/spago.lock b/spago.lock index 419c254..28a0da2 100644 --- a/spago.lock +++ b/spago.lock @@ -14,7 +14,6 @@ workspace: - js-date - maybe - node-buffer - - node-buffer-blob - node-path - node-streams - nullable @@ -25,7 +24,6 @@ workspace: - unsafe-coerce build_plan: - aff - - aff-promise - arraybuffer-types - arrays - bifunctors @@ -48,14 +46,11 @@ workspace: - integers - invariant - js-date - - js-promise - lazy - lists - maybe - - media-types - newtype - node-buffer - - node-buffer-blob - node-event-emitter - node-path - node-streams @@ -79,7 +74,6 @@ workspace: - type-equality - unfoldable - unsafe-coerce - - web-streams test: dependencies: - aff @@ -639,135 +633,7 @@ workspace: yoga-tree: 1.0.0 z3: 0.0.2 zipperarray: 2.0.0 - extra_packages: - bench: - path: /home/srghma/projects/purescript-language-cst-parser/bench - bin: - path: /home/srghma/projects/purescript-overlay/generate/bin - bolson: - path: /home/srghma/projects/purescript-bolson - codegen: - path: /home/srghma/projects/purescript-deku/codegen - deku: - path: /home/srghma/projects/purescript-deku/deku - deku-core: - path: /home/srghma/projects/purescript-deku/deku-core - deku-css: - path: /home/srghma/projects/purescript-deku/deku-css - deku-documentation: - path: /home/srghma/projects/deku-documentation - deku-dom: - path: /home/srghma/projects/purescript-deku/deku-dom - deku-nextui: - path: /home/srghma/projects/purescript-deku-nextui - dodo-printer: - path: /home/srghma/projects/purescript-dodo-printer - express: - path: /home/srghma/projects/purescript-express - faker: - path: /home/srghma/projects/purescript-faker - foreign-generic: - path: /home/srghma/projects/purescript-foreign-generic - foreign-js-map: - path: /home/srghma/projects/purescript-foreign-js-map - github-actions-toolkit: - path: /home/srghma/projects/purescript-github-actions-toolkit - homogeneous-records: - path: /home/srghma/projects/purescript-homogeneous-records - html2deku: - path: /home/srghma/projects/html2deku - hyper: - path: /home/srghma/projects/hyper - hyrule: - path: /home/srghma/projects/purescript-hyrule - hyrule-demo: - path: /home/srghma/projects/purescript-hyrule-demo - jsdom: - path: /home/srghma/projects/purescript-jsdom - language-cst-parser: - path: /home/srghma/projects/purescript-language-cst-parser/lib - lib: - path: /home/srghma/projects/purescript-overlay/generate/lib - lumi-components: - path: /home/srghma/projects/purescript-lumi-components - lunapark: - path: /home/srghma/projects/purescript-lunapark - myapp-api-server: - path: /home/srghma/projects/nativescript-testapp/packages/api-server - myapp-common: - path: /home/srghma/projects/nativescript-testapp/packages/common - node-buffer-blob: - path: /home/srghma/projects/purescript-node-buffer-blob - node-workerbees: - path: /home/srghma/projects/purescript-node-workerbees - nodemailer: - path: /home/srghma/projects/purescript-nodemailer - open-drawing: - path: /home/srghma/projects/purescript-open-drawing/lib - open-drawing-example: - path: /home/srghma/projects/purescript-open-drawing/example - open-express-passport: - path: /home/srghma/projects/purescript-open-express-passport - open-folds: - path: /home/srghma/projects/purescript-open-folds - open-foreign-generic: - path: /home/srghma/projects/purescript-open-foreign-generic - open-memoize: - path: /home/srghma/projects/purescript-open-memoize - open-mkdirp-aff: - path: /home/srghma/projects/purescript-open-mkdirp-aff - open-pairing: - path: /home/srghma/projects/purescript-open-pairing_ - open-smolder: - path: /home/srghma/projects/purescript-open-smolder - parse-package-set: - path: /home/srghma/projects/purescript-language-cst-parser/parse-package-set - parsing: - path: /home/srghma/projects/purescript-parsing - pathy-node-fs: - path: /home/srghma/projects/purescript-pathy-node-fs - postgresql-client: - path: /home/srghma/projects/purescript-postgresql-client - profunctor: - path: /home/srghma/projects/purescript-profunctor - protolude: - path: /home/srghma/projects/purescript-protolude - record-extra-srghma: - path: /home/srghma/projects/purescript-record-extra-srghma - routing-duplex-variant: - path: /home/srghma/projects/purescript-routing-duplex-variant - simple: - path: /home/srghma/projects/purescript-overlay/nix/examples/simple - simple-codegen: - path: /home/srghma/projects/purescript-overlay/nix/examples/simple-codegen - simple-ffi: - path: /home/srghma/projects/purescript-overlay/nix/examples/simple-ffi - spago: - path: /home/srghma/projects/spago - spago-bin: - path: /home/srghma/projects/spago/bin - spago-core: - path: /home/srghma/projects/spago/core - spec-discovery: - path: /home/srghma/projects/purescript-spec-discovery - tidy: - path: /home/srghma/projects/purescript-tidy/lib - tidy-cli: - path: /home/srghma/projects/purescript-tidy/bin - tidy-codegen: - path: /home/srghma/projects/purescript-tidy-codegen - tidy-script: - path: /home/srghma/projects/purescript-tidy/script - tldr: - path: /home/srghma/projects/purescript-tldr - web-intersection-observer: - path: /home/srghma/projects/purescript-web-intersection-observer - webpack-loader-api: - path: /home/srghma/projects/purescript-webpack-loader-api - websocket-simple: - path: /home/srghma/projects/purescript-websocket-simple - yarn: - path: /home/srghma/projects/purescript-yarn + extra_packages: {} packages: aff: type: registry @@ -790,13 +656,6 @@ packages: - tailrec - transformers - unsafe-coerce - aff-promise: - type: registry - version: 4.0.0 - integrity: sha256-Kq5EupbUpXeUXx4JqGQE7/RTTz/H6idzWhsocwlEFhM= - dependencies: - - aff - - foreign arraybuffer-types: type: registry version: 3.0.2 @@ -1051,17 +910,6 @@ packages: - foreign - integers - now - js-promise: - type: registry - version: 1.0.0 - integrity: sha256-kXNo5g9RJgPdrTuKRe5oG2kBIwPp+j5VDPDplqZBJzQ= - dependencies: - - effect - - exceptions - - foldable-traversable - - functions - - maybe - - prelude lazy: type: registry version: 6.0.0 @@ -1097,13 +945,6 @@ packages: - invariant - newtype - prelude - media-types: - type: registry - version: 6.0.0 - integrity: sha256-n/4FoGBasbVSYscGVRSyBunQ6CZbL3jsYL+Lp01mc9k= - dependencies: - - newtype - - prelude newtype: type: registry version: 5.0.0 @@ -1122,21 +963,6 @@ packages: - nullable - st - unsafe-coerce - node-buffer-blob: - type: local - path: /home/srghma/projects/purescript-node-buffer-blob - dependencies: - - aff-promise - - arraybuffer-types - - arrays - - effect - - maybe - - media-types - - newtype - - node-buffer - - nullable - - prelude - - web-streams node-event-emitter: type: registry version: 3.0.0 @@ -1251,8 +1077,9 @@ packages: integrity: sha256-o8p6SLYmVPqzXZhQFd2hGAWEwBoXl1swxLG/scpJ0V0= dependencies: [] profunctor: - type: local - path: /home/srghma/projects/purescript-profunctor + type: registry + version: 6.0.1 + integrity: sha256-E58hSYdJvF2Qjf9dnWLPlJKh2Z2fLfFLkQoYi16vsFk= dependencies: - control - distributive @@ -1366,15 +1193,3 @@ packages: version: 6.0.0 integrity: sha256-IqIYW4Vkevn8sI+6aUwRGvd87tVL36BBeOr0cGAE7t0= dependencies: [] - web-streams: - type: registry - version: 4.0.0 - integrity: sha256-02HgXIk6R+pU9fWOX42krukAI1QkCbLKcCv3b4Jq6WI= - dependencies: - - arraybuffer-types - - effect - - exceptions - - js-promise - - nullable - - prelude - - tuples diff --git a/spago.yaml b/spago.yaml index 67bd253..8710691 100644 --- a/spago.yaml +++ b/spago.yaml @@ -24,7 +24,6 @@ package: - prelude - strings - unsafe-coerce - - node-buffer-blob - refs test: main: Test.Main @@ -36,132 +35,4 @@ package: workspace: packageSet: registry: 60.2.1 - extraPackages: - bench: - path: /home/srghma/projects/purescript-language-cst-parser/bench - bin: - path: /home/srghma/projects/purescript-overlay/generate/bin - bolson: - path: /home/srghma/projects/purescript-bolson - codegen: - path: /home/srghma/projects/purescript-deku/codegen - deku: - path: /home/srghma/projects/purescript-deku/deku - deku-core: - path: /home/srghma/projects/purescript-deku/deku-core - deku-css: - path: /home/srghma/projects/purescript-deku/deku-css - deku-documentation: - path: /home/srghma/projects/deku-documentation - deku-dom: - path: /home/srghma/projects/purescript-deku/deku-dom - deku-nextui: - path: /home/srghma/projects/purescript-deku-nextui - dodo-printer: - path: /home/srghma/projects/purescript-dodo-printer - express: - path: /home/srghma/projects/purescript-express - faker: - path: /home/srghma/projects/purescript-faker - foreign-generic: - path: /home/srghma/projects/purescript-foreign-generic - foreign-js-map: - path: /home/srghma/projects/purescript-foreign-js-map - github-actions-toolkit: - path: /home/srghma/projects/purescript-github-actions-toolkit - homogeneous-records: - path: /home/srghma/projects/purescript-homogeneous-records - html2deku: - path: /home/srghma/projects/html2deku - hyper: - path: /home/srghma/projects/hyper - hyrule: - path: /home/srghma/projects/purescript-hyrule - hyrule-demo: - path: /home/srghma/projects/purescript-hyrule-demo - jsdom: - path: /home/srghma/projects/purescript-jsdom - language-cst-parser: - path: /home/srghma/projects/purescript-language-cst-parser/lib - lib: - path: /home/srghma/projects/purescript-overlay/generate/lib - lumi-components: - path: /home/srghma/projects/purescript-lumi-components - lunapark: - path: /home/srghma/projects/purescript-lunapark - myapp-api-server: - path: /home/srghma/projects/nativescript-testapp/packages/api-server - myapp-common: - path: /home/srghma/projects/nativescript-testapp/packages/common - node-buffer-blob: - path: /home/srghma/projects/purescript-node-buffer-blob - node-workerbees: - path: /home/srghma/projects/purescript-node-workerbees - nodemailer: - path: /home/srghma/projects/purescript-nodemailer - open-drawing: - path: /home/srghma/projects/purescript-open-drawing/lib - open-drawing-example: - path: /home/srghma/projects/purescript-open-drawing/example - open-express-passport: - path: /home/srghma/projects/purescript-open-express-passport - open-folds: - path: /home/srghma/projects/purescript-open-folds - open-foreign-generic: - path: /home/srghma/projects/purescript-open-foreign-generic - open-memoize: - path: /home/srghma/projects/purescript-open-memoize - open-mkdirp-aff: - path: /home/srghma/projects/purescript-open-mkdirp-aff - open-pairing: - path: /home/srghma/projects/purescript-open-pairing_ - open-smolder: - path: /home/srghma/projects/purescript-open-smolder - parse-package-set: - path: /home/srghma/projects/purescript-language-cst-parser/parse-package-set - parsing: - path: /home/srghma/projects/purescript-parsing - pathy-node-fs: - path: /home/srghma/projects/purescript-pathy-node-fs - postgresql-client: - path: /home/srghma/projects/purescript-postgresql-client - profunctor: - path: /home/srghma/projects/purescript-profunctor - protolude: - path: /home/srghma/projects/purescript-protolude - record-extra-srghma: - path: /home/srghma/projects/purescript-record-extra-srghma - routing-duplex-variant: - path: /home/srghma/projects/purescript-routing-duplex-variant - simple: - path: /home/srghma/projects/purescript-overlay/nix/examples/simple - simple-codegen: - path: /home/srghma/projects/purescript-overlay/nix/examples/simple-codegen - simple-ffi: - path: /home/srghma/projects/purescript-overlay/nix/examples/simple-ffi - spago: - path: /home/srghma/projects/spago - spago-bin: - path: /home/srghma/projects/spago/bin - spago-core: - path: /home/srghma/projects/spago/core - spec-discovery: - path: /home/srghma/projects/purescript-spec-discovery - tidy: - path: /home/srghma/projects/purescript-tidy/lib - tidy-cli: - path: /home/srghma/projects/purescript-tidy/bin - tidy-codegen: - path: /home/srghma/projects/purescript-tidy-codegen - tidy-script: - path: /home/srghma/projects/purescript-tidy/script - tldr: - path: /home/srghma/projects/purescript-tldr - web-intersection-observer: - path: /home/srghma/projects/purescript-web-intersection-observer - webpack-loader-api: - path: /home/srghma/projects/purescript-webpack-loader-api - websocket-simple: - path: /home/srghma/projects/purescript-websocket-simple - yarn: - path: /home/srghma/projects/purescript-yarn + extraPackages: {} From 2e5f45ccdee9ec6eef9008967fa7543be8fdbf7d Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Fri, 4 Oct 2024 19:28:04 +0700 Subject: [PATCH 04/32] feat: spago build --offline --censor-stats --strict --pedantic-packages --- spago.lock | 7 +++++++ spago.yaml | 9 +++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/spago.lock b/spago.lock index 28a0da2..37a7a2b 100644 --- a/spago.lock +++ b/spago.lock @@ -4,6 +4,8 @@ workspace: path: ./ core: dependencies: + - aff + - arrays - datetime - effect - either @@ -21,6 +23,7 @@ workspace: - prelude - refs - strings + - tuples - unsafe-coerce build_plan: - aff @@ -80,6 +83,8 @@ workspace: - arrays - assert - console + - foldable-traversable + - node-event-emitter build_plan: - aff - arrays @@ -107,7 +112,9 @@ workspace: - lists - maybe - newtype + - node-event-emitter - nonempty + - nullable - numbers - ordered-collections - orders diff --git a/spago.yaml b/spago.yaml index 8710691..c754890 100644 --- a/spago.yaml +++ b/spago.yaml @@ -7,6 +7,8 @@ package: githubOwner: purescript-node githubRepo: purescript-node-fs dependencies: + - aff + - arrays - datetime - effect - either @@ -22,16 +24,19 @@ package: - nullable - partial - prelude + - refs - strings + - tuples - unsafe-coerce - - refs test: main: Test.Main dependencies: - - console - aff - arrays - assert + - console + - foldable-traversable + - node-event-emitter workspace: packageSet: registry: 60.2.1 From ddd6a47236dfa41160249f03bfe8f5b2d72abbc3 Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Sat, 5 Oct 2024 07:05:23 +0700 Subject: [PATCH 05/32] fix: tests --- .github/workflows/ci.yml | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 00e2e2c..025c44c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,27 +14,19 @@ jobs: - uses: purescript-contrib/setup-purescript@main with: - purescript: "unstable" + purescript: "latest" purs-tidy: "latest" + spago: "unstable" - uses: actions/setup-node@v4 with: node-version: "lts/*" - - name: Install dependencies - run: | - npm install -g bower - npm install - bower install --production - - name: Build source - run: npm run-script build + run: spago build --censor-stats --strict --pedantic-packages - name: Run tests - run: | - bower install - npm run-script test --if-present + run: spago test --censor-stats --strict --pedantic-packages - - name: Check formatting - run: | - purs-tidy check src test + - name: Verify formatting + run: purs-tidy check src test From e98b91cd58d9c05bf41b76dac3e385ab48cdc7c5 Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Sat, 5 Oct 2024 17:10:27 +0700 Subject: [PATCH 06/32] rm -rdf .spago spago.lock output && spago upgrade --migrate && spago test --censor-stats --strict --pedantic-packages --- spago.lock | 2522 +++++++++++++++++++++++++++------------------------- spago.yaml | 2 +- 2 files changed, 1321 insertions(+), 1203 deletions(-) diff --git a/spago.lock b/spago.lock index 37a7a2b..49fc213 100644 --- a/spago.lock +++ b/spago.lock @@ -1,1202 +1,1320 @@ -workspace: - packages: - node-fs: - path: ./ - core: - dependencies: - - aff - - arrays - - datetime - - effect - - either - - enums - - exceptions - - functions - - integers - - js-date - - maybe - - node-buffer - - node-path - - node-streams - - nullable - - partial - - prelude - - refs - - strings - - tuples - - unsafe-coerce - build_plan: - - aff - - arraybuffer-types - - arrays - - bifunctors - - const - - contravariant - - control - - datetime - - distributive - - effect - - either - - enums - - exceptions - - exists - - foldable-traversable - - foreign - - functions - - functors - - gen - - identity - - integers - - invariant - - js-date - - lazy - - lists - - maybe - - newtype - - node-buffer - - node-event-emitter - - node-path - - node-streams - - nonempty - - now - - nullable - - numbers - - ordered-collections - - orders - - parallel - - partial - - prelude - - profunctor - - refs - - safe-coerce - - st - - strings - - tailrec - - transformers - - tuples - - type-equality - - unfoldable - - unsafe-coerce - test: - dependencies: - - aff - - arrays - - assert - - console - - foldable-traversable - - node-event-emitter - build_plan: - - aff - - arrays - - assert - - bifunctors - - console - - const - - contravariant - - control - - datetime - - distributive - - effect - - either - - enums - - exceptions - - exists - - foldable-traversable - - functions - - functors - - gen - - identity - - integers - - invariant - - lazy - - lists - - maybe - - newtype - - node-event-emitter - - nonempty - - nullable - - numbers - - ordered-collections - - orders - - parallel - - partial - - prelude - - profunctor - - refs - - safe-coerce - - st - - tailrec - - transformers - - tuples - - type-equality - - unfoldable - - unsafe-coerce - package_set: - address: - registry: 60.2.1 - compiler: ">=0.15.15 <0.16.0" - content: - abc-parser: 2.0.1 - ace: 9.1.0 - address-rfc2821: 0.1.1 - aff: 8.0.0 - aff-bus: 6.0.0 - aff-coroutines: 9.0.0 - aff-promise: 4.0.0 - aff-retry: 2.0.0 - affjax: 13.0.0 - affjax-node: 1.0.0 - affjax-web: 1.0.0 - ansi: 7.0.0 - apexcharts: 0.5.0 - applicative-phases: 1.0.0 - argonaut: 9.0.0 - argonaut-aeson-generic: 0.4.1 - argonaut-codecs: 9.1.0 - argonaut-core: 7.0.0 - argonaut-generic: 8.0.0 - argonaut-traversals: 10.0.0 - argparse-basic: 2.0.0 - array-builder: 0.1.2 - array-search: 0.6.0 - arraybuffer: 13.2.0 - arraybuffer-builder: 3.1.0 - arraybuffer-types: 3.0.2 - arrays: 7.3.0 - arrays-extra: 0.6.1 - arrays-zipper: 2.0.1 - ask: 1.0.0 - assert: 6.0.0 - assert-multiple: 0.4.0 - avar: 5.0.0 - b64: 0.0.8 - barbies: 1.0.1 - barlow-lens: 0.9.0 - bifunctors: 6.0.0 - bigints: 7.0.1 - bolson: 0.3.9 - bookhound: 0.1.7 - bower-json: 3.0.0 - call-by-name: 4.0.1 - canvas: 6.0.0 - canvas-action: 9.0.0 - cartesian: 1.0.6 - catenable-lists: 7.0.0 - cbor-stream: 1.3.0 - chameleon: 1.0.0 - chameleon-halogen: 1.0.3 - chameleon-react-basic: 1.1.0 - chameleon-styled: 2.5.0 - chameleon-transformers: 1.0.0 - channel: 1.0.0 - checked-exceptions: 3.1.1 - choku: 1.0.1 - classless: 0.1.1 - classless-arbitrary: 0.1.1 - classless-decode-json: 0.1.1 - classless-encode-json: 0.1.3 - classnames: 2.0.0 - codec: 6.1.0 - codec-argonaut: 10.0.0 - codec-json: 2.0.0 - colors: 7.0.1 - concur-core: 0.5.0 - concur-react: 0.5.0 - concurrent-queues: 3.0.0 - console: 6.1.0 - const: 6.0.0 - contravariant: 6.0.0 - control: 6.0.0 - convertable-options: 1.0.0 - coroutines: 7.0.0 - css: 6.0.0 - css-frameworks: 1.0.1 - csv-stream: 2.3.0 - data-mvc: 0.0.2 - datetime: 6.1.0 - datetime-parsing: 0.2.0 - debounce: 0.1.0 - debug: 6.0.2 - decimals: 7.1.0 - default-values: 1.0.1 - deku: 0.9.23 - deno: 0.0.5 - dissect: 1.0.0 - distributive: 6.0.0 - dom-filereader: 7.0.0 - dom-indexed: 12.0.0 - dom-simple: 0.4.0 - dotenv: 4.0.3 - droplet: 0.6.0 - dts: 1.0.0 - dual-numbers: 1.0.3 - dynamic-buffer: 3.0.1 - echarts-simple: 0.0.1 - effect: 4.0.0 - either: 6.1.0 - elmish: 0.13.0 - elmish-enzyme: 0.1.1 - elmish-hooks: 0.10.3 - elmish-html: 0.9.0 - elmish-testing-library: 0.3.2 - email-validate: 7.0.0 - encoding: 0.0.9 - enums: 6.0.1 - env-names: 0.4.0 - error: 2.0.0 - eta-conversion: 0.3.2 - exceptions: 6.1.0 - exists: 6.0.0 - exitcodes: 4.0.0 - expect-inferred: 3.0.0 - ezfetch: 1.0.0 - fahrtwind: 2.0.0 - fallback: 0.1.0 - fast-vect: 1.2.0 - fetch: 4.1.0 - fetch-argonaut: 1.0.1 - fetch-core: 5.1.0 - fetch-yoga-json: 1.1.0 - ffi-simple: 0.5.1 - fft-js: 0.1.0 - filterable: 5.0.0 - fix-functor: 0.1.0 - fixed-points: 7.0.0 - fixed-precision: 5.0.0 - flame: 1.3.0 - float32: 2.0.0 - fmt: 0.2.1 - foldable-traversable: 6.0.0 - foldable-traversable-extra: 0.0.6 - foreign: 7.0.0 - foreign-object: 4.1.0 - foreign-readwrite: 3.4.0 - forgetmenot: 0.1.0 - fork: 6.0.0 - form-urlencoded: 7.0.0 - formatters: 7.0.0 - framer-motion: 1.0.1 - free: 7.1.0 - freeap: 7.0.0 - freer-free: 0.0.1 - freet: 7.0.0 - functions: 6.0.0 - functor1: 3.0.0 - functors: 5.0.0 - fuzzy: 0.4.0 - gen: 4.0.0 - generate-values: 1.0.1 - generic-router: 0.0.1 - geojson: 0.0.5 - geometria: 2.2.0 - gojs: 0.1.1 - grain: 3.0.0 - grain-router: 3.0.0 - grain-virtualized: 3.0.0 - graphs: 8.1.0 - group: 4.1.1 - halogen: 7.0.0 - halogen-bootstrap5: 5.3.2 - halogen-canvas: 1.0.0 - halogen-css: 10.0.0 - halogen-echarts-simple: 0.0.4 - halogen-formless: 4.0.3 - halogen-helix: 1.0.1 - halogen-hooks: 0.6.3 - halogen-hooks-extra: 0.9.0 - halogen-infinite-scroll: 1.1.0 - halogen-store: 0.5.4 - halogen-storybook: 2.0.0 - halogen-subscriptions: 2.0.0 - halogen-svg-elems: 8.0.0 - halogen-typewriter: 1.0.4 - halogen-vdom: 8.0.0 - halogen-vdom-string-renderer: 0.5.0 - halogen-xterm: 2.0.0 - heckin: 2.0.1 - heterogeneous: 0.6.0 - homogeneous: 0.4.0 - http-methods: 6.0.0 - httpurple: 4.0.0 - huffman: 0.4.0 - humdrum: 0.0.1 - hyrule: 2.3.8 - identity: 6.0.0 - identy: 4.0.1 - indexed-db: 1.0.0 - indexed-monad: 3.0.0 - int64: 3.0.0 - integers: 6.0.0 - interpolate: 5.0.2 - intersection-observer: 1.0.1 - invariant: 6.0.0 - jarilo: 1.0.1 - jelly: 0.10.0 - jelly-router: 0.3.0 - jelly-signal: 0.4.0 - jest: 1.0.0 - js-abort-controller: 1.0.0 - js-bigints: 2.2.1 - js-date: 8.0.0 - js-fetch: 0.2.1 - js-fileio: 3.0.0 - js-intl: 1.0.4 - js-iterators: 0.1.1 - js-maps: 0.1.2 - js-promise: 1.0.0 - js-promise-aff: 1.0.0 - js-timers: 6.1.0 - js-uri: 3.1.0 - json: 1.1.0 - json-codecs: 5.0.0 - justifill: 0.5.0 - jwt: 0.0.9 - labeled-data: 0.2.0 - language-cst-parser: 0.14.0 - lazy: 6.0.0 - lazy-joe: 1.0.0 - lcg: 4.0.0 - leibniz: 5.0.0 - leveldb: 1.0.1 - liminal: 1.0.1 - linalg: 6.0.0 - lists: 7.0.0 - literals: 1.0.2 - logging: 3.0.0 - logging-journald: 0.4.0 - lumi-components: 18.0.0 - machines: 7.0.0 - maps-eager: 0.5.0 - marionette: 1.0.0 - marionette-react-basic-hooks: 0.1.1 - marked: 0.1.0 - matrices: 5.0.1 - matryoshka: 1.0.0 - maybe: 6.0.0 - media-types: 6.0.0 - meowclient: 1.0.0 - midi: 4.0.0 - milkis: 9.0.0 - minibench: 4.0.1 - mmorph: 7.0.0 - monad-control: 5.0.0 - monad-logger: 1.3.1 - monad-loops: 0.5.0 - monad-unlift: 1.0.1 - monoid-extras: 0.0.1 - monoidal: 0.16.0 - morello: 0.4.0 - mote: 3.0.0 - motsunabe: 2.0.0 - mvc: 0.0.1 - mysql: 6.0.1 - n3: 0.1.0 - nano-id: 1.1.0 - nanoid: 0.1.0 - naturals: 3.0.0 - nested-functor: 0.2.1 - newtype: 5.0.0 - nextjs: 0.1.1 - nextui: 0.2.0 - node-buffer: 9.0.0 - node-child-process: 11.1.0 - node-event-emitter: 3.0.0 - node-execa: 5.0.0 - node-fs: 9.2.0 - node-glob-basic: 1.3.0 - node-http: 9.1.0 - node-http2: 1.1.1 - node-human-signals: 1.0.0 - node-net: 5.1.0 - node-os: 5.1.0 - node-path: 5.0.0 - node-process: 11.2.0 - node-readline: 8.1.1 - node-sqlite3: 8.0.0 - node-stream-pipes: 2.1.6 - node-streams: 9.0.0 - node-tls: 0.3.1 - node-url: 7.0.1 - node-zlib: 0.4.0 - nonempty: 7.0.0 - now: 6.0.0 - npm-package-json: 2.0.0 - nullable: 6.0.0 - numberfield: 0.2.2 - numbers: 9.0.1 - oak: 3.1.1 - oak-debug: 1.2.2 - object-maps: 0.3.0 - ocarina: 1.5.4 - oooooooooorrrrrrrmm-lib: 0.0.1 - open-folds: 6.4.0 - open-foreign-generic: 11.0.3 - open-memoize: 6.2.0 - open-mkdirp-aff: 1.2.0 - open-pairing: 6.2.0 - open-smolder: 12.0.2 - options: 7.0.0 - optparse: 5.0.1 - ordered-collections: 3.2.0 - ordered-set: 0.4.0 - orders: 6.0.0 - owoify: 1.2.0 - pairs: 9.0.1 - parallel: 7.0.0 - parsing: 10.2.0 - parsing-dataview: 3.2.4 - partial: 4.0.0 - pathy: 9.0.0 - pha: 0.13.0 - phaser: 0.7.0 - phylio: 1.1.2 - pipes: 8.0.0 - pirates-charm: 0.0.1 - pmock: 0.9.0 - point-free: 1.0.0 - pointed-list: 0.5.1 - polymorphic-vectors: 4.0.0 - posix-types: 6.0.0 - postgresql: 2.0.19 - precise: 6.0.0 - precise-datetime: 7.0.0 - prelude: 6.0.1 - prettier-printer: 3.0.0 - priority-queue: 0.1.2 - profunctor: 6.0.1 - profunctor-lenses: 8.0.0 - protobuf: 4.3.0 - psa-utils: 8.0.0 - psci-support: 6.0.0 - punycode: 1.0.0 - qualified-do: 2.2.0 - quantities: 12.2.0 - quickcheck: 8.0.1 - quickcheck-combinators: 0.1.3 - quickcheck-laws: 7.0.0 - quickcheck-utf8: 0.0.0 - random: 6.0.0 - rationals: 6.0.0 - rdf: 0.1.0 - react: 11.0.0 - react-aria: 0.2.0 - react-basic: 17.0.0 - react-basic-classic: 3.0.0 - react-basic-dnd: 10.1.0 - react-basic-dom: 6.1.0 - react-basic-emotion: 7.1.0 - react-basic-hooks: 8.2.0 - react-basic-storybook: 2.0.0 - react-dom: 8.0.0 - react-halo: 3.0.0 - react-icons: 1.1.5 - react-markdown: 0.1.0 - react-testing-library: 4.0.1 - react-virtuoso: 1.0.0 - reactix: 0.6.1 - read: 1.0.1 - recharts: 1.1.0 - record: 4.0.0 - record-extra: 5.0.1 - record-ptional-fields: 0.1.2 - record-studio: 1.0.4 - refs: 6.0.0 - remotedata: 5.0.1 - repr: 0.5.0 - resize-observer: 1.0.0 - resource: 2.0.1 - resourcet: 1.0.0 - result: 1.0.3 - return: 0.2.0 - ring-modules: 5.0.1 - rito: 0.3.4 - roman: 0.4.0 - rough-notation: 1.0.2 - routing: 11.0.0 - routing-duplex: 0.7.0 - run: 5.0.0 - safe-coerce: 2.0.0 - safely: 4.0.1 - school-of-music: 1.3.0 - selection-foldable: 0.2.0 - selective-functors: 1.0.1 - semirings: 7.0.0 - signal: 13.0.0 - simple-emitter: 3.0.1 - simple-i18n: 2.0.1 - simple-json: 9.0.0 - simple-json-generics: 0.2.1 - simple-ulid: 3.0.0 - sized-matrices: 1.0.0 - sized-vectors: 5.0.2 - slug: 3.1.0 - small-ffi: 4.0.1 - soundfonts: 4.1.0 - sparse-matrices: 2.0.1 - sparse-polynomials: 3.0.1 - spec: 8.0.0 - spec-discovery: 8.3.0 - spec-mocha: 5.1.1 - spec-node: 0.0.2 - spec-quickcheck: 5.0.2 - spec-reporter-xunit: 0.7.1 - splitmix: 2.1.0 - ssrs: 1.0.0 - st: 6.2.0 - statistics: 0.3.2 - strictlypositiveint: 1.0.1 - string-parsers: 8.0.0 - strings: 6.0.1 - strings-extra: 4.0.0 - stringutils: 0.0.12 - substitute: 0.2.3 - supply: 0.2.0 - svg-parser: 3.0.0 - systemd-journald: 0.3.0 - tagged: 4.0.2 - tailrec: 6.1.0 - tecton: 0.2.1 - tecton-halogen: 0.2.0 - test-unit: 17.0.0 - thermite: 6.3.1 - thermite-dom: 0.3.1 - these: 6.0.0 - threading: 0.0.3 - tldr: 0.0.0 - toestand: 0.9.0 - transformation-matrix: 1.0.1 - transformers: 6.1.0 - tree-rose: 4.0.2 - ts-bridge: 4.0.0 - tuples: 7.0.0 - two-or-more: 1.0.0 - type-equality: 4.0.1 - typedenv: 2.0.1 - typelevel: 6.0.0 - typelevel-lists: 2.1.0 - typelevel-peano: 1.0.1 - typelevel-prelude: 7.0.0 - typelevel-regex: 0.0.3 - typelevel-rows: 0.1.0 - typisch: 0.4.0 - uint: 7.0.0 - ulid: 3.0.1 - uncurried-transformers: 1.1.0 - undefined: 2.0.0 - undefined-is-not-a-problem: 1.1.0 - unfoldable: 6.0.0 - unicode: 6.0.0 - unique: 0.6.1 - unlift: 1.0.1 - unordered-collections: 3.1.0 - unsafe-coerce: 6.0.0 - unsafe-reference: 5.0.0 - untagged-to-tagged: 0.1.4 - untagged-union: 1.0.0 - uri: 9.0.0 - url-immutable: 1.0.0 - uuid: 9.0.0 - uuidv4: 1.0.0 - validation: 6.0.0 - variant: 8.0.0 - variant-encodings: 2.0.0 - vectorfield: 1.0.1 - vectors: 2.1.0 - versions: 7.0.0 - visx: 0.0.2 - web-clipboard: 6.0.0 - web-cssom: 2.0.0 - web-cssom-view: 0.1.0 - web-dom: 6.0.0 - web-dom-parser: 8.0.0 - web-dom-xpath: 3.0.0 - web-encoding: 3.0.0 - web-events: 4.0.0 - web-fetch: 4.0.1 - web-file: 4.0.0 - web-geometry: 0.1.0 - web-html: 4.1.0 - web-pointerevents: 2.0.0 - web-proletarian: 1.0.0 - web-promise: 3.2.0 - web-resize-observer: 2.1.0 - web-router: 1.0.0 - web-socket: 4.0.0 - web-storage: 5.0.0 - web-streams: 4.0.0 - web-touchevents: 4.0.0 - web-uievents: 5.0.0 - web-url: 2.0.0 - web-workers: 1.1.0 - web-xhr: 5.0.1 - webextension-polyfill: 0.1.0 - webgpu: 0.0.1 - which: 2.0.0 - xterm: 1.0.0 - yoga-fetch: 1.0.1 - yoga-json: 5.1.0 - yoga-om: 0.1.0 - yoga-postgres: 6.0.0 - yoga-tree: 1.0.0 - z3: 0.0.2 - zipperarray: 2.0.0 - extra_packages: {} -packages: - aff: - type: registry - version: 8.0.0 - integrity: sha256-5MmdI4+0RHBtSBy+YlU3/Cq4R5W2ih3OaRedJIrVHdk= - dependencies: - - bifunctors - - control - - datetime - - effect - - either - - exceptions - - foldable-traversable - - functions - - maybe - - newtype - - parallel - - prelude - - refs - - tailrec - - transformers - - unsafe-coerce - arraybuffer-types: - type: registry - version: 3.0.2 - integrity: sha256-mQKokysYVkooS4uXbO+yovmV/s8b138Ws3zQvOwIHRA= - dependencies: [] - arrays: - type: registry - version: 7.3.0 - integrity: sha256-tmcklBlc/muUtUfr9RapdCPwnlQeB3aSrC4dK85gQlc= - dependencies: - - bifunctors - - control - - foldable-traversable - - functions - - maybe - - nonempty - - partial - - prelude - - safe-coerce - - st - - tailrec - - tuples - - unfoldable - - unsafe-coerce - assert: - type: registry - version: 6.0.0 - integrity: sha256-hCSYcCw9kj3qujoDcriWhCdmrpPZoguSPDZhEMnTl3A= - dependencies: - - console - - effect - - prelude - bifunctors: - type: registry - version: 6.0.0 - integrity: sha256-/gZwC9YhNxZNQpnHa5BIYerCGM2jeX9ukZiEvYxm5Nw= - dependencies: - - const - - either - - newtype - - prelude - - tuples - console: - type: registry - version: 6.1.0 - integrity: sha256-CxmAzjgyuGDmt9FZW51VhV6rBPwR6o0YeKUzA9rSzcM= - dependencies: - - effect - - prelude - const: - type: registry - version: 6.0.0 - integrity: sha256-tNrxDW8D8H4jdHE2HiPzpLy08zkzJMmGHdRqt5BQuTc= - dependencies: - - invariant - - newtype - - prelude - contravariant: - type: registry - version: 6.0.0 - integrity: sha256-TP+ooAp3vvmdjfQsQJSichF5B4BPDHp3wAJoWchip6c= - dependencies: - - const - - either - - newtype - - prelude - - tuples - control: - type: registry - version: 6.0.0 - integrity: sha256-sH7Pg9E96JCPF9PIA6oQ8+BjTyO/BH1ZuE/bOcyj4Jk= - dependencies: - - newtype - - prelude - datetime: - type: registry - version: 6.1.0 - integrity: sha256-g/5X5BBegQWLpI9IWD+sY6mcaYpzzlW5lz5NBzaMtyI= - dependencies: - - bifunctors - - control - - either - - enums - - foldable-traversable - - functions - - gen - - integers - - lists - - maybe - - newtype - - numbers - - ordered-collections - - partial - - prelude - - tuples - distributive: - type: registry - version: 6.0.0 - integrity: sha256-HTDdmEnzigMl+02SJB88j+gAXDx9VKsbvR4MJGDPbOQ= - dependencies: - - identity - - newtype - - prelude - - tuples - - type-equality - effect: - type: registry - version: 4.0.0 - integrity: sha256-eBtZu+HZcMa5HilvI6kaDyVX3ji8p0W9MGKy2K4T6+M= - dependencies: - - prelude - either: - type: registry - version: 6.1.0 - integrity: sha256-6hgTPisnMWVwQivOu2PKYcH8uqjEOOqDyaDQVUchTpY= - dependencies: - - control - - invariant - - maybe - - prelude - enums: - type: registry - version: 6.0.1 - integrity: sha256-HWaD73JFLorc4A6trKIRUeDMdzE+GpkJaEOM1nTNkC8= - dependencies: - - control - - either - - gen - - maybe - - newtype - - nonempty - - partial - - prelude - - tuples - - unfoldable - exceptions: - type: registry - version: 6.1.0 - integrity: sha256-K0T89IHtF3vBY7eSAO7eDOqSb2J9kZGAcDN5+IKsF8E= - dependencies: - - effect - - either - - maybe - - prelude - exists: - type: registry - version: 6.0.0 - integrity: sha256-A0JQHpTfo1dNOj9U5/Fd3xndlRSE0g2IQWOGor2yXn8= - dependencies: - - unsafe-coerce - foldable-traversable: - type: registry - version: 6.0.0 - integrity: sha256-fLeqRYM4jUrZD5H4WqcwUgzU7XfYkzO4zhgtNc3jcWM= - dependencies: - - bifunctors - - const - - control - - either - - functors - - identity - - maybe - - newtype - - orders - - prelude - - tuples - foreign: - type: registry - version: 7.0.0 - integrity: sha256-1ORiqoS3HW+qfwSZAppHPWy4/6AQysxZ2t29jcdUMNA= - dependencies: - - either - - functions - - identity - - integers - - lists - - maybe - - prelude - - strings - - transformers - functions: - type: registry - version: 6.0.0 - integrity: sha256-adMyJNEnhGde2unHHAP79gPtlNjNqzgLB8arEOn9hLI= - dependencies: - - prelude - functors: - type: registry - version: 5.0.0 - integrity: sha256-zfPWWYisbD84MqwpJSZFlvM6v86McM68ob8p9s27ywU= - dependencies: - - bifunctors - - const - - contravariant - - control - - distributive - - either - - invariant - - maybe - - newtype - - prelude - - profunctor - - tuples - - unsafe-coerce - gen: - type: registry - version: 4.0.0 - integrity: sha256-f7yzAXWwr+xnaqEOcvyO3ezKdoes8+WXWdXIHDBCAPI= - dependencies: - - either - - foldable-traversable - - identity - - maybe - - newtype - - nonempty - - prelude - - tailrec - - tuples - - unfoldable - identity: - type: registry - version: 6.0.0 - integrity: sha256-4wY0XZbAksjY6UAg99WkuKyJlQlWAfTi2ssadH0wVMY= - dependencies: - - control - - invariant - - newtype - - prelude - integers: - type: registry - version: 6.0.0 - integrity: sha256-sf+sK26R1hzwl3NhXR7WAu9zCDjQnfoXwcyGoseX158= - dependencies: - - maybe - - numbers - - prelude - invariant: - type: registry - version: 6.0.0 - integrity: sha256-RGWWyYrz0Hs1KjPDA+87Kia67ZFBhfJ5lMGOMCEFoLo= - dependencies: - - control - - prelude - js-date: - type: registry - version: 8.0.0 - integrity: sha256-6TVF4DWg5JL+jRAsoMssYw8rgOVALMUHT1CuNZt8NRo= - dependencies: - - datetime - - effect - - exceptions - - foreign - - integers - - now - lazy: - type: registry - version: 6.0.0 - integrity: sha256-lMsfFOnlqfe4KzRRiW8ot5ge6HtcU3Eyh2XkXcP5IgU= - dependencies: - - control - - foldable-traversable - - invariant - - prelude - lists: - type: registry - version: 7.0.0 - integrity: sha256-EKF15qYqucuXP2lT/xPxhqy58f0FFT6KHdIB/yBOayI= - dependencies: - - bifunctors - - control - - foldable-traversable - - lazy - - maybe - - newtype - - nonempty - - partial - - prelude - - tailrec - - tuples - - unfoldable - maybe: - type: registry - version: 6.0.0 - integrity: sha256-5cCIb0wPwbat2PRkQhUeZO0jcAmf8jCt2qE0wbC3v2Q= - dependencies: - - control - - invariant - - newtype - - prelude - newtype: - type: registry - version: 5.0.0 - integrity: sha256-gdrQu8oGe9eZE6L3wOI8ql/igOg+zEGB5ITh2g+uttw= - dependencies: - - prelude - - safe-coerce - node-buffer: - type: registry - version: 9.0.0 - integrity: sha256-PWE2DJ5ruBLCmeA/fUiuySEFmUJ/VuRfyrnCuVZBlu4= - dependencies: - - arraybuffer-types - - effect - - maybe - - nullable - - st - - unsafe-coerce - node-event-emitter: - type: registry - version: 3.0.0 - integrity: sha256-Qw0MjsT4xRH2j2i4K8JmRjcMKnH5z1Cw39t00q4LE4w= - dependencies: - - effect - - either - - functions - - maybe - - nullable - - prelude - - unsafe-coerce - node-path: - type: registry - version: 5.0.0 - integrity: sha256-pd82nQ+2l5UThzaxPdKttgDt7xlsgIDLpPG0yxDEdyE= - dependencies: - - effect - node-streams: - type: registry - version: 9.0.0 - integrity: sha256-2n6dq7YWleTDmD1Kur/ul7Cn08IvWrScgPf+0PgX2TQ= - dependencies: - - aff - - effect - - either - - exceptions - - node-buffer - - node-event-emitter - - nullable - - prelude - nonempty: - type: registry - version: 7.0.0 - integrity: sha256-54ablJZUHGvvlTJzi3oXyPCuvY6zsrWJuH/dMJ/MFLs= - dependencies: - - control - - foldable-traversable - - maybe - - prelude - - tuples - - unfoldable - now: - type: registry - version: 6.0.0 - integrity: sha256-xZ7x37ZMREfs6GCDw/h+FaKHV/3sPWmtqBZRGTxybQY= - dependencies: - - datetime - - effect - nullable: - type: registry - version: 6.0.0 - integrity: sha256-yiGBVl3AD+Guy4kNWWeN+zl1gCiJK+oeIFtZtPCw4+o= - dependencies: - - effect - - functions - - maybe - numbers: - type: registry - version: 9.0.1 - integrity: sha256-/9M6aeMDBdB4cwYDeJvLFprAHZ49EbtKQLIJsneXLIk= - dependencies: - - functions - - maybe - ordered-collections: - type: registry - version: 3.2.0 - integrity: sha256-o9jqsj5rpJmMdoe/zyufWHFjYYFTTsJpgcuCnqCO6PM= - dependencies: - - arrays - - foldable-traversable - - gen - - lists - - maybe - - partial - - prelude - - st - - tailrec - - tuples - - unfoldable - orders: - type: registry - version: 6.0.0 - integrity: sha256-nBA0g3/ai0euH8q9pSbGqk53W2q6agm/dECZTHcoink= - dependencies: - - newtype - - prelude - parallel: - type: registry - version: 7.0.0 - integrity: sha256-gUC9i4Txnx9K9RcMLsjujbwZz6BB1bnE2MLvw4GIw5o= - dependencies: - - control - - effect - - either - - foldable-traversable - - functors - - maybe - - newtype - - prelude - - profunctor - - refs - - transformers - partial: - type: registry - version: 4.0.0 - integrity: sha256-fwXerld6Xw1VkReh8yeQsdtLVrjfGiVuC5bA1Wyo/J4= - dependencies: [] - prelude: - type: registry - version: 6.0.1 - integrity: sha256-o8p6SLYmVPqzXZhQFd2hGAWEwBoXl1swxLG/scpJ0V0= - dependencies: [] - profunctor: - type: registry - version: 6.0.1 - integrity: sha256-E58hSYdJvF2Qjf9dnWLPlJKh2Z2fLfFLkQoYi16vsFk= - dependencies: - - control - - distributive - - either - - exists - - invariant - - newtype - - prelude - - tuples - refs: - type: registry - version: 6.0.0 - integrity: sha256-Vgwne7jIbD3ZMoLNNETLT8Litw6lIYo3MfYNdtYWj9s= - dependencies: - - effect - - prelude - safe-coerce: - type: registry - version: 2.0.0 - integrity: sha256-a1ibQkiUcbODbLE/WAq7Ttbbh9ex+x33VCQ7GngKudU= - dependencies: - - unsafe-coerce - st: - type: registry - version: 6.2.0 - integrity: sha256-z9X0WsOUlPwNx9GlCC+YccCyz8MejC8Wb0C4+9fiBRY= - dependencies: - - partial - - prelude - - tailrec - - unsafe-coerce - strings: - type: registry - version: 6.0.1 - integrity: sha256-WssD3DbX4OPzxSdjvRMX0yvc9+pS7n5gyPv5I2Trb7k= - dependencies: - - arrays - - control - - either - - enums - - foldable-traversable - - gen - - integers - - maybe - - newtype - - nonempty - - partial - - prelude - - tailrec - - tuples - - unfoldable - - unsafe-coerce - tailrec: - type: registry - version: 6.1.0 - integrity: sha256-Xx19ECVDRrDWpz9D2GxQHHV89vd61dnXxQm0IcYQHGk= - dependencies: - - bifunctors - - effect - - either - - identity - - maybe - - partial - - prelude - - refs - transformers: - type: registry - version: 6.1.0 - integrity: sha256-3Bm+Z6tsC/paG888XkywDngJ2JMos+JfOhRlkVfb7gI= - dependencies: - - control - - distributive - - effect - - either - - exceptions - - foldable-traversable - - identity - - lazy - - maybe - - newtype - - prelude - - st - - tailrec - - tuples - - unfoldable - tuples: - type: registry - version: 7.0.0 - integrity: sha256-1rXgTomes9105BjgXqIw0FL6Fz1lqqUTLWOumhWec1M= - dependencies: - - control - - invariant - - prelude - type-equality: - type: registry - version: 4.0.1 - integrity: sha256-Hs9D6Y71zFi/b+qu5NSbuadUQXe5iv5iWx0226vOHUw= - dependencies: [] - unfoldable: - type: registry - version: 6.0.0 - integrity: sha256-JtikvJdktRap7vr/K4ITlxUX1QexpnqBq0G/InLr6eg= - dependencies: - - foldable-traversable - - maybe - - partial - - prelude - - tuples - unsafe-coerce: - type: registry - version: 6.0.0 - integrity: sha256-IqIYW4Vkevn8sI+6aUwRGvd87tVL36BBeOr0cGAE7t0= - dependencies: [] +{ + "workspace": { + "packages": { + "node-fs": { + "path": "./", + "core": { + "dependencies": [ + "aff", + "arrays", + "datetime", + "effect", + "either", + "enums", + "exceptions", + "functions", + "integers", + "js-date", + "maybe", + "node-buffer", + "node-path", + "node-streams", + "nullable", + "partial", + "prelude", + "refs", + "strings", + "tuples", + "unsafe-coerce" + ], + "build_plan": [ + "aff", + "arraybuffer-types", + "arrays", + "bifunctors", + "const", + "contravariant", + "control", + "datetime", + "distributive", + "effect", + "either", + "enums", + "exceptions", + "exists", + "foldable-traversable", + "foreign", + "functions", + "functors", + "gen", + "identity", + "integers", + "invariant", + "js-date", + "lazy", + "lists", + "maybe", + "newtype", + "node-buffer", + "node-event-emitter", + "node-path", + "node-streams", + "nonempty", + "now", + "nullable", + "numbers", + "ordered-collections", + "orders", + "parallel", + "partial", + "prelude", + "profunctor", + "refs", + "safe-coerce", + "st", + "strings", + "tailrec", + "transformers", + "tuples", + "type-equality", + "unfoldable", + "unsafe-coerce" + ] + }, + "test": { + "dependencies": [ + "aff", + "arrays", + "assert", + "console", + "foldable-traversable", + "node-event-emitter" + ], + "build_plan": [ + "aff", + "arrays", + "assert", + "bifunctors", + "console", + "const", + "contravariant", + "control", + "datetime", + "distributive", + "effect", + "either", + "enums", + "exceptions", + "exists", + "foldable-traversable", + "functions", + "functors", + "gen", + "identity", + "integers", + "invariant", + "lazy", + "lists", + "maybe", + "newtype", + "node-event-emitter", + "nonempty", + "nullable", + "numbers", + "ordered-collections", + "orders", + "parallel", + "partial", + "prelude", + "profunctor", + "refs", + "safe-coerce", + "st", + "tailrec", + "transformers", + "tuples", + "type-equality", + "unfoldable", + "unsafe-coerce" + ] + } + } + }, + "package_set": { + "address": { + "registry": "60.3.0" + }, + "compiler": ">=0.15.15 <0.16.0", + "content": { + "abc-parser": "2.0.1", + "ace": "9.1.0", + "address-rfc2821": "0.1.1", + "aff": "8.0.0", + "aff-bus": "6.0.0", + "aff-coroutines": "9.0.0", + "aff-promise": "4.0.0", + "aff-retry": "2.0.0", + "affjax": "13.0.0", + "affjax-node": "1.0.0", + "affjax-web": "1.0.0", + "ansi": "7.0.0", + "apexcharts": "0.5.0", + "applicative-phases": "1.0.0", + "argonaut": "9.0.0", + "argonaut-aeson-generic": "0.4.1", + "argonaut-codecs": "9.1.0", + "argonaut-core": "7.0.0", + "argonaut-generic": "8.0.0", + "argonaut-traversals": "10.0.0", + "argparse-basic": "2.0.0", + "array-builder": "0.1.2", + "array-search": "0.6.0", + "arraybuffer": "13.2.0", + "arraybuffer-builder": "3.1.0", + "arraybuffer-types": "3.0.2", + "arrays": "7.3.0", + "arrays-extra": "0.6.1", + "arrays-zipper": "2.0.1", + "ask": "1.0.0", + "assert": "6.0.0", + "assert-multiple": "0.4.0", + "avar": "5.0.0", + "b64": "0.0.8", + "barbies": "1.0.1", + "barlow-lens": "0.9.0", + "bifunctors": "6.0.0", + "bigints": "7.0.1", + "bolson": "0.3.9", + "bookhound": "0.1.7", + "bower-json": "3.0.0", + "call-by-name": "4.0.1", + "canvas": "6.0.0", + "canvas-action": "9.0.0", + "cartesian": "1.0.6", + "catenable-lists": "7.0.0", + "cbor-stream": "1.3.0", + "chameleon": "1.0.0", + "chameleon-halogen": "1.0.3", + "chameleon-react-basic": "1.1.0", + "chameleon-styled": "2.5.0", + "chameleon-transformers": "1.0.0", + "channel": "1.0.0", + "checked-exceptions": "3.1.1", + "choku": "1.0.1", + "classless": "0.1.1", + "classless-arbitrary": "0.1.1", + "classless-decode-json": "0.1.1", + "classless-encode-json": "0.1.3", + "classnames": "2.0.0", + "codec": "6.1.0", + "codec-argonaut": "10.0.0", + "codec-json": "2.0.0", + "colors": "7.0.1", + "concur-core": "0.5.0", + "concur-react": "0.5.0", + "concurrent-queues": "3.0.0", + "console": "6.1.0", + "const": "6.0.0", + "contravariant": "6.0.0", + "control": "6.0.0", + "convertable-options": "1.0.0", + "coroutines": "7.0.0", + "css": "6.0.0", + "css-frameworks": "1.0.1", + "csv-stream": "2.3.0", + "data-mvc": "0.0.2", + "datetime": "6.1.0", + "datetime-parsing": "0.2.0", + "debounce": "0.1.0", + "debug": "6.0.2", + "decimals": "7.1.0", + "default-values": "1.0.1", + "deku": "0.9.23", + "deno": "0.0.5", + "dissect": "1.0.0", + "distributive": "6.0.0", + "dom-filereader": "7.0.0", + "dom-indexed": "12.0.0", + "dom-simple": "0.4.0", + "dotenv": "4.0.3", + "droplet": "0.6.0", + "dts": "1.0.0", + "dual-numbers": "1.0.3", + "dynamic-buffer": "3.0.1", + "echarts-simple": "0.0.1", + "effect": "4.0.0", + "either": "6.1.0", + "elmish": "0.13.0", + "elmish-enzyme": "0.1.1", + "elmish-hooks": "0.10.3", + "elmish-html": "0.9.0", + "elmish-testing-library": "0.3.2", + "email-validate": "7.0.0", + "encoding": "0.0.9", + "enums": "6.0.1", + "env-names": "0.4.0", + "error": "2.0.0", + "eta-conversion": "0.3.2", + "exceptions": "6.1.0", + "exists": "6.0.0", + "exitcodes": "4.0.0", + "expect-inferred": "3.0.0", + "ezfetch": "1.0.0", + "fahrtwind": "2.0.0", + "fallback": "0.1.0", + "fast-vect": "1.2.0", + "fetch": "4.1.0", + "fetch-argonaut": "1.0.1", + "fetch-core": "5.1.0", + "fetch-yoga-json": "1.1.0", + "ffi-simple": "0.5.1", + "fft-js": "0.1.0", + "filterable": "5.0.0", + "fix-functor": "0.1.0", + "fixed-points": "7.0.0", + "fixed-precision": "5.0.0", + "flame": "1.3.0", + "float32": "2.0.0", + "fmt": "0.2.1", + "foldable-traversable": "6.0.0", + "foldable-traversable-extra": "0.0.6", + "foreign": "7.0.0", + "foreign-object": "4.1.0", + "foreign-readwrite": "3.4.0", + "forgetmenot": "0.1.0", + "fork": "6.0.0", + "form-urlencoded": "7.0.0", + "formatters": "7.0.0", + "framer-motion": "1.0.1", + "free": "7.1.0", + "freeap": "7.0.0", + "freer-free": "0.0.1", + "freet": "7.0.0", + "functions": "6.0.0", + "functor1": "3.0.0", + "functors": "5.0.0", + "fuzzy": "0.4.0", + "gen": "4.0.0", + "generate-values": "1.0.1", + "generic-router": "0.0.1", + "geojson": "0.0.5", + "geometria": "2.2.0", + "gojs": "0.1.1", + "grain": "3.0.0", + "grain-router": "3.0.0", + "grain-virtualized": "3.0.0", + "graphs": "8.1.0", + "group": "4.1.1", + "halogen": "7.0.0", + "halogen-bootstrap5": "5.3.2", + "halogen-canvas": "1.0.0", + "halogen-css": "10.0.0", + "halogen-echarts-simple": "0.0.4", + "halogen-formless": "4.0.3", + "halogen-helix": "1.0.1", + "halogen-hooks": "0.6.3", + "halogen-hooks-extra": "0.9.0", + "halogen-infinite-scroll": "1.1.0", + "halogen-store": "0.5.4", + "halogen-storybook": "2.0.0", + "halogen-subscriptions": "2.0.0", + "halogen-svg-elems": "8.0.0", + "halogen-typewriter": "1.0.4", + "halogen-vdom": "8.0.0", + "halogen-vdom-string-renderer": "0.5.0", + "halogen-xterm": "2.0.0", + "heckin": "2.0.1", + "heterogeneous": "0.6.0", + "homogeneous": "0.4.0", + "http-methods": "6.0.0", + "httpurple": "4.0.0", + "huffman": "0.4.0", + "humdrum": "0.0.1", + "hyrule": "2.3.8", + "identity": "6.0.0", + "identy": "4.0.1", + "indexed-db": "1.0.0", + "indexed-monad": "3.0.0", + "int64": "3.0.0", + "integers": "6.0.0", + "interpolate": "5.0.2", + "intersection-observer": "1.0.1", + "invariant": "6.0.0", + "jarilo": "1.0.1", + "jelly": "0.10.0", + "jelly-router": "0.3.0", + "jelly-signal": "0.4.0", + "jest": "1.0.0", + "js-abort-controller": "1.0.0", + "js-bigints": "2.2.1", + "js-date": "8.0.0", + "js-fetch": "0.2.1", + "js-fileio": "3.0.0", + "js-intl": "1.0.4", + "js-iterators": "0.1.1", + "js-maps": "0.1.2", + "js-promise": "1.0.0", + "js-promise-aff": "1.0.0", + "js-timers": "6.1.0", + "js-uri": "3.1.0", + "json": "1.1.0", + "json-codecs": "5.0.0", + "justifill": "0.5.0", + "jwt": "0.0.9", + "labeled-data": "0.2.0", + "language-cst-parser": "0.14.0", + "lazy": "6.0.0", + "lazy-joe": "1.0.0", + "lcg": "4.0.0", + "leibniz": "5.0.0", + "leveldb": "1.0.1", + "liminal": "1.0.1", + "linalg": "6.0.0", + "lists": "7.0.0", + "literals": "1.0.2", + "logging": "3.0.0", + "logging-journald": "0.4.0", + "lumi-components": "18.0.0", + "machines": "7.0.0", + "maps-eager": "0.5.0", + "marionette": "1.0.0", + "marionette-react-basic-hooks": "0.1.1", + "marked": "0.1.0", + "matrices": "5.0.1", + "matryoshka": "1.0.0", + "maybe": "6.0.0", + "media-types": "6.0.0", + "meowclient": "1.0.0", + "midi": "4.0.0", + "milkis": "9.0.0", + "minibench": "4.0.1", + "mmorph": "7.0.0", + "monad-control": "5.0.0", + "monad-logger": "1.3.1", + "monad-loops": "0.5.0", + "monad-unlift": "1.0.1", + "monoid-extras": "0.0.1", + "monoidal": "0.16.0", + "morello": "0.4.0", + "mote": "3.0.0", + "motsunabe": "2.0.0", + "mvc": "0.0.1", + "mysql": "6.0.1", + "n3": "0.1.0", + "nano-id": "1.1.0", + "nanoid": "0.1.0", + "naturals": "3.0.0", + "nested-functor": "0.2.1", + "newtype": "5.0.0", + "nextjs": "0.1.1", + "nextui": "0.2.0", + "node-buffer": "9.0.0", + "node-child-process": "11.1.0", + "node-event-emitter": "3.0.0", + "node-execa": "5.0.0", + "node-fs": "9.2.0", + "node-glob-basic": "1.3.0", + "node-http": "9.1.0", + "node-http2": "1.1.1", + "node-human-signals": "1.0.0", + "node-net": "5.1.0", + "node-os": "5.1.0", + "node-path": "5.0.0", + "node-process": "11.2.0", + "node-readline": "8.1.1", + "node-sqlite3": "8.0.0", + "node-stream-pipes": "2.1.6", + "node-streams": "9.0.0", + "node-tls": "0.3.1", + "node-url": "7.0.1", + "node-zlib": "0.4.0", + "nonempty": "7.0.0", + "now": "6.0.0", + "npm-package-json": "2.0.0", + "nullable": "6.0.0", + "numberfield": "0.2.2", + "numbers": "9.0.1", + "oak": "3.1.1", + "oak-debug": "1.2.2", + "object-maps": "0.3.0", + "ocarina": "1.5.4", + "oooooooooorrrrrrrmm-lib": "0.0.1", + "open-colors-scales-and-schemes": "1.0.0", + "open-folds": "6.4.0", + "open-foreign-generic": "11.0.3", + "open-memoize": "6.2.0", + "open-mkdirp-aff": "1.2.0", + "open-pairing": "6.2.0", + "open-smolder": "12.0.2", + "options": "7.0.0", + "optparse": "5.0.1", + "ordered-collections": "3.2.0", + "ordered-set": "0.4.0", + "orders": "6.0.0", + "owoify": "1.2.0", + "pairs": "9.0.1", + "parallel": "7.0.0", + "parsing": "10.2.0", + "parsing-dataview": "3.2.4", + "partial": "4.0.0", + "pathy": "9.0.0", + "pha": "0.13.0", + "phaser": "0.7.0", + "phylio": "1.1.2", + "pipes": "8.0.0", + "pirates-charm": "0.0.1", + "pmock": "0.9.0", + "point-free": "1.0.0", + "pointed-list": "0.5.1", + "polymorphic-vectors": "4.0.0", + "posix-types": "6.0.0", + "postgresql": "2.0.19", + "precise": "6.0.0", + "precise-datetime": "7.0.0", + "prelude": "6.0.1", + "prettier-printer": "3.0.0", + "priority-queue": "0.1.2", + "profunctor": "6.0.1", + "profunctor-lenses": "8.0.0", + "protobuf": "4.3.0", + "psa-utils": "8.0.0", + "psci-support": "6.0.0", + "punycode": "1.0.0", + "qualified-do": "2.2.0", + "quantities": "12.2.0", + "quickcheck": "8.0.1", + "quickcheck-combinators": "0.1.3", + "quickcheck-laws": "7.0.0", + "quickcheck-utf8": "0.0.0", + "random": "6.0.0", + "rationals": "6.0.0", + "rdf": "0.1.0", + "react": "11.0.0", + "react-aria": "0.2.0", + "react-basic": "17.0.0", + "react-basic-classic": "3.0.0", + "react-basic-dnd": "10.1.0", + "react-basic-dom": "6.1.0", + "react-basic-dom-beta": "0.1.1", + "react-basic-emotion": "7.1.0", + "react-basic-hooks": "8.2.0", + "react-basic-storybook": "2.0.0", + "react-dom": "8.0.0", + "react-halo": "3.0.0", + "react-icons": "1.1.5", + "react-markdown": "0.1.0", + "react-testing-library": "4.0.1", + "react-virtuoso": "1.0.0", + "reactix": "0.6.1", + "read": "1.0.1", + "recharts": "1.1.0", + "record": "4.0.0", + "record-extra": "5.0.1", + "record-ptional-fields": "0.1.2", + "record-studio": "1.0.4", + "refs": "6.0.0", + "remotedata": "5.0.1", + "repr": "0.5.0", + "resize-observer": "1.0.0", + "resource": "2.0.1", + "resourcet": "1.0.0", + "result": "1.0.3", + "return": "0.2.0", + "ring-modules": "5.0.1", + "rito": "0.3.4", + "roman": "0.4.0", + "rough-notation": "1.0.2", + "routing": "11.0.0", + "routing-duplex": "0.7.0", + "run": "5.0.0", + "safe-coerce": "2.0.0", + "safely": "4.0.1", + "school-of-music": "1.3.0", + "selection-foldable": "0.2.0", + "selective-functors": "1.0.1", + "semirings": "7.0.0", + "signal": "13.0.0", + "simple-emitter": "3.0.1", + "simple-i18n": "2.0.1", + "simple-json": "9.0.0", + "simple-json-generics": "0.2.1", + "simple-ulid": "3.0.0", + "sized-matrices": "1.0.0", + "sized-vectors": "5.0.2", + "slug": "3.1.0", + "small-ffi": "4.0.1", + "soundfonts": "4.1.0", + "sparse-matrices": "2.0.1", + "sparse-polynomials": "3.0.1", + "spec": "8.0.0", + "spec-discovery": "8.3.0", + "spec-mocha": "5.1.1", + "spec-node": "0.0.2", + "spec-quickcheck": "5.0.2", + "spec-reporter-xunit": "0.7.1", + "splitmix": "2.1.0", + "ssrs": "1.0.0", + "st": "6.2.0", + "statistics": "0.3.2", + "strictlypositiveint": "1.0.1", + "string-parsers": "8.0.0", + "strings": "6.0.1", + "strings-extra": "4.0.0", + "stringutils": "0.0.12", + "substitute": "0.2.3", + "supply": "0.2.0", + "svg-parser": "3.0.0", + "systemd-journald": "0.3.0", + "tagged": "4.0.2", + "tailrec": "6.1.0", + "tecton": "0.2.1", + "tecton-halogen": "0.2.0", + "test-unit": "17.0.0", + "thermite": "6.3.1", + "thermite-dom": "0.3.1", + "these": "6.0.0", + "threading": "0.0.3", + "tldr": "0.0.0", + "toestand": "0.9.0", + "transformation-matrix": "1.0.1", + "transformers": "6.1.0", + "tree-rose": "4.0.2", + "ts-bridge": "4.0.0", + "tuples": "7.0.0", + "two-or-more": "1.0.0", + "type-equality": "4.0.1", + "typedenv": "2.0.1", + "typelevel": "6.0.0", + "typelevel-lists": "2.1.0", + "typelevel-peano": "1.0.1", + "typelevel-prelude": "7.0.0", + "typelevel-regex": "0.0.3", + "typelevel-rows": "0.1.0", + "typisch": "0.4.0", + "uint": "7.0.0", + "ulid": "3.0.1", + "uncurried-transformers": "1.1.0", + "undefined": "2.0.0", + "undefined-is-not-a-problem": "1.1.0", + "unfoldable": "6.0.0", + "unicode": "6.0.0", + "unique": "0.6.1", + "unlift": "1.0.1", + "unordered-collections": "3.1.0", + "unsafe-coerce": "6.0.0", + "unsafe-reference": "5.0.0", + "untagged-to-tagged": "0.1.4", + "untagged-union": "1.0.0", + "uri": "9.0.0", + "url-immutable": "1.0.0", + "uuid": "9.0.0", + "uuidv4": "1.0.0", + "validation": "6.0.0", + "variant": "8.0.0", + "variant-encodings": "2.0.0", + "vectorfield": "1.0.1", + "vectors": "2.1.0", + "versions": "7.0.0", + "visx": "0.0.2", + "web-clipboard": "6.0.0", + "web-cssom": "2.0.0", + "web-cssom-view": "0.1.0", + "web-dom": "6.0.0", + "web-dom-parser": "8.0.0", + "web-dom-xpath": "3.0.0", + "web-encoding": "3.0.0", + "web-events": "4.0.0", + "web-fetch": "4.0.1", + "web-file": "4.0.0", + "web-geometry": "0.1.0", + "web-html": "4.1.0", + "web-pointerevents": "2.0.0", + "web-proletarian": "1.0.0", + "web-promise": "3.2.0", + "web-resize-observer": "2.1.0", + "web-router": "1.0.0", + "web-socket": "4.0.0", + "web-storage": "5.0.0", + "web-streams": "4.0.0", + "web-touchevents": "4.0.0", + "web-uievents": "5.0.0", + "web-url": "2.0.0", + "web-workers": "1.1.0", + "web-xhr": "5.0.1", + "webextension-polyfill": "0.1.0", + "webgpu": "0.0.1", + "which": "2.0.0", + "xterm": "1.0.0", + "yoga-fetch": "1.0.1", + "yoga-json": "5.1.0", + "yoga-om": "0.1.0", + "yoga-postgres": "6.0.0", + "yoga-tree": "1.0.0", + "z3": "0.0.2", + "zipperarray": "2.0.0" + } + }, + "extra_packages": {} + }, + "packages": { + "aff": { + "type": "registry", + "version": "8.0.0", + "integrity": "sha256-5MmdI4+0RHBtSBy+YlU3/Cq4R5W2ih3OaRedJIrVHdk=", + "dependencies": [ + "bifunctors", + "control", + "datetime", + "effect", + "either", + "exceptions", + "foldable-traversable", + "functions", + "maybe", + "newtype", + "parallel", + "prelude", + "refs", + "tailrec", + "transformers", + "unsafe-coerce" + ] + }, + "arraybuffer-types": { + "type": "registry", + "version": "3.0.2", + "integrity": "sha256-mQKokysYVkooS4uXbO+yovmV/s8b138Ws3zQvOwIHRA=", + "dependencies": [] + }, + "arrays": { + "type": "registry", + "version": "7.3.0", + "integrity": "sha256-tmcklBlc/muUtUfr9RapdCPwnlQeB3aSrC4dK85gQlc=", + "dependencies": [ + "bifunctors", + "control", + "foldable-traversable", + "functions", + "maybe", + "nonempty", + "partial", + "prelude", + "safe-coerce", + "st", + "tailrec", + "tuples", + "unfoldable", + "unsafe-coerce" + ] + }, + "assert": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-hCSYcCw9kj3qujoDcriWhCdmrpPZoguSPDZhEMnTl3A=", + "dependencies": [ + "console", + "effect", + "prelude" + ] + }, + "bifunctors": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-/gZwC9YhNxZNQpnHa5BIYerCGM2jeX9ukZiEvYxm5Nw=", + "dependencies": [ + "const", + "either", + "newtype", + "prelude", + "tuples" + ] + }, + "console": { + "type": "registry", + "version": "6.1.0", + "integrity": "sha256-CxmAzjgyuGDmt9FZW51VhV6rBPwR6o0YeKUzA9rSzcM=", + "dependencies": [ + "effect", + "prelude" + ] + }, + "const": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-tNrxDW8D8H4jdHE2HiPzpLy08zkzJMmGHdRqt5BQuTc=", + "dependencies": [ + "invariant", + "newtype", + "prelude" + ] + }, + "contravariant": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-TP+ooAp3vvmdjfQsQJSichF5B4BPDHp3wAJoWchip6c=", + "dependencies": [ + "const", + "either", + "newtype", + "prelude", + "tuples" + ] + }, + "control": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-sH7Pg9E96JCPF9PIA6oQ8+BjTyO/BH1ZuE/bOcyj4Jk=", + "dependencies": [ + "newtype", + "prelude" + ] + }, + "datetime": { + "type": "registry", + "version": "6.1.0", + "integrity": "sha256-g/5X5BBegQWLpI9IWD+sY6mcaYpzzlW5lz5NBzaMtyI=", + "dependencies": [ + "bifunctors", + "control", + "either", + "enums", + "foldable-traversable", + "functions", + "gen", + "integers", + "lists", + "maybe", + "newtype", + "numbers", + "ordered-collections", + "partial", + "prelude", + "tuples" + ] + }, + "distributive": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-HTDdmEnzigMl+02SJB88j+gAXDx9VKsbvR4MJGDPbOQ=", + "dependencies": [ + "identity", + "newtype", + "prelude", + "tuples", + "type-equality" + ] + }, + "effect": { + "type": "registry", + "version": "4.0.0", + "integrity": "sha256-eBtZu+HZcMa5HilvI6kaDyVX3ji8p0W9MGKy2K4T6+M=", + "dependencies": [ + "prelude" + ] + }, + "either": { + "type": "registry", + "version": "6.1.0", + "integrity": "sha256-6hgTPisnMWVwQivOu2PKYcH8uqjEOOqDyaDQVUchTpY=", + "dependencies": [ + "control", + "invariant", + "maybe", + "prelude" + ] + }, + "enums": { + "type": "registry", + "version": "6.0.1", + "integrity": "sha256-HWaD73JFLorc4A6trKIRUeDMdzE+GpkJaEOM1nTNkC8=", + "dependencies": [ + "control", + "either", + "gen", + "maybe", + "newtype", + "nonempty", + "partial", + "prelude", + "tuples", + "unfoldable" + ] + }, + "exceptions": { + "type": "registry", + "version": "6.1.0", + "integrity": "sha256-K0T89IHtF3vBY7eSAO7eDOqSb2J9kZGAcDN5+IKsF8E=", + "dependencies": [ + "effect", + "either", + "maybe", + "prelude" + ] + }, + "exists": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-A0JQHpTfo1dNOj9U5/Fd3xndlRSE0g2IQWOGor2yXn8=", + "dependencies": [ + "unsafe-coerce" + ] + }, + "foldable-traversable": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-fLeqRYM4jUrZD5H4WqcwUgzU7XfYkzO4zhgtNc3jcWM=", + "dependencies": [ + "bifunctors", + "const", + "control", + "either", + "functors", + "identity", + "maybe", + "newtype", + "orders", + "prelude", + "tuples" + ] + }, + "foreign": { + "type": "registry", + "version": "7.0.0", + "integrity": "sha256-1ORiqoS3HW+qfwSZAppHPWy4/6AQysxZ2t29jcdUMNA=", + "dependencies": [ + "either", + "functions", + "identity", + "integers", + "lists", + "maybe", + "prelude", + "strings", + "transformers" + ] + }, + "functions": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-adMyJNEnhGde2unHHAP79gPtlNjNqzgLB8arEOn9hLI=", + "dependencies": [ + "prelude" + ] + }, + "functors": { + "type": "registry", + "version": "5.0.0", + "integrity": "sha256-zfPWWYisbD84MqwpJSZFlvM6v86McM68ob8p9s27ywU=", + "dependencies": [ + "bifunctors", + "const", + "contravariant", + "control", + "distributive", + "either", + "invariant", + "maybe", + "newtype", + "prelude", + "profunctor", + "tuples", + "unsafe-coerce" + ] + }, + "gen": { + "type": "registry", + "version": "4.0.0", + "integrity": "sha256-f7yzAXWwr+xnaqEOcvyO3ezKdoes8+WXWdXIHDBCAPI=", + "dependencies": [ + "either", + "foldable-traversable", + "identity", + "maybe", + "newtype", + "nonempty", + "prelude", + "tailrec", + "tuples", + "unfoldable" + ] + }, + "identity": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-4wY0XZbAksjY6UAg99WkuKyJlQlWAfTi2ssadH0wVMY=", + "dependencies": [ + "control", + "invariant", + "newtype", + "prelude" + ] + }, + "integers": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-sf+sK26R1hzwl3NhXR7WAu9zCDjQnfoXwcyGoseX158=", + "dependencies": [ + "maybe", + "numbers", + "prelude" + ] + }, + "invariant": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-RGWWyYrz0Hs1KjPDA+87Kia67ZFBhfJ5lMGOMCEFoLo=", + "dependencies": [ + "control", + "prelude" + ] + }, + "js-date": { + "type": "registry", + "version": "8.0.0", + "integrity": "sha256-6TVF4DWg5JL+jRAsoMssYw8rgOVALMUHT1CuNZt8NRo=", + "dependencies": [ + "datetime", + "effect", + "exceptions", + "foreign", + "integers", + "now" + ] + }, + "lazy": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-lMsfFOnlqfe4KzRRiW8ot5ge6HtcU3Eyh2XkXcP5IgU=", + "dependencies": [ + "control", + "foldable-traversable", + "invariant", + "prelude" + ] + }, + "lists": { + "type": "registry", + "version": "7.0.0", + "integrity": "sha256-EKF15qYqucuXP2lT/xPxhqy58f0FFT6KHdIB/yBOayI=", + "dependencies": [ + "bifunctors", + "control", + "foldable-traversable", + "lazy", + "maybe", + "newtype", + "nonempty", + "partial", + "prelude", + "tailrec", + "tuples", + "unfoldable" + ] + }, + "maybe": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-5cCIb0wPwbat2PRkQhUeZO0jcAmf8jCt2qE0wbC3v2Q=", + "dependencies": [ + "control", + "invariant", + "newtype", + "prelude" + ] + }, + "newtype": { + "type": "registry", + "version": "5.0.0", + "integrity": "sha256-gdrQu8oGe9eZE6L3wOI8ql/igOg+zEGB5ITh2g+uttw=", + "dependencies": [ + "prelude", + "safe-coerce" + ] + }, + "node-buffer": { + "type": "registry", + "version": "9.0.0", + "integrity": "sha256-PWE2DJ5ruBLCmeA/fUiuySEFmUJ/VuRfyrnCuVZBlu4=", + "dependencies": [ + "arraybuffer-types", + "effect", + "maybe", + "nullable", + "st", + "unsafe-coerce" + ] + }, + "node-event-emitter": { + "type": "registry", + "version": "3.0.0", + "integrity": "sha256-Qw0MjsT4xRH2j2i4K8JmRjcMKnH5z1Cw39t00q4LE4w=", + "dependencies": [ + "effect", + "either", + "functions", + "maybe", + "nullable", + "prelude", + "unsafe-coerce" + ] + }, + "node-path": { + "type": "registry", + "version": "5.0.0", + "integrity": "sha256-pd82nQ+2l5UThzaxPdKttgDt7xlsgIDLpPG0yxDEdyE=", + "dependencies": [ + "effect" + ] + }, + "node-streams": { + "type": "registry", + "version": "9.0.0", + "integrity": "sha256-2n6dq7YWleTDmD1Kur/ul7Cn08IvWrScgPf+0PgX2TQ=", + "dependencies": [ + "aff", + "effect", + "either", + "exceptions", + "node-buffer", + "node-event-emitter", + "nullable", + "prelude" + ] + }, + "nonempty": { + "type": "registry", + "version": "7.0.0", + "integrity": "sha256-54ablJZUHGvvlTJzi3oXyPCuvY6zsrWJuH/dMJ/MFLs=", + "dependencies": [ + "control", + "foldable-traversable", + "maybe", + "prelude", + "tuples", + "unfoldable" + ] + }, + "now": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-xZ7x37ZMREfs6GCDw/h+FaKHV/3sPWmtqBZRGTxybQY=", + "dependencies": [ + "datetime", + "effect" + ] + }, + "nullable": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-yiGBVl3AD+Guy4kNWWeN+zl1gCiJK+oeIFtZtPCw4+o=", + "dependencies": [ + "effect", + "functions", + "maybe" + ] + }, + "numbers": { + "type": "registry", + "version": "9.0.1", + "integrity": "sha256-/9M6aeMDBdB4cwYDeJvLFprAHZ49EbtKQLIJsneXLIk=", + "dependencies": [ + "functions", + "maybe" + ] + }, + "ordered-collections": { + "type": "registry", + "version": "3.2.0", + "integrity": "sha256-o9jqsj5rpJmMdoe/zyufWHFjYYFTTsJpgcuCnqCO6PM=", + "dependencies": [ + "arrays", + "foldable-traversable", + "gen", + "lists", + "maybe", + "partial", + "prelude", + "st", + "tailrec", + "tuples", + "unfoldable" + ] + }, + "orders": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-nBA0g3/ai0euH8q9pSbGqk53W2q6agm/dECZTHcoink=", + "dependencies": [ + "newtype", + "prelude" + ] + }, + "parallel": { + "type": "registry", + "version": "7.0.0", + "integrity": "sha256-gUC9i4Txnx9K9RcMLsjujbwZz6BB1bnE2MLvw4GIw5o=", + "dependencies": [ + "control", + "effect", + "either", + "foldable-traversable", + "functors", + "maybe", + "newtype", + "prelude", + "profunctor", + "refs", + "transformers" + ] + }, + "partial": { + "type": "registry", + "version": "4.0.0", + "integrity": "sha256-fwXerld6Xw1VkReh8yeQsdtLVrjfGiVuC5bA1Wyo/J4=", + "dependencies": [] + }, + "prelude": { + "type": "registry", + "version": "6.0.1", + "integrity": "sha256-o8p6SLYmVPqzXZhQFd2hGAWEwBoXl1swxLG/scpJ0V0=", + "dependencies": [] + }, + "profunctor": { + "type": "registry", + "version": "6.0.1", + "integrity": "sha256-E58hSYdJvF2Qjf9dnWLPlJKh2Z2fLfFLkQoYi16vsFk=", + "dependencies": [ + "control", + "distributive", + "either", + "exists", + "invariant", + "newtype", + "prelude", + "tuples" + ] + }, + "refs": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-Vgwne7jIbD3ZMoLNNETLT8Litw6lIYo3MfYNdtYWj9s=", + "dependencies": [ + "effect", + "prelude" + ] + }, + "safe-coerce": { + "type": "registry", + "version": "2.0.0", + "integrity": "sha256-a1ibQkiUcbODbLE/WAq7Ttbbh9ex+x33VCQ7GngKudU=", + "dependencies": [ + "unsafe-coerce" + ] + }, + "st": { + "type": "registry", + "version": "6.2.0", + "integrity": "sha256-z9X0WsOUlPwNx9GlCC+YccCyz8MejC8Wb0C4+9fiBRY=", + "dependencies": [ + "partial", + "prelude", + "tailrec", + "unsafe-coerce" + ] + }, + "strings": { + "type": "registry", + "version": "6.0.1", + "integrity": "sha256-WssD3DbX4OPzxSdjvRMX0yvc9+pS7n5gyPv5I2Trb7k=", + "dependencies": [ + "arrays", + "control", + "either", + "enums", + "foldable-traversable", + "gen", + "integers", + "maybe", + "newtype", + "nonempty", + "partial", + "prelude", + "tailrec", + "tuples", + "unfoldable", + "unsafe-coerce" + ] + }, + "tailrec": { + "type": "registry", + "version": "6.1.0", + "integrity": "sha256-Xx19ECVDRrDWpz9D2GxQHHV89vd61dnXxQm0IcYQHGk=", + "dependencies": [ + "bifunctors", + "effect", + "either", + "identity", + "maybe", + "partial", + "prelude", + "refs" + ] + }, + "transformers": { + "type": "registry", + "version": "6.1.0", + "integrity": "sha256-3Bm+Z6tsC/paG888XkywDngJ2JMos+JfOhRlkVfb7gI=", + "dependencies": [ + "control", + "distributive", + "effect", + "either", + "exceptions", + "foldable-traversable", + "identity", + "lazy", + "maybe", + "newtype", + "prelude", + "st", + "tailrec", + "tuples", + "unfoldable" + ] + }, + "tuples": { + "type": "registry", + "version": "7.0.0", + "integrity": "sha256-1rXgTomes9105BjgXqIw0FL6Fz1lqqUTLWOumhWec1M=", + "dependencies": [ + "control", + "invariant", + "prelude" + ] + }, + "type-equality": { + "type": "registry", + "version": "4.0.1", + "integrity": "sha256-Hs9D6Y71zFi/b+qu5NSbuadUQXe5iv5iWx0226vOHUw=", + "dependencies": [] + }, + "unfoldable": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-JtikvJdktRap7vr/K4ITlxUX1QexpnqBq0G/InLr6eg=", + "dependencies": [ + "foldable-traversable", + "maybe", + "partial", + "prelude", + "tuples" + ] + }, + "unsafe-coerce": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-IqIYW4Vkevn8sI+6aUwRGvd87tVL36BBeOr0cGAE7t0=", + "dependencies": [] + } + } +} diff --git a/spago.yaml b/spago.yaml index c754890..a37a130 100644 --- a/spago.yaml +++ b/spago.yaml @@ -39,5 +39,5 @@ package: - node-event-emitter workspace: packageSet: - registry: 60.2.1 + registry: 60.3.0 extraPackages: {} From 2cc9b29709182682971a701401fa09b8bf349adf Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Sat, 5 Oct 2024 19:05:45 +0700 Subject: [PATCH 07/32] feat: opendirOptionsDefault --- src/Node/FS/Aff.purs | 10 +++++----- src/Node/FS/Async.purs | 39 ++++++++++++++++++++++++++++++--------- test/Test.purs | 2 ++ test/TestDirEntries.purs | 7 ++++--- 4 files changed, 41 insertions(+), 17 deletions(-) diff --git a/src/Node/FS/Aff.purs b/src/Node/FS/Aff.purs index 8417ce9..37ddf91 100644 --- a/src/Node/FS/Aff.purs +++ b/src/Node/FS/Aff.purs @@ -83,8 +83,8 @@ import Effect.Aff (Aff, Error, makeAff, nonCanceler) import Node.Buffer (Buffer) import Node.Encoding (Encoding) import Node.FS as F -import Node.FS.Async (CpOptions) -import Node.FS.Async (CpOptions, CpForce(..), cpOptionsDefault) as Exports +import Node.FS.Async (CpOptions, CpForce(..), cpOptionsDefault, OpendirOptions , opendirOptionsDefault, RmOptions, rmOptionsDefault, RmdirOptions, rmdirOptionsDefault) as Exports +import Node.FS.Async (CpOptions, OpendirOptions, RmdirOptions, RmOptions) import Node.FS.Async as A import Node.FS.Constants (AccessMode, CopyMode) import Node.FS.Dir (Dir) @@ -264,7 +264,7 @@ rmdir = toAff1 A.rmdir -- | -- | Deletes a directory with options. -- | -rmdir' :: FilePath -> { maxRetries :: Int, retryDelay :: Int } -> Aff Unit +rmdir' :: FilePath -> RmdirOptions -> Aff Unit rmdir' = toAff2 A.rmdir' -- | @@ -276,7 +276,7 @@ rm = toAff1 A.rm -- | -- | Deletes a file or directory with options. -- | -rm' :: FilePath -> { force :: Boolean, maxRetries :: Int, recursive :: Boolean, retryDelay :: Int } -> Aff Unit +rm' :: FilePath -> RmOptions -> Aff Unit rm' = toAff2 A.rm' -- | @@ -502,7 +502,7 @@ opendir = toAff1 A.opendir -- | Open a directory. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_opendir_path_options_callback) -- | for details. -opendir' :: FilePath -> { bufferSize :: Int, recursive :: Boolean, encoding :: Encoding } -> Aff Dir +opendir' :: FilePath -> OpendirOptions -> Aff Dir opendir' = toAff2 A.opendir' -- | Read from a file descriptor into a buffer array. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_readv_fd_buffers_position_callback) diff --git a/src/Node/FS/Async.purs b/src/Node/FS/Async.purs index d725037..b02a76e 100644 --- a/src/Node/FS/Async.purs +++ b/src/Node/FS/Async.purs @@ -20,8 +20,12 @@ module Node.FS.Async , unlink , rmdir , rmdir' + , rmdirOptionsDefault + , RmdirOptions , rm , rm' + , rmOptionsDefault + , RmOptions , mkdir , mkdir' , readdir @@ -65,8 +69,10 @@ module Node.FS.Async , lchown , lutimes -- , openAsBlob - , opendir' , opendir + , opendir' + , OpendirOptions + , opendirOptionsDefault , readv , statfs -- , unwatchFile @@ -158,8 +164,8 @@ foreign import symlinkImpl :: EffectFn4 FilePath FilePath (Nullable String) (JSC foreign import readlinkImpl :: EffectFn2 FilePath (JSCallback FilePath) Unit foreign import realpathImpl :: forall cache. EffectFn3 FilePath { | cache } (JSCallback FilePath) Unit foreign import unlinkImpl :: EffectFn2 FilePath (JSCallback Unit) Unit -foreign import rmdirImpl :: EffectFn3 FilePath { maxRetries :: Int, retryDelay :: Int } (JSCallback Unit) Unit -foreign import rmImpl :: EffectFn3 FilePath { force :: Boolean, maxRetries :: Int, recursive :: Boolean, retryDelay :: Int } (JSCallback Unit) Unit +foreign import rmdirImpl :: EffectFn3 FilePath RmdirOptions (JSCallback Unit) Unit +foreign import rmImpl :: EffectFn3 FilePath RmOptions (JSCallback Unit) Unit foreign import mkdirImpl :: EffectFn3 FilePath { recursive :: Boolean, mode :: String } (JSCallback Unit) Unit -- if { withFileTypes: false, recursive: false } => ['Tidy'] -- if { withFileTypes: false, recursive: true } => [ 'Tidy', 'Tidy/Codegen', 'Tidy/Codegen.purs', 'Tidy/Codegen/Class.purs', .. ] @@ -290,32 +296,42 @@ unlink -> Effect Unit unlink file cb = runEffectFn2 unlinkImpl file (handleCallback cb) +type RmdirOptions = { maxRetries :: Int, retryDelay :: Int } + +rmdirOptionsDefault :: RmdirOptions +rmdirOptionsDefault = { maxRetries: 0, retryDelay: 100 } + -- | Deletes a directory. rmdir :: FilePath -> Callback Unit -> Effect Unit -rmdir path cb = rmdir' path { maxRetries: 0, retryDelay: 100 } cb +rmdir path cb = rmdir' path rmdirOptionsDefault cb -- | Deletes a directory with options. rmdir' :: FilePath - -> { maxRetries :: Int, retryDelay :: Int } + -> RmdirOptions -> Callback Unit -> Effect Unit rmdir' path opts cb = runEffectFn3 rmdirImpl path opts (handleCallback cb) +type RmOptions = { force :: Boolean, maxRetries :: Int, recursive :: Boolean, retryDelay :: Int } + +rmOptionsDefault :: RmOptions +rmOptionsDefault = { force: false, maxRetries: 100, recursive: false, retryDelay: 1000 } + -- | Deletes a file or directory. rm :: FilePath -> Callback Unit -> Effect Unit -rm path = rm' path { force: false, maxRetries: 100, recursive: false, retryDelay: 1000 } +rm path = rm' path rmOptionsDefault -- | Deletes a file or directory with options. rm' :: FilePath - -> { force :: Boolean, maxRetries :: Int, recursive :: Boolean, retryDelay :: Int } + -> RmOptions -> Callback Unit -> Effect Unit rm' path opts cb = runEffectFn3 rmImpl path opts (handleCallback cb) @@ -655,16 +671,21 @@ lutimes file atime mtime cb = runEffectFn4 lutimesImpl file (datetimeToUnixEpoch -- openAsBlob :: FilePath -> Promise Blob -> Effect Unit -- openAsBlob path cb = runEffectFn2 openAsBlobImpl path (handleCallback cb) +type OpendirOptions = { encoding :: Encoding, bufferSize :: Int, recursive :: Boolean } + +opendirOptionsDefault :: OpendirOptions +opendirOptionsDefault = { bufferSize: 32, recursive: false, encoding: UTF8 } + -- | Open a directory. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_opendir_path_options_callback) -- | for details. -opendir' :: FilePath -> { encoding :: Encoding, bufferSize :: Int, recursive :: Boolean } -> Callback Dir -> Effect Unit +opendir' :: FilePath -> OpendirOptions -> Callback Dir -> Effect Unit opendir' path { encoding, bufferSize, recursive } cb = runEffectFn3 opendirImpl path { encoding: encodingToNode encoding, bufferSize, recursive } (handleCallback cb) -- | Open a directory. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_opendir_path_options_callback) -- | for details. -- | NOTE: encoding: 'buffer' is not supported, will throw error "TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received an instance of Buffer" opendir :: FilePath -> Callback Dir -> Effect Unit -opendir path = opendir' path { bufferSize: 32, recursive: false, encoding: UTF8 } +opendir path = opendir' path opendirOptionsDefault -- | Read from a file descriptor into a buffer array. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_readv_fd_buffers_position_callback) -- | for details. diff --git a/test/Test.purs b/test/Test.purs index 1d1d2aa..4606f29 100644 --- a/test/Test.purs +++ b/test/Test.purs @@ -11,6 +11,7 @@ import Effect.Exception (Error, catchException, error, message, throw, throwExce import Node.Buffer as Buffer import Node.Encoding (Encoding(..)) import Node.FS (FileFlags(..), SymlinkType(..)) +import Node.FS.Aff (rmOptionsDefault) import Node.FS.Async as A import Node.FS.Constants (copyFile_EXCL, r_OK, w_OK) import Node.FS.Perms (mkPerms, permsAll) @@ -80,6 +81,7 @@ main = do log "statusChangedTime:" log $ show $ statusChangedTime stats + S.rm' (fp [ "tmp", "TestSymlink.js" ]) (rmOptionsDefault { force = true }) S.symlink (fp [ "tmp", "Test1.js" ]) (fp [ "tmp", "TestSymlink.js" ]) FileLink lstats <- S.lstat (fp [ "tmp", "TestSymlink.js" ]) diff --git a/test/TestDirEntries.purs b/test/TestDirEntries.purs index 5f4f177..977a5e5 100644 --- a/test/TestDirEntries.purs +++ b/test/TestDirEntries.purs @@ -11,6 +11,7 @@ import Effect.Class (liftEffect) import Effect.Console (log) import Effect.Exception (Error) import Node.Encoding (Encoding(..)) +import Node.FS.Aff (opendirOptionsDefault, rmOptionsDefault) import Node.FS.Aff as A import Node.FS.Aff.Dir (close, entries, read) import Node.FS.Dirent (Dirent, DirentNameTypeString) @@ -24,7 +25,7 @@ outerTmpDir = "./tmp/dir-entries-test" prepare :: Aff Unit prepare = do - A.rm' outerTmpDir { force: true, maxRetries: 100, recursive: true, retryDelay: 1000 } + A.rm' outerTmpDir (rmOptionsDefault { recursive = true, force = true }) A.mkdir' outerTmpDir { recursive: true, mode: permsAll } A.writeTextFile UTF8 (Path.concat [ outerTmpDir, "1.txt" ]) "1" A.writeTextFile UTF8 (Path.concat [ outerTmpDir, "2.txt" ]) "2" @@ -34,7 +35,7 @@ prepare = do test1 :: Aff Unit test1 = do - dir <- A.opendir' outerTmpDir { bufferSize: 32, recursive: true, encoding: UTF8 } + dir <- A.opendir' outerTmpDir (opendirOptionsDefault { recursive = true }) files' <- entries dir liftEffect $ assertEqual { actual: show files' @@ -74,7 +75,7 @@ test1 = do test2 :: Aff Unit test2 = do - dir <- A.opendir' outerTmpDir { bufferSize: 32, recursive: false, encoding: UTF8 } + dir <- A.opendir' outerTmpDir (opendirOptionsDefault { recursive = false }) read dir >>= \file -> liftEffect $ assertEqual { actual: show file , expected: "(Just Dirent Dirent {\n name: 'dir1',\n parentPath: './tmp/dir-entries-test',\n path: './tmp/dir-entries-test',\n [Symbol(type)]: 2\n})" From 13cf95d3137747670172fec892f3e7b5b1a66e0c Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Sun, 6 Oct 2024 10:07:05 +0700 Subject: [PATCH 08/32] refactor: tests -> move, use Test dir like specified in spago documentation --- test/Main.purs | 18 --------------- test/Test/Main.purs | 18 +++++++++++++++ test/{TestAff.purs => Test/Node/FS/Aff.purs} | 2 +- .../Node/FS/Async.purs} | 6 ++--- .../Node/FS/OpendirAndDir.purs} | 23 ++++++++++--------- test/{ => Test/Node/FS}/Streams.purs | 6 ++--- test/{Test.purs => Test/Node/FS/Sync.purs} | 13 +++++------ 7 files changed, 43 insertions(+), 43 deletions(-) delete mode 100644 test/Main.purs create mode 100644 test/Test/Main.purs rename test/{TestAff.purs => Test/Node/FS/Aff.purs} (94%) rename test/{TestAsync.purs => Test/Node/FS/Async.purs} (90%) rename test/{TestDirEntries.purs => Test/Node/FS/OpendirAndDir.purs} (84%) rename test/{ => Test/Node/FS}/Streams.purs (74%) rename test/{Test.purs => Test/Node/FS/Sync.purs} (93%) diff --git a/test/Main.purs b/test/Main.purs deleted file mode 100644 index c2e36e1..0000000 --- a/test/Main.purs +++ /dev/null @@ -1,18 +0,0 @@ -module Test.Main where - -import Prelude - -import Effect (Effect) -import Test as Test -import Test.Streams as Streams -import TestAff as TestAff -import TestAsync as TestAsync -import TestDirEntries as TestDirEntries - -main :: Effect Unit -main = do - Test.main - TestAsync.main - Streams.main - TestAff.main - TestDirEntries.main diff --git a/test/Test/Main.purs b/test/Test/Main.purs new file mode 100644 index 0000000..a45b14a --- /dev/null +++ b/test/Test/Main.purs @@ -0,0 +1,18 @@ +module Test.Main where + +import Prelude + +import Effect (Effect) +import Test.Node.FS.Sync as Sync +import Test.Node.FS.Streams as Streams +import Test.Node.FS.Aff as Aff +import Test.Node.FS.Async as Async +import Test.Node.FS.OpendirAndDir as OpendirAndDir + +main :: Effect Unit +main = do + Sync.main + Async.main + Streams.main + Aff.main + OpendirAndDir.main diff --git a/test/TestAff.purs b/test/Test/Node/FS/Aff.purs similarity index 94% rename from test/TestAff.purs rename to test/Test/Node/FS/Aff.purs index 4feea61..44bd244 100644 --- a/test/TestAff.purs +++ b/test/Test/Node/FS/Aff.purs @@ -1,4 +1,4 @@ -module TestAff where +module Test.Node.FS.Aff where import Prelude diff --git a/test/TestAsync.purs b/test/Test/Node/FS/Async.purs similarity index 90% rename from test/TestAsync.purs rename to test/Test/Node/FS/Async.purs index d44f790..a1b1d7d 100644 --- a/test/TestAsync.purs +++ b/test/Test/Node/FS/Async.purs @@ -1,4 +1,4 @@ -module TestAsync where +module Test.Node.FS.Async where import Prelude (Unit, show, bind, discard, (<>), ($)) import Data.Either (Either(..)) @@ -15,8 +15,8 @@ import Node.Buffer as B main :: Effect Unit main = do let - path1 = FP.concat ([ "test", "TestAsync.purs" ]) - path2 = FP.concat ([ "test", "TestAsync.purs.partial" ]) + path1 = FP.concat ([ "test", "Test", "Node", "FS", "Async.purs" ]) + path2 = FP.concat ([ "test", "Test", "Node", "FS", "Async.purs.partial" ]) buf <- B.create 1000 diff --git a/test/TestDirEntries.purs b/test/Test/Node/FS/OpendirAndDir.purs similarity index 84% rename from test/TestDirEntries.purs rename to test/Test/Node/FS/OpendirAndDir.purs index 977a5e5..85487ee 100644 --- a/test/TestDirEntries.purs +++ b/test/Test/Node/FS/OpendirAndDir.purs @@ -1,4 +1,4 @@ -module TestDirEntries where +module Test.Node.FS.OpendirAndDir where import Prelude @@ -21,7 +21,8 @@ import Node.Path as Path import Test.Assert (assertEqual) outerTmpDir :: FilePath -outerTmpDir = "./tmp/dir-entries-test" +outerTmpDir = Path.concat ["tmp", "dir-entries-test"] +-- outerTmpDir = Path.concat [".", "tmp", "dir-entries-test"] prepare :: Aff Unit prepare = do @@ -42,18 +43,18 @@ test1 = do , expected: """[Dirent Dirent { name: 'dir1', - parentPath: './tmp/dir-entries-test', - path: './tmp/dir-entries-test', + parentPath: 'tmp/dir-entries-test', + path: 'tmp/dir-entries-test', [Symbol(type)]: 2 },Dirent Dirent { name: '1.txt', - parentPath: './tmp/dir-entries-test', - path: './tmp/dir-entries-test', + parentPath: 'tmp/dir-entries-test', + path: 'tmp/dir-entries-test', [Symbol(type)]: 1 },Dirent Dirent { name: '2.txt', - parentPath: './tmp/dir-entries-test', - path: './tmp/dir-entries-test', + parentPath: 'tmp/dir-entries-test', + path: 'tmp/dir-entries-test', [Symbol(type)]: 1 },Dirent Dirent { name: '3.txt', @@ -78,15 +79,15 @@ test2 = do dir <- A.opendir' outerTmpDir (opendirOptionsDefault { recursive = false }) read dir >>= \file -> liftEffect $ assertEqual { actual: show file - , expected: "(Just Dirent Dirent {\n name: 'dir1',\n parentPath: './tmp/dir-entries-test',\n path: './tmp/dir-entries-test',\n [Symbol(type)]: 2\n})" + , expected: "(Just Dirent Dirent {\n name: 'dir1',\n parentPath: 'tmp/dir-entries-test',\n path: 'tmp/dir-entries-test',\n [Symbol(type)]: 2\n})" } read dir >>= \file -> liftEffect $ assertEqual { actual: show file - , expected: "(Just Dirent Dirent {\n name: '1.txt',\n parentPath: './tmp/dir-entries-test',\n path: './tmp/dir-entries-test',\n [Symbol(type)]: 1\n})" + , expected: "(Just Dirent Dirent {\n name: '1.txt',\n parentPath: 'tmp/dir-entries-test',\n path: 'tmp/dir-entries-test',\n [Symbol(type)]: 1\n})" } read dir >>= \file -> liftEffect $ assertEqual { actual: show file - , expected: "(Just Dirent Dirent {\n name: '2.txt',\n parentPath: './tmp/dir-entries-test',\n path: './tmp/dir-entries-test',\n [Symbol(type)]: 1\n})" + , expected: "(Just Dirent Dirent {\n name: '2.txt',\n parentPath: 'tmp/dir-entries-test',\n path: 'tmp/dir-entries-test',\n [Symbol(type)]: 1\n})" } read dir >>= \file -> liftEffect $ assertEqual { actual: show file diff --git a/test/Streams.purs b/test/Test/Node/FS/Streams.purs similarity index 74% rename from test/Streams.purs rename to test/Test/Node/FS/Streams.purs index eef4029..bce9971 100644 --- a/test/Streams.purs +++ b/test/Test/Node/FS/Streams.purs @@ -1,4 +1,4 @@ -module Test.Streams where +module Test.Node.FS.Streams where import Prelude @@ -17,13 +17,13 @@ main = do log "Testing streams" - r <- createReadStream (fp [ "test", "Streams.purs" ]) + r <- createReadStream (fp [ "test", "Test", "Node", "FS", "Streams.purs" ]) w <- createWriteStream (fp [ "tmp", "Streams.purs" ]) _ <- Stream.pipe r w r # on_ Stream.endH do - src <- Sync.readTextFile UTF8 (fp [ "test", "Streams.purs" ]) + src <- Sync.readTextFile UTF8 (fp [ "test", "Test", "Node", "FS", "Streams.purs" ]) dst <- Sync.readTextFile UTF8 (fp [ "tmp", "Streams.purs" ]) if src == dst then log "all good" diff --git a/test/Test.purs b/test/Test/Node/FS/Sync.purs similarity index 93% rename from test/Test.purs rename to test/Test/Node/FS/Sync.purs index 4606f29..994ddc6 100644 --- a/test/Test.purs +++ b/test/Test/Node/FS/Sync.purs @@ -1,4 +1,4 @@ -module Test where +module Test.Node.FS.Sync where import Prelude @@ -35,10 +35,10 @@ main :: Effect Unit main = do let fp = Path.concat - e <- S.exists (fp [ "test", "Test.purs" ]) + e <- S.exists (fp [ "test", "Test", "Node", "FS", "Sync.purs" ]) log $ "Test.purs exists? " <> show e - file <- S.readTextFile UTF8 (fp [ "test", "Test.purs" ]) + file <- S.readTextFile UTF8 (fp [ "test", "Test", "Node", "FS", "Sync.purs" ]) log "\n\nreadTextFile sync result:" log $ file @@ -99,16 +99,16 @@ main = do log "\n\ntruncate result:" either (log <<< show) (log <<< show) y - A.readFile (fp [ "test", "Test.purs" ]) $ \mbuf -> do + A.readFile (fp [ "test", "Test", "Node", "FS", "Sync.purs" ]) $ \mbuf -> do buf <- traverse Buffer.freeze mbuf log "\n\nreadFile result:" either (log <<< show) (log <<< show) buf - A.readTextFile UTF8 (fp [ "test", "Test.purs" ]) $ \x -> do + A.readTextFile UTF8 (fp [ "test", "Test", "Node", "FS", "Sync.purs" ]) $ \x -> do log "\n\nreadTextFile result:" either (log <<< show) log x - A.stat (fp [ "test", "Test.purs" ]) $ \x -> do + A.stat (fp [ "test", "Test", "Node", "FS", "Sync.purs" ]) $ \x -> do log "\n\nA.stat:" case x of Left err -> log $ "Error:" <> show err @@ -197,4 +197,3 @@ main = do case copyErr of Left _ -> pure unit Right _ -> throw $ destReadPath <> " already exists, but copying a file to there did not throw an error with COPYFILE_EXCL option" - From e48eea5ef4f1ecc44017c11d0250f3d418f3f692 Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Sun, 6 Oct 2024 14:58:50 +0700 Subject: [PATCH 09/32] feat: move Options to separate file --- src/Node/FS.purs | 41 +- src/Node/FS/Aff.purs | 155 +++---- src/Node/FS/Aff/Dir.purs | 16 +- src/Node/FS/Async.purs | 598 +++++++++++++-------------- src/Node/FS/Constants.purs | 1 + src/Node/FS/Dir.purs | 25 +- src/Node/FS/Internal/AffUtils.purs | 71 ++++ src/Node/FS/Internal/Utils.purs | 42 ++ src/Node/FS/Options.purs | 329 +++++++++++++++ src/Node/FS/Sync.js | 31 +- src/Node/FS/Types.purs | 34 ++ test/Test/Node/FS/OpendirAndDir.purs | 3 +- test/Test/Node/FS/Sync.purs | 3 +- 13 files changed, 859 insertions(+), 490 deletions(-) create mode 100644 src/Node/FS/Internal/AffUtils.purs create mode 100644 src/Node/FS/Internal/Utils.purs create mode 100644 src/Node/FS/Options.purs create mode 100644 src/Node/FS/Types.purs diff --git a/src/Node/FS.purs b/src/Node/FS.purs index 9db38cb..644e7cf 100644 --- a/src/Node/FS.purs +++ b/src/Node/FS.purs @@ -1,45 +1,8 @@ -module Node.FS - ( FileDescriptor - , FileMode - , SymlinkType(..) - , symlinkTypeToNode - , BufferLength - , BufferOffset - , ByteCount - , FilePosition - , module Exports - ) where +module Node.FS (module Exports) where import Prelude import Data.Nullable (Nullable) import Data.Nullable as Nullable import Node.FS.Constants (FileFlags(..), fileFlagsToNode) as Exports - -foreign import data FileDescriptor :: Type - -type FileMode = Int -type FilePosition = Int -type BufferLength = Int -type BufferOffset = Int -type ByteCount = Int - --- | Symlink varieties. -data SymlinkType = FileLink | DirLink | JunctionLink | AutodetectLink - --- | Convert a `SymlinkType` to a `String` in the format expected by the --- | Node.js filesystem API. -symlinkTypeToNode :: SymlinkType -> Nullable String -symlinkTypeToNode ty = case ty of - FileLink -> Nullable.notNull "file" - DirLink -> Nullable.notNull "dir" - JunctionLink -> Nullable.notNull "junction" - AutodetectLink -> Nullable.null - -instance showSymlinkType :: Show SymlinkType where - show FileLink = "FileLink" - show DirLink = "DirLink" - show JunctionLink = "JunctionLink" - show AutodetectLink = "AutodetectLink" - -derive instance eqSymlinkType :: Eq SymlinkType +import Node.FS.Types as Exports diff --git a/src/Node/FS/Aff.purs b/src/Node/FS/Aff.purs index 37ddf91..e1438d0 100644 --- a/src/Node/FS/Aff.purs +++ b/src/Node/FS/Aff.purs @@ -9,8 +9,8 @@ module Node.FS.Aff , truncate , chown , chmod - , stat , lstat + , stat , link , symlink , readlink @@ -40,8 +40,11 @@ module Node.FS.Aff , appendTextFile , fdOpen , fdRead + , fdRead' , fdNext , fdWrite + , fdWrite' + , fdWriteString , fdAppend , fdClose , cp @@ -69,7 +72,6 @@ module Node.FS.Aff -- , watch -- , watchFile , writev - , module Exports ) where import Prelude @@ -78,84 +80,20 @@ import Data.DateTime (DateTime) import Data.Either (Either(..)) import Data.Maybe (Maybe) import Data.Tuple (Tuple) -import Effect (Effect) import Effect.Aff (Aff, Error, makeAff, nonCanceler) import Node.Buffer (Buffer) import Node.Encoding (Encoding) -import Node.FS as F -import Node.FS.Async (CpOptions, CpForce(..), cpOptionsDefault, OpendirOptions , opendirOptionsDefault, RmOptions, rmOptionsDefault, RmdirOptions, rmdirOptionsDefault) as Exports -import Node.FS.Async (CpOptions, OpendirOptions, RmdirOptions, RmOptions) +import Node.FS.Types (BufferLength, BufferOffset, ByteCount, FileDescriptor, FileMode, FilePosition, SymlinkType) +import Node.FS.Internal.AffUtils (toAff1, toAff2, toAff3, toAff4, toAff5) +import Node.FS.Options (CpOptions, FdReadOptions, FdWriteOptions, OpendirOptions, RealpathOptions, RmOptions, RmdirOptions) +import Node.FS.Constants (AccessMode, CopyMode, FileFlags) import Node.FS.Async as A -import Node.FS.Constants (AccessMode, CopyMode) import Node.FS.Dir (Dir) import Node.FS.Dirent (Dirent, DirentNameTypeBuffer, DirentNameTypeString) import Node.FS.Perms (Perms) import Node.FS.Stats (Stats) import Node.Path (FilePath) -toAff - :: forall a - . (A.Callback a -> Effect Unit) - -> Aff a -toAff p = makeAff \k -> p k $> nonCanceler - -toAff1 - :: forall a x - . (x -> A.Callback a -> Effect Unit) - -> x - -> Aff a -toAff1 f a = toAff (f a) - -toAff2 - :: forall a x y - . (x -> y -> A.Callback a -> Effect Unit) - -> x - -> y - -> Aff a -toAff2 f a b = toAff (f a b) - -toAff3 - :: forall a x y z - . (x -> y -> z -> A.Callback a -> Effect Unit) - -> x - -> y - -> z - -> Aff a -toAff3 f a b c = toAff (f a b c) - --- toAff4 --- :: forall a x y z --- . (x -> y -> z -> y -> A.Callback a -> Effect Unit) --- -> x --- -> y --- -> z --- -> y --- -> Aff a --- toAff4 f a b c d = toAff (f a b c d) - -toAff5 - :: forall a w v x y z - . (w -> v -> x -> y -> z -> A.Callback a -> Effect Unit) - -> w - -> v - -> x - -> y - -> z - -> Aff a -toAff5 f a b c d e = toAff (f a b c d e) - --- toAff6 --- :: forall a w v x y z t --- . (w -> v -> x -> y -> z -> t -> A.Callback a -> Effect Unit) --- -> w --- -> v --- -> x --- -> y --- -> z --- -> t --- -> Aff a --- toAff6 f a b c d e t = toAff (f a b c d e t) - access :: FilePath -> Aff (Maybe Error) access path = makeAff \k -> do A.access path (k <<< Right) @@ -226,7 +164,7 @@ link = toAff2 A.link symlink :: FilePath -> FilePath - -> F.SymlinkType + -> SymlinkType -> Aff Unit symlink = toAff3 A.symlink @@ -246,7 +184,7 @@ realpath = toAff1 A.realpath -- | Find the canonicalized absolute location for a path using a cache object -- | for already resolved paths. -- | -realpath' :: forall cache. FilePath -> { | cache } -> Aff FilePath +realpath' :: FilePath -> RealpathOptions -> Aff FilePath realpath' = toAff2 A.realpath' -- | @@ -376,46 +314,71 @@ appendTextFile = toAff3 A.appendTextFile -- | for details. fdOpen :: FilePath - -> F.FileFlags - -> Maybe F.FileMode - -> Aff F.FileDescriptor + -> FileFlags + -> Maybe FileMode + -> Aff FileDescriptor fdOpen = toAff3 A.fdOpen -- | Read from a file asynchronously. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_read_fd_buffer_offset_length_position_callback) -- | for details. fdRead - :: F.FileDescriptor + :: FileDescriptor -> Buffer - -> F.BufferOffset - -> F.BufferLength - -> Maybe F.FilePosition - -> Aff F.ByteCount + -> BufferOffset + -> BufferLength + -> Maybe FilePosition + -> Aff ByteCount fdRead = toAff5 A.fdRead +-- | Read from a file asynchronously. See the [Node Documentation](https://nodejs.org/docs/latest/api/fs.html#fsreadfd-options-callback) +-- | for details. +fdRead' + :: FileDescriptor + -> FdReadOptions + -> Aff (Tuple ByteCount Buffer) +fdRead' = toAff2 A.fdRead' + -- | Convenience function to fill the whole buffer from the current -- | file position. -fdNext :: F.FileDescriptor -> Buffer -> Aff F.ByteCount +fdNext :: FileDescriptor -> Buffer -> Aff ByteCount fdNext = toAff2 A.fdNext -- | Write to a file asynchronously. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_write_fd_buffer_offset_length_position_callback) -- | for details. fdWrite - :: F.FileDescriptor + :: FileDescriptor -> Buffer - -> F.BufferOffset - -> F.BufferLength - -> Maybe F.FilePosition - -> Aff F.ByteCount + -> BufferOffset + -> BufferLength + -> Maybe FilePosition + -> Aff ByteCount fdWrite = toAff5 A.fdWrite +-- | Write from a file asynchronously. See the [Node Documentation](https://nodejs.org/docs/latest/api/fs.html#fswritefd-options-callback) +-- | for details. +fdWrite' + :: FileDescriptor + -> FdWriteOptions + -> Aff (Tuple ByteCount Buffer) +fdWrite' = toAff2 A.fdWrite' + +-- It is unsafe to use fs.write() multiple times on the same file without waiting for the callback. For this scenario, fs.createWriteStream() is recommended. +fdWriteString + :: FileDescriptor + -> String + -> Maybe FilePosition + -> Encoding + -> Aff (Tuple ByteCount String) +fdWriteString = toAff4 A.fdWriteString + -- | Convenience function to append the whole buffer to the current -- | file position. -fdAppend :: F.FileDescriptor -> Buffer -> Aff F.ByteCount +fdAppend :: FileDescriptor -> Buffer -> Aff ByteCount fdAppend = toAff2 A.fdAppend -- | Close a file asynchronously. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_close_fd_callback) -- | for details. -fdClose :: F.FileDescriptor -> Aff Unit +fdClose :: FileDescriptor -> Aff Unit fdClose = toAff1 A.fdClose -- | Copy a file asynchronously. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fspromises_copyfile_src_dest_mode) @@ -428,32 +391,32 @@ cp' = toAff3 A.cp' -- | Change permissions on a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fchmod_fd_mode_callback) -- | for details. -fchmod :: F.FileDescriptor -> Perms -> Aff Unit +fchmod :: FileDescriptor -> Perms -> Aff Unit fchmod = toAff2 A.fchmod -- | Change ownership of a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fchown_fd_uid_gid_callback) -- | for details. -fchown :: F.FileDescriptor -> Int -> Int -> Aff Unit +fchown :: FileDescriptor -> Int -> Int -> Aff Unit fchown = toAff3 A.fchown -- | Synchronize a file's in-core state with storage. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fdatasync_fd_callback) -- | for details. -fdatasync :: F.FileDescriptor -> Aff Unit +fdatasync :: FileDescriptor -> Aff Unit fdatasync = toAff1 A.fdatasync -- | Get file status information. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fstat_fd_callback) -- | for details. -fstat :: F.FileDescriptor -> Aff Stats +fstat :: FileDescriptor -> Aff Stats fstat = toAff1 A.fstat -- | Flushes a file descriptor to disk. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fsync_fd_callback) -- | for details. -fsync :: F.FileDescriptor -> Aff Unit +fsync :: FileDescriptor -> Aff Unit fsync = toAff1 A.fsync -- | Truncate a file to a specified length. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_ftruncate_fd_len_callback) -- | for details. -ftruncate :: F.FileDescriptor -> Int -> Aff Unit +ftruncate :: FileDescriptor -> Int -> Aff Unit ftruncate = toAff2 A.ftruncate -- | Change file timestamps for a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_futimes_fd_atime_mtime_callback) @@ -507,7 +470,7 @@ opendir' = toAff2 A.opendir' -- | Read from a file descriptor into a buffer array. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_readv_fd_buffers_position_callback) -- | for details. -readv :: F.FileDescriptor -> Array Buffer -> Maybe F.FilePosition -> Aff (Tuple F.ByteCount (Array Buffer)) +readv :: FileDescriptor -> Array Buffer -> Maybe FilePosition -> Aff (Tuple ByteCount (Array Buffer)) readv = toAff3 A.readv -- | TODO: bigint, path Buffer Url @@ -534,5 +497,5 @@ statfs = toAff1 A.statfs -- | Write from an array of buffers to a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_writev_fd_buffers_position_callback) -- | for details. -writev :: F.FileDescriptor -> Array Buffer -> Maybe F.FilePosition -> Aff (Tuple F.ByteCount (Array Buffer)) +writev :: FileDescriptor -> Array Buffer -> Maybe FilePosition -> Aff (Tuple ByteCount (Array Buffer)) writev = toAff3 A.writev diff --git a/src/Node/FS/Aff/Dir.purs b/src/Node/FS/Aff/Dir.purs index f72ef2b..2fa6fb0 100644 --- a/src/Node/FS/Aff/Dir.purs +++ b/src/Node/FS/Aff/Dir.purs @@ -16,22 +16,10 @@ import Effect.Class (liftEffect) import Effect.Exception (Error) import Effect.Ref (Ref) import Effect.Ref as Ref -import Node.FS.Dir (Callback2, Dir) +import Node.FS.Dir (Dir) import Node.FS.Dir as Dir import Node.FS.Dirent (Dirent, DirentNameTypeString) - -toAff - :: forall a - . (Callback2 a -> Effect Unit) - -> Aff a -toAff p = makeAff \k -> p k $> nonCanceler - -toAff1 - :: forall a x - . (x -> Callback2 a -> Effect Unit) - -> x - -> Aff a -toAff1 f a = toAff (f a) +import Node.FS.Internal.AffUtils read :: Dir -> Aff (Maybe (Dirent DirentNameTypeString)) read = toAff1 Dir.read diff --git a/src/Node/FS/Async.purs b/src/Node/FS/Async.purs index b02a76e..0beecca 100644 --- a/src/Node/FS/Async.purs +++ b/src/Node/FS/Async.purs @@ -1,6 +1,5 @@ module Node.FS.Async - ( Callback - , access + ( access , access' , copyFile , copyFile' @@ -20,12 +19,8 @@ module Node.FS.Async , unlink , rmdir , rmdir' - , rmdirOptionsDefault - , RmdirOptions , rm , rm' - , rmOptionsDefault - , RmOptions , mkdir , mkdir' , readdir @@ -45,15 +40,15 @@ module Node.FS.Async , appendTextFile , fdOpen , fdRead + , fdRead' , fdNext , fdWrite + , fdWrite' + , fdWriteString , fdAppend , fdClose , cp , cp' - , cpOptionsDefault - , CpOptions - , CpForce(..) , fchmod , fchown , fdatasync @@ -71,8 +66,6 @@ module Node.FS.Async -- , openAsBlob , opendir , opendir' - , OpendirOptions - , opendirOptionsDefault , readv , statfs -- , unwatchFile @@ -84,227 +77,206 @@ module Node.FS.Async import Prelude import Data.DateTime (DateTime) -import Data.DateTime.Instant (fromDateTime, unInstant) -import Data.Either (Either(..)) -import Data.Function.Uncurried (Fn2, mkFn2) -import Data.Int (round) import Data.Maybe (Maybe(..)) import Data.Nullable (Nullable, toMaybe, toNullable) -import Data.Time.Duration (Milliseconds(..)) -import Data.Tuple (Tuple(..)) +import Data.Tuple (Tuple) import Effect (Effect) import Effect.Exception (Error) -import Effect.Uncurried (EffectFn1, EffectFn2, EffectFn3, EffectFn4, EffectFn6, mkEffectFn1, mkEffectFn2, mkEffectFn3, runEffectFn2, runEffectFn3, runEffectFn4, runEffectFn6) +import Effect.Uncurried (EffectFn1, EffectFn2, EffectFn3, EffectFn4, EffectFn5, EffectFn6, mkEffectFn1, runEffectFn2, runEffectFn3, runEffectFn4, runEffectFn5, runEffectFn6) import Node.Buffer (Buffer, size) import Node.Encoding (Encoding(..), encodingToNode) import Node.FS (FileDescriptor, ByteCount, FilePosition, BufferLength, BufferOffset, FileMode, SymlinkType, symlinkTypeToNode) -import Node.FS.Constants (FileFlags, fileFlagsToNode, AccessMode, CopyMode, defaultAccessMode, defaultCopyMode) +import Node.FS.Constants +import Node.FS.Internal.Utils +import Node.FS.Options import Node.FS.Dir (Dir) import Node.FS.Dirent (Dirent, DirentNameTypeBuffer, DirentNameTypeString) -import Node.FS.Perms (Perms, permsToString, all, mkPerms) +import Node.FS.Perms (Perms, permsToString) import Node.FS.Stats (Stats) import Node.Path (FilePath) +import Unsafe.Coerce (unsafeCoerce) -datetimeToUnixEpochTimeInSeconds :: DateTime -> Int -datetimeToUnixEpochTimeInSeconds date = ms (toEpochMilliseconds date) / 1000 - where - ms (Milliseconds n) = round n - toEpochMilliseconds = unInstant <<< fromDateTime - -type JSCallback a = EffectFn2 (Nullable Error) a Unit - -type JSCallback2 a b = EffectFn3 (Nullable Error) a b Unit - -handleCallback :: forall a. Callback a -> JSCallback a -handleCallback cb = mkEffectFn2 \err a -> case toMaybe err of - Nothing -> cb (Right a) - Just err' -> cb (Left err') - -handleCallback2 :: forall a b. Callback (Tuple a b) -> JSCallback2 a b -handleCallback2 cb = mkEffectFn3 \err a b -> case toMaybe err of - Nothing -> cb (Right (Tuple a b)) - Just err' -> cb (Left err') - --- | Type synonym for callback functions. -type Callback a = Either Error a -> Effect Unit +foreign import accessImpl :: EffectFn3 FilePath AccessMode (EffectFn1 (Nullable Error) Unit) Unit +foreign import copyFileImpl :: EffectFn4 FilePath FilePath CopyMode (JSCallback1 Unit) Unit +foreign import mkdtempImpl :: EffectFn3 FilePath FilePath (JSCallback1 FilePath) Unit +foreign import renameImpl :: EffectFn3 FilePath FilePath (JSCallback1 Unit) Unit +foreign import truncateImpl :: EffectFn3 FilePath Int (JSCallback1 Unit) Unit +foreign import chownImpl :: EffectFn4 FilePath Int Int (JSCallback1 Unit) Unit +foreign import chmodImpl :: EffectFn3 FilePath String (JSCallback1 Unit) Unit +foreign import statImpl :: EffectFn2 FilePath (JSCallback1 Stats) Unit +foreign import lstatImpl :: EffectFn2 FilePath (JSCallback1 Stats) Unit +foreign import linkImpl :: EffectFn3 FilePath FilePath (JSCallback1 Unit) Unit +foreign import symlinkImpl :: EffectFn4 FilePath FilePath (Nullable String) (JSCallback1 Unit) Unit +foreign import readlinkImpl :: EffectFn2 FilePath (JSCallback1 FilePath) Unit +foreign import realpathImpl :: EffectFn3 FilePath RealpathOptionsInternal (JSCallback1 FilePath) Unit +foreign import unlinkImpl :: EffectFn2 FilePath (JSCallback1 Unit) Unit +foreign import rmdirImpl :: EffectFn3 FilePath RmdirOptions (JSCallback1 Unit) Unit +foreign import rmImpl :: EffectFn3 FilePath RmOptions (JSCallback1 Unit) Unit +foreign import mkdirImpl :: EffectFn3 FilePath MkdirOptionsInternal (JSCallback1 Unit) Unit +-- if { withFileTypes: false, recursive: false } => ['Tidy'] +-- if { withFileTypes: false, recursive: true } => [ 'Tidy', 'Tidy/Codegen', 'Tidy/Codegen.purs', 'Tidy/Codegen/Class.purs', .. ] +foreign import readdirImpl :: forall filepathOrDirentOrBuffer . EffectFn3 FilePath ReaddirOptionsInternal (JSCallback1 (Array filepathOrDirentOrBuffer)) Unit +foreign import utimesImpl :: EffectFn4 FilePath Int Int (JSCallback1 Unit) Unit +foreign import readFileImpl :: forall stringOrBuffer . EffectFn3 FilePath ReadFileOptionsInternal (JSCallback1 stringOrBuffer) Unit +foreign import writeFileImpl :: forall stringOrBuffer . EffectFn4 FilePath stringOrBuffer WriteFileOptionsInternal (JSCallback1 Unit) Unit +foreign import appendFileImpl :: forall stringOrBuffer . EffectFn4 FilePath stringOrBuffer AppendFileOptionsInternal (JSCallback1 Unit) Unit +foreign import openImpl :: EffectFn4 FilePath String (Nullable FileMode) (JSCallback1 FileDescriptor) Unit +foreign import readImpl :: EffectFn6 FileDescriptor Buffer BufferOffset BufferLength (Nullable FilePosition) (JSCallback1 ByteCount) Unit + +-- https://nodejs.org/docs/latest/api/fs.html#fsreadfd-options-callback +readWithOptionsImpl :: EffectFn3 FileDescriptor FdReadOptionsInternal (JSCallback2 ByteCount Buffer) Unit +readWithOptionsImpl = unsafeCoerce readImpl + +foreign import writeImpl :: EffectFn6 FileDescriptor Buffer BufferOffset BufferLength (Nullable FilePosition) (JSCallback1 ByteCount) Unit + +-- https://nodejs.org/docs/latest/api/fs.html#fsreadfd-options-callback +writeWithOptionsImpl :: EffectFn3 FileDescriptor FdWriteOptionsInternal (JSCallback2 ByteCount Buffer) Unit +writeWithOptionsImpl = unsafeCoerce writeImpl + +-- https://nodejs.org/docs/latest/api/fs.html#fsreadfd-options-callback +writeStringImpl :: EffectFn5 FileDescriptor String (Nullable FilePosition) String (JSCallback2 ByteCount String) Unit +writeStringImpl = unsafeCoerce writeImpl + +foreign import closeImpl :: EffectFn2 FileDescriptor (JSCallback1 Unit) Unit +foreign import cpImpl :: EffectFn4 FilePath FilePath CpOptionsInternal (JSCallback1 Unit) Unit +foreign import fchmodImpl :: EffectFn3 FileDescriptor String (JSCallback1 Unit) Unit +foreign import fchownImpl :: EffectFn4 FileDescriptor Int Int (JSCallback1 Unit) Unit +foreign import fdatasyncImpl :: EffectFn2 FileDescriptor (JSCallback1 Unit) Unit +foreign import fstatImpl :: EffectFn2 FileDescriptor (JSCallback1 Stats) Unit +foreign import fsyncImpl :: EffectFn2 FileDescriptor (JSCallback1 Unit) Unit +foreign import ftruncateImpl :: EffectFn3 FileDescriptor Int (JSCallback1 Unit) Unit +foreign import futimesImpl :: EffectFn4 FileDescriptor Int Int (JSCallback1 Unit) Unit +foreign import globImpl :: forall filepathOrDirent. EffectFn3 (Array FilePath) (GlobOptionsInternal filepathOrDirent) (JSCallback1 (Array filepathOrDirent)) Unit +foreign import lchmodImpl :: EffectFn3 FilePath String (JSCallback1 Unit) Unit +foreign import lchownImpl :: EffectFn4 FilePath Int Int (JSCallback1 Unit) Unit +foreign import lutimesImpl :: EffectFn4 FilePath Int Int (JSCallback1 Unit) Unit +-- foreign import openAsBlobImpl :: EffectFn2 FilePath (Promise Blob) Unit +foreign import opendirImpl :: EffectFn3 FilePath OpendirOptionsInternal (JSCallback1 Dir) Unit +foreign import readvImpl :: EffectFn4 FileDescriptor (Array Buffer) (Nullable FilePosition) (JSCallback2 ByteCount (Array Buffer)) Unit +foreign import statfsImpl :: EffectFn2 FilePath (JSCallback1 Stats) Unit +-- foreign import unwatchFileImpl :: EffectFn1 FilePath Unit +-- foreign import watchImpl :: EffectFn2 FilePath (EffectFn1 String Unit) Unit +-- foreign import watchFileImpl :: EffectFn2 FilePath (EffectFn2 Stats Stats Unit) Unit +foreign import writevImpl :: EffectFn4 FileDescriptor (Array Buffer) (Nullable FilePosition) (JSCallback2 ByteCount (Array Buffer)) Unit access :: FilePath -> (Maybe Error -> Effect Unit) -> Effect Unit access path = access' path defaultAccessMode access' :: FilePath -> AccessMode -> (Maybe Error -> Effect Unit) -> Effect Unit -access' path mode cb = runEffectFn3 accessImpl path mode $ mkEffectFn1 \err -> do - cb $ toMaybe err +access' path mode cb = runEffectFn3 accessImpl path mode $ mkEffectFn1 (cb <<< toMaybe) -foreign import accessImpl :: EffectFn3 FilePath AccessMode (EffectFn1 (Nullable Error) Unit) Unit - -copyFile :: FilePath -> FilePath -> Callback Unit -> Effect Unit +copyFile :: FilePath -> FilePath -> Callback1 Unit -> Effect Unit copyFile src dest = copyFile' src dest defaultCopyMode -copyFile' :: FilePath -> FilePath -> CopyMode -> Callback Unit -> Effect Unit -copyFile' src dest mode cb = runEffectFn4 copyFileImpl src dest mode (handleCallback cb) - -foreign import copyFileImpl :: EffectFn4 FilePath FilePath CopyMode (JSCallback Unit) Unit +copyFile' :: FilePath -> FilePath -> CopyMode -> Callback1 Unit -> Effect Unit +copyFile' src dest mode cb = runEffectFn4 copyFileImpl src dest mode (handleCallback1 cb) -mkdtemp :: FilePath -> Callback FilePath -> Effect Unit +mkdtemp :: FilePath -> Callback1 FilePath -> Effect Unit mkdtemp prefix = mkdtemp' prefix UTF8 -mkdtemp' :: FilePath -> Encoding -> Callback FilePath -> Effect Unit -mkdtemp' prefix encoding cb = runEffectFn3 mkdtempImpl prefix (encodingToNode encoding) (handleCallback cb) - -foreign import mkdtempImpl :: EffectFn3 FilePath FilePath (JSCallback FilePath) Unit - -foreign import renameImpl :: EffectFn3 FilePath FilePath (JSCallback Unit) Unit -foreign import truncateImpl :: EffectFn3 FilePath Int (JSCallback Unit) Unit -foreign import chownImpl :: EffectFn4 FilePath Int Int (JSCallback Unit) Unit -foreign import chmodImpl :: EffectFn3 FilePath String (JSCallback Unit) Unit -foreign import statImpl :: EffectFn2 FilePath (JSCallback Stats) Unit -foreign import lstatImpl :: EffectFn2 FilePath (JSCallback Stats) Unit -foreign import linkImpl :: EffectFn3 FilePath FilePath (JSCallback Unit) Unit -foreign import symlinkImpl :: EffectFn4 FilePath FilePath (Nullable String) (JSCallback Unit) Unit -foreign import readlinkImpl :: EffectFn2 FilePath (JSCallback FilePath) Unit -foreign import realpathImpl :: forall cache. EffectFn3 FilePath { | cache } (JSCallback FilePath) Unit -foreign import unlinkImpl :: EffectFn2 FilePath (JSCallback Unit) Unit -foreign import rmdirImpl :: EffectFn3 FilePath RmdirOptions (JSCallback Unit) Unit -foreign import rmImpl :: EffectFn3 FilePath RmOptions (JSCallback Unit) Unit -foreign import mkdirImpl :: EffectFn3 FilePath { recursive :: Boolean, mode :: String } (JSCallback Unit) Unit --- if { withFileTypes: false, recursive: false } => ['Tidy'] --- if { withFileTypes: false, recursive: true } => [ 'Tidy', 'Tidy/Codegen', 'Tidy/Codegen.purs', 'Tidy/Codegen/Class.purs', .. ] -foreign import readdirImpl :: forall filepathOrDirentOrBuffer stringOrBuffer. EffectFn3 FilePath { encoding :: stringOrBuffer, recursive :: Boolean, withFileTypes :: Boolean } (JSCallback (Array filepathOrDirentOrBuffer)) Unit -foreign import utimesImpl :: EffectFn4 FilePath Int Int (JSCallback Unit) Unit -foreign import readFileImpl :: forall a opts. EffectFn3 FilePath { | opts } (JSCallback a) Unit -foreign import writeFileImpl :: forall a opts. EffectFn4 FilePath a { | opts } (JSCallback Unit) Unit -foreign import appendFileImpl :: forall a opts. EffectFn4 FilePath a { | opts } (JSCallback Unit) Unit -foreign import openImpl :: EffectFn4 FilePath String (Nullable FileMode) (JSCallback FileDescriptor) Unit -foreign import readImpl :: EffectFn6 FileDescriptor Buffer BufferOffset BufferLength (Nullable FilePosition) (JSCallback ByteCount) Unit -foreign import writeImpl :: EffectFn6 FileDescriptor Buffer BufferOffset BufferLength (Nullable FilePosition) (JSCallback ByteCount) Unit -foreign import closeImpl :: EffectFn2 FileDescriptor (JSCallback Unit) Unit -foreign import cpImpl :: EffectFn4 FilePath FilePath CpOptionsInternal (JSCallback Unit) Unit -foreign import fchmodImpl :: EffectFn3 FileDescriptor String (JSCallback Unit) Unit -foreign import fchownImpl :: EffectFn4 FileDescriptor Int Int (JSCallback Unit) Unit -foreign import fdatasyncImpl :: EffectFn2 FileDescriptor (JSCallback Unit) Unit -foreign import fstatImpl :: EffectFn2 FileDescriptor (JSCallback Stats) Unit -foreign import fsyncImpl :: EffectFn2 FileDescriptor (JSCallback Unit) Unit -foreign import ftruncateImpl :: EffectFn3 FileDescriptor Int (JSCallback Unit) Unit -foreign import futimesImpl :: EffectFn4 FileDescriptor Int Int (JSCallback Unit) Unit -foreign import globImpl :: forall filepathOrDirent. EffectFn3 (Array FilePath) { cwd :: Nullable FilePath, exclude :: Nullable (filepathOrDirent -> Boolean), withFileTypes :: Boolean } (JSCallback (Array filepathOrDirent)) Unit -foreign import lchmodImpl :: EffectFn3 FilePath String (JSCallback Unit) Unit -foreign import lchownImpl :: EffectFn4 FilePath Int Int (JSCallback Unit) Unit -foreign import lutimesImpl :: EffectFn4 FilePath Int Int (JSCallback Unit) Unit --- foreign import openAsBlobImpl :: EffectFn2 FilePath (Promise Blob) Unit -foreign import opendirImpl :: EffectFn3 FilePath { bufferSize :: Int, recursive :: Boolean, encoding :: String } (JSCallback Dir) Unit -foreign import readvImpl :: EffectFn4 FileDescriptor (Array Buffer) (Nullable FilePosition) (JSCallback2 ByteCount (Array Buffer)) Unit -foreign import statfsImpl :: EffectFn2 FilePath (JSCallback Stats) Unit --- foreign import unwatchFileImpl :: EffectFn1 FilePath Unit --- foreign import watchImpl :: EffectFn2 FilePath (EffectFn1 String Unit) Unit --- foreign import watchFileImpl :: EffectFn2 FilePath (EffectFn2 Stats Stats Unit) Unit -foreign import writevImpl :: EffectFn4 FileDescriptor (Array Buffer) (Nullable FilePosition) (JSCallback2 ByteCount (Array Buffer)) Unit +mkdtemp' :: FilePath -> Encoding -> Callback1 FilePath -> Effect Unit +mkdtemp' prefix encoding cb = runEffectFn3 mkdtempImpl prefix (encodingToNode encoding) (handleCallback1 cb) -- | Renames a file. rename :: FilePath -> FilePath - -> Callback Unit + -> Callback1 Unit -> Effect Unit -rename oldFile newFile cb = runEffectFn3 renameImpl oldFile newFile (handleCallback cb) +rename oldFile newFile cb = runEffectFn3 renameImpl oldFile newFile (handleCallback1 cb) -- | Truncates a file to the specified length. truncate :: FilePath -> Int - -> Callback Unit + -> Callback1 Unit -> Effect Unit -truncate file len cb = runEffectFn3 truncateImpl file len (handleCallback cb) +truncate file len cb = runEffectFn3 truncateImpl file len (handleCallback1 cb) -- | Changes the ownership of a file. chown :: FilePath -> Int -> Int - -> Callback Unit + -> Callback1 Unit -> Effect Unit -chown file uid gid cb = runEffectFn4 chownImpl file uid gid (handleCallback cb) +chown file uid gid cb = runEffectFn4 chownImpl file uid gid (handleCallback1 cb) -- | Changes the permissions of a file. chmod :: FilePath -> Perms - -> Callback Unit + -> Callback1 Unit -> Effect Unit -chmod file perms cb = runEffectFn3 chmodImpl file (permsToString perms) (handleCallback cb) +chmod file perms cb = runEffectFn3 chmodImpl file (permsToString perms) (handleCallback1 cb) -- | Gets file statistics. stat :: FilePath - -> Callback Stats + -> Callback1 Stats -> Effect Unit -stat file cb = runEffectFn2 statImpl file (handleCallback $ cb) +stat file cb = runEffectFn2 statImpl file (handleCallback1 $ cb) -- | Gets file or symlink statistics. `lstat` is identical to `stat`, except -- | that if the `FilePath` is a symbolic link, then the link itself is stat-ed, -- | not the file that it refers to. lstat :: FilePath - -> Callback Stats + -> Callback1 Stats -> Effect Unit -lstat file cb = runEffectFn2 lstatImpl file (handleCallback $ cb) +lstat file cb = runEffectFn2 lstatImpl file (handleCallback1 $ cb) -- | Creates a link to an existing file. link :: FilePath -> FilePath - -> Callback Unit + -> Callback1 Unit -> Effect Unit -link src dst cb = runEffectFn3 linkImpl src dst (handleCallback cb) +link src dst cb = runEffectFn3 linkImpl src dst (handleCallback1 cb) -- | Creates a symlink. symlink :: FilePath -> FilePath -> SymlinkType - -> Callback Unit + -> Callback1 Unit -> Effect Unit -symlink src dest ty cb = runEffectFn4 symlinkImpl src dest (symlinkTypeToNode ty) (handleCallback cb) +symlink src dest ty cb = runEffectFn4 symlinkImpl src dest (symlinkTypeToNode ty) (handleCallback1 cb) -- | Reads the value of a symlink. readlink :: FilePath - -> Callback FilePath + -> Callback1 FilePath -> Effect Unit -readlink path cb = runEffectFn2 readlinkImpl path (handleCallback cb) +readlink path cb = runEffectFn2 readlinkImpl path (handleCallback1 cb) -- | Find the canonicalized absolute location for a path. realpath :: FilePath - -> Callback FilePath + -> Callback1 FilePath -> Effect Unit -realpath path cb = runEffectFn3 realpathImpl path {} (handleCallback cb) +realpath path = realpath' path realpathOptionsDefault -- | Find the canonicalized absolute location for a path using a cache object -- | for already resolved paths. realpath' - :: forall cache - . FilePath - -> { | cache } - -> Callback FilePath + :: FilePath + -> RealpathOptions + -> Callback1 FilePath -> Effect Unit -realpath' path cache cb = runEffectFn3 realpathImpl path cache (handleCallback cb) +realpath' path options cb = runEffectFn3 realpathImpl path (realpathOptionsToInternal options) (handleCallback1 cb) -- | Deletes a file. unlink :: FilePath - -> Callback Unit + -> Callback1 Unit -> Effect Unit -unlink file cb = runEffectFn2 unlinkImpl file (handleCallback cb) - -type RmdirOptions = { maxRetries :: Int, retryDelay :: Int } - -rmdirOptionsDefault :: RmdirOptions -rmdirOptionsDefault = { maxRetries: 0, retryDelay: 100 } +unlink file cb = runEffectFn2 unlinkImpl file (handleCallback1 cb) -- | Deletes a directory. rmdir :: FilePath - -> Callback Unit + -> Callback1 Unit -> Effect Unit rmdir path cb = rmdir' path rmdirOptionsDefault cb @@ -312,19 +284,14 @@ rmdir path cb = rmdir' path rmdirOptionsDefault cb rmdir' :: FilePath -> RmdirOptions - -> Callback Unit + -> Callback1 Unit -> Effect Unit -rmdir' path opts cb = runEffectFn3 rmdirImpl path opts (handleCallback cb) - -type RmOptions = { force :: Boolean, maxRetries :: Int, recursive :: Boolean, retryDelay :: Int } - -rmOptionsDefault :: RmOptions -rmOptionsDefault = { force: false, maxRetries: 100, recursive: false, retryDelay: 1000 } +rmdir' path opts cb = runEffectFn3 rmdirImpl path opts (handleCallback1 cb) -- | Deletes a file or directory. rm :: FilePath - -> Callback Unit + -> Callback1 Unit -> Effect Unit rm path = rm' path rmOptionsDefault @@ -332,152 +299,198 @@ rm path = rm' path rmOptionsDefault rm' :: FilePath -> RmOptions - -> Callback Unit + -> Callback1 Unit -> Effect Unit -rm' path opts cb = runEffectFn3 rmImpl path opts (handleCallback cb) +rm' path opts cb = runEffectFn3 rmImpl path opts (handleCallback1 cb) -- | Makes a new directory. mkdir :: FilePath - -> Callback Unit + -> Callback1 Unit -> Effect Unit -mkdir path = mkdir' path { recursive: false, mode: mkPerms all all all } +mkdir path = mkdir' path mkdirOptionsDefault -- | Makes a new directory with the specified permissions. mkdir' :: FilePath - -> { recursive :: Boolean, mode :: Perms } - -> Callback Unit + -> MkdirOptions + -> Callback1 Unit -> Effect Unit -mkdir' file { recursive, mode: perms } cb = runEffectFn3 mkdirImpl file { recursive, mode: permsToString perms } (handleCallback cb) +mkdir' file opts cb = runEffectFn3 mkdirImpl file (mkdirOptionsToInternal opts) (handleCallback1 cb) -- | Reads the contents of a directory. readdir :: FilePath - -> Callback (Array FilePath) + -> Callback1 (Array FilePath) -> Effect Unit -readdir file = readdir' file { recursive: false, encoding: UTF8 } +readdir file = readdir' file readdirFilePathOptionsDefault -- | Reads the contents of a directory. readdir' :: FilePath - -> { recursive :: Boolean, encoding :: Encoding } - -> Callback (Array FilePath) + -> ReaddirFilePathOptions + -> Callback1 (Array FilePath) -> Effect Unit -readdir' file { recursive, encoding } cb = runEffectFn3 readdirImpl file { recursive, encoding: encodingToNode encoding, withFileTypes: false } (handleCallback cb) +readdir' file options cb = runEffectFn3 readdirImpl file (readdirFilePathOptionsToInternal options) (handleCallback1 cb) -- | Reads the contents of a directory. readdirBuffer :: FilePath - -> Callback (Array Buffer) + -> Callback1 (Array Buffer) -> Effect Unit -readdirBuffer file = readdirBuffer' file { recursive: false } +readdirBuffer file = readdirBuffer' file readdirBufferOptionsDefault -- | Reads the contents of a directory. readdirBuffer' :: FilePath - -> { recursive :: Boolean } - -> Callback (Array Buffer) + -> ReaddirBufferOptions + -> Callback1 (Array Buffer) -> Effect Unit -readdirBuffer' file { recursive } cb = runEffectFn3 readdirImpl file { recursive, encoding: "buffer", withFileTypes: false } (handleCallback cb) +readdirBuffer' file options cb = runEffectFn3 readdirImpl file (readdirBufferOptionsToInternal options) (handleCallback1 cb) -- | Reads the contents of a directory. readdirDirent :: FilePath - -> Callback (Array (Dirent DirentNameTypeString)) + -> Callback1 (Array (Dirent DirentNameTypeString)) -> Effect Unit -readdirDirent file = readdirDirent' file { recursive: false, encoding: UTF8 } +readdirDirent file = readdirDirent' file readdirDirentOptionsDefault -- | Reads the contents of a directory. readdirDirent' :: FilePath - -> { recursive :: Boolean, encoding :: Encoding } - -> Callback (Array (Dirent DirentNameTypeString)) + -> ReaddirDirentOptions + -> Callback1 (Array (Dirent DirentNameTypeString)) -> Effect Unit -readdirDirent' file { recursive, encoding } cb = runEffectFn3 readdirImpl file { recursive, encoding: encodingToNode encoding, withFileTypes: true } (handleCallback cb) +readdirDirent' file options cb = runEffectFn3 readdirImpl file (readdirDirentOptionsToInternal options) (handleCallback1 cb) -- | Reads the contents of a directory. readdirDirentBuffer :: FilePath - -> Callback (Array (Dirent DirentNameTypeBuffer)) + -> Callback1 (Array (Dirent DirentNameTypeBuffer)) -> Effect Unit -readdirDirentBuffer file = readdirDirentBuffer' file { recursive: false } +readdirDirentBuffer file = readdirDirentBuffer' file readdirDirentBufferOptionsDefault -- | Reads the contents of a directory. readdirDirentBuffer' :: FilePath - -> { recursive :: Boolean } - -> Callback (Array (Dirent DirentNameTypeBuffer)) + -> ReaddirDirentBufferOptions + -> Callback1 (Array (Dirent DirentNameTypeBuffer)) -> Effect Unit -readdirDirentBuffer' file { recursive } cb = runEffectFn3 readdirImpl file { recursive, encoding: "buffer", withFileTypes: true } (handleCallback cb) +readdirDirentBuffer' file options cb = runEffectFn3 readdirImpl file (readdirDirentBufferOptionsToInternal options) (handleCallback1 cb) -- | Sets the accessed and modified times for the specified file. utimes :: FilePath -> DateTime -> DateTime - -> Callback Unit - -> Effect Unit -utimes file atime mtime cb = runEffectFn4 utimesImpl file (datetimeToUnixEpochTimeInSeconds atime) (datetimeToUnixEpochTimeInSeconds mtime) (handleCallback cb) - --- | Reads the entire contents of a file returning the result as a raw buffer. -readFile - :: FilePath - -> Callback Buffer + -> Callback1 Unit -> Effect Unit -readFile file cb = runEffectFn3 readFileImpl file {} (handleCallback cb) +utimes file atime mtime cb = runEffectFn4 utimesImpl file (datetimeToUnixEpochTimeInSeconds atime) (datetimeToUnixEpochTimeInSeconds mtime) (handleCallback1 cb) -- | Reads the entire contents of a text file with the specified encoding. readTextFile :: Encoding -> FilePath - -> Callback String + -> Callback1 String -> Effect Unit -readTextFile encoding file cb = runEffectFn3 readFileImpl file { encoding: show encoding } (handleCallback cb) +readTextFile encoding file = readTextFile' file (readFileStringOptionsDefault { encoding = encoding }) --- | Writes a buffer to a file. -writeFile +readTextFile' :: FilePath - -> Buffer - -> Callback Unit + -> ReadFileStringOptions + -> Callback1 String -> Effect Unit -writeFile file buff cb = runEffectFn4 writeFileImpl file buff {} (handleCallback cb) +readTextFile' file options cb = runEffectFn3 readFileImpl file (readFileStringOptionsToInternal options) (handleCallback1 cb) + +-- | Reads the entire contents of a file returning the result as a raw buffer. +readFile + :: FilePath + -> Callback1 Buffer + -> Effect Unit +readFile file = readFile' file readFileBufferOptionsDefault + +readFile' + :: FilePath + -> ReadFileBufferOptions + -> Callback1 Buffer + -> Effect Unit +readFile' file options cb = runEffectFn3 readFileImpl file (readFileBufferOptionsToInternal options) (handleCallback1 cb) -- | Writes text to a file using the specified encoding. writeTextFile :: Encoding -> FilePath -> String - -> Callback Unit + -> Callback1 Unit -> Effect Unit -writeTextFile encoding file buff cb = runEffectFn4 writeFileImpl file buff { encoding: show encoding } (handleCallback cb) +writeTextFile encoding file buff = writeTextFile' file buff (writeFileStringOptionsDefault { encoding = encoding }) --- | Appends the contents of a buffer to a file. -appendFile +writeTextFile' + :: FilePath + -> String + -> WriteFileStringOptions + -> Callback1 Unit + -> Effect Unit +writeTextFile' file buff options cb = runEffectFn4 writeFileImpl file buff (writeFileStringOptionsToInternal options) (handleCallback1 cb) + +-- | Writes a buffer to a file. +writeFile + :: FilePath + -> Buffer + -> Callback1 Unit + -> Effect Unit +writeFile file buff = writeFile' file buff writeFileBufferOptionsDefault + +writeFile' :: FilePath -> Buffer - -> Callback Unit + -> WriteFileBufferOptions + -> Callback1 Unit -> Effect Unit -appendFile file buff cb = runEffectFn4 appendFileImpl file buff {} (handleCallback cb) +writeFile' file buff options cb = runEffectFn4 writeFileImpl file buff (writeFileBufferOptionsToInternal options) (handleCallback1 cb) -- | Appends text to a file using the specified encoding. appendTextFile :: Encoding -> FilePath -> String - -> Callback Unit + -> Callback1 Unit + -> Effect Unit +appendTextFile encoding file buff = appendTextFile' file buff (appendFileStringOptionsDefault { encoding = encoding }) + +appendTextFile' + :: FilePath + -> String + -> AppendFileStringOptions + -> Callback1 Unit + -> Effect Unit +appendTextFile' file buff options cb = runEffectFn4 appendFileImpl file buff (appendFileStringOptionsToInternal options) (handleCallback1 cb) + +-- | Appends a buffer to a file. +appendFile + :: FilePath + -> Buffer + -> Callback1 Unit -> Effect Unit -appendTextFile encoding file buff cb = runEffectFn4 appendFileImpl file buff { encoding: show encoding } (handleCallback cb) +appendFile file buff = appendFile' file buff appendFileBufferOptionsDefault + +appendFile' + :: FilePath + -> Buffer + -> AppendFileBufferOptions + -> Callback1 Unit + -> Effect Unit +appendFile' file buff options cb = runEffectFn4 appendFileImpl file buff (appendFileBufferOptionsToInternal options) (handleCallback1 cb) -- | Open a file asynchronously. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_open_path_flags_mode_callback) -- | for details. fdOpen :: FilePath - -> FileFlags - -> Maybe FileMode - -> Callback FileDescriptor + -> FileFlags -- default 'r' + -> Maybe FileMode -- default '0o666', TODO: use Perms? + -> Callback1 FileDescriptor -> Effect Unit -fdOpen file flags mode cb = runEffectFn4 openImpl file (fileFlagsToNode flags) (toNullable mode) (handleCallback cb) +fdOpen file flags mode cb = runEffectFn4 openImpl file (fileFlagsToNode flags) (toNullable mode) (handleCallback1 cb) -- | Read from a file asynchronously. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_read_fd_buffer_offset_length_position_callback) -- | for details. @@ -485,18 +498,27 @@ fdRead :: FileDescriptor -> Buffer -> BufferOffset - -> BufferLength - -> Maybe FilePosition - -> Callback ByteCount + -> BufferLength -- TODO: should be Maybe BufferLength + -> Maybe FilePosition -- If position is null or -1 , data will be read from the current file position + -> Callback1 ByteCount -> Effect Unit -fdRead fd buff off len pos cb = runEffectFn6 readImpl fd buff off len (toNullable pos) (handleCallback cb) +fdRead fd buff off len pos cb = runEffectFn6 readImpl fd buff off len (toNullable pos) (handleCallback1 cb) + +-- | Read from a file asynchronously. See the [Node Documentation](https://nodejs.org/docs/latest/api/fs.html#fsreadfd-options-callback) +-- | for details. +fdRead' + :: FileDescriptor + -> FdReadOptions + -> Callback1 (Tuple ByteCount Buffer) + -> Effect Unit +fdRead' fd options cb = runEffectFn3 readWithOptionsImpl fd (fdReadOptionsToInternal options) (handleCallback1Tuple cb) -- | Convenience function to fill the whole buffer from the current -- | file position. fdNext :: FileDescriptor -> Buffer - -> Callback ByteCount + -> Callback1 ByteCount -> Effect Unit fdNext fd buff cb = do sz <- size buff @@ -508,18 +530,37 @@ fdWrite :: FileDescriptor -> Buffer -> BufferOffset - -> BufferLength + -> BufferLength -- TODO: should be Maybe BufferLength -> Maybe FilePosition - -> Callback ByteCount + -> Callback1 ByteCount -> Effect Unit -fdWrite fd buff off len pos cb = runEffectFn6 writeImpl fd buff off len (toNullable pos) (handleCallback cb) +fdWrite fd buff off len pos cb = runEffectFn6 writeImpl fd buff off len (toNullable pos) (handleCallback1 cb) + +-- | Write from a file asynchronously. See the [Node Documentation](https://nodejs.org/docs/latest/api/fs.html#fswritefd-options-callback) +-- | for details. +fdWrite' + :: FileDescriptor + -> FdWriteOptions + -> Callback1 (Tuple ByteCount Buffer) + -> Effect Unit +fdWrite' fd options cb = runEffectFn3 writeWithOptionsImpl fd (fdWriteOptionsToInternal options) (handleCallback1Tuple cb) + +-- It is unsafe to use fs.write() multiple times on the same file without waiting for the callback. For this scenario, fs.createWriteStream() is recommended. +fdWriteString + :: FileDescriptor + -> String + -> Maybe FilePosition + -> Encoding + -> Callback1 (Tuple ByteCount String) + -> Effect Unit +fdWriteString fd string pos encoding cb = runEffectFn5 writeStringImpl fd string (toNullable pos) (encodingToNode encoding) (handleCallback1Tuple cb) -- | Convenience function to append the whole buffer to the current -- | file position. fdAppend :: FileDescriptor -> Buffer - -> Callback ByteCount + -> Callback1 ByteCount -> Effect Unit fdAppend fd buff cb = do sz <- size buff @@ -529,97 +570,47 @@ fdAppend fd buff cb = do -- | for details. fdClose :: FileDescriptor - -> Callback Unit - -> Effect Unit -fdClose fd cb = runEffectFn2 closeImpl fd (handleCallback cb) - -data CpForce = CpForce_False | CpForce_TrueWithoutErrorOnExit | CpForce_TrueWithErrorOnExit - -type CpOptionsInternal = - { dereference :: Boolean - , errorOnExist :: Boolean - , filter :: Nullable (Fn2 FilePath FilePath Boolean) - , force :: Boolean - , mode :: FileMode - , preserveTimestamps :: Boolean - , recursive :: Boolean - , verbatimSymlinks :: Boolean - } - -type CpOptions = - { dereference :: Boolean -- Whether to dereference symlinks - , filter :: Maybe (FilePath -> FilePath -> Boolean) - , force :: CpForce - , mode :: FileMode -- Modifiers for copy operation - , preserveTimestamps :: Boolean -- Preserve timestamps from source - , recursive :: Boolean -- Copy directories recursively - , verbatimSymlinks :: Boolean -- Skip path resolution for symlinks - } - -cpOptionsToCpOptionsInternal :: CpOptions -> CpOptionsInternal -cpOptionsToCpOptionsInternal opts = - { dereference: opts.dereference - , errorOnExist: case opts.force of - CpForce_TrueWithErrorOnExit -> true - _ -> false - , filter: toNullable $ map mkFn2 (opts.filter) - , force: case opts.force of - CpForce_False -> false - _ -> true - , mode: opts.mode - , preserveTimestamps: opts.preserveTimestamps - , recursive: opts.recursive - , verbatimSymlinks: opts.verbatimSymlinks - } - -cpOptionsDefault :: CpOptions -cpOptionsDefault = - { dereference: false - , filter: Nothing - , force: CpForce_TrueWithoutErrorOnExit - , mode: 0 - , preserveTimestamps: false - , recursive: false - , verbatimSymlinks: false - } + -> Callback1 Unit + -> Effect Unit +fdClose fd cb = runEffectFn2 closeImpl fd (handleCallback1 cb) -- | Copy a file asynchronously. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fspromises_copyfile_src_dest_mode) -- | for details. -cp :: FilePath -> FilePath -> Callback Unit -> Effect Unit +cp :: FilePath -> FilePath -> Callback1 Unit -> Effect Unit cp src dest = cp' src dest cpOptionsDefault -cp' :: FilePath -> FilePath -> CpOptions -> Callback Unit -> Effect Unit -cp' src dest opts cb = runEffectFn4 cpImpl src dest (cpOptionsToCpOptionsInternal opts) (handleCallback cb) +cp' :: FilePath -> FilePath -> CpOptions -> Callback1 Unit -> Effect Unit +cp' src dest opts cb = runEffectFn4 cpImpl src dest (cpOptionsToCpOptionsInternal opts) (handleCallback1 cb) -- | Change permissions on a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fchmod_fd_mode_callback) -- | for details. -fchmod :: FileDescriptor -> Perms -> Callback Unit -> Effect Unit -fchmod fd perms cb = runEffectFn3 fchmodImpl fd (permsToString perms) (handleCallback cb) +fchmod :: FileDescriptor -> Perms -> Callback1 Unit -> Effect Unit +fchmod fd perms cb = runEffectFn3 fchmodImpl fd (permsToString perms) (handleCallback1 cb) -- | Change ownership of a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fchown_fd_uid_gid_callback) -- | for details. -fchown :: FileDescriptor -> Int -> Int -> Callback Unit -> Effect Unit -fchown fd uid gid cb = runEffectFn4 fchownImpl fd uid gid (handleCallback cb) +fchown :: FileDescriptor -> Int -> Int -> Callback1 Unit -> Effect Unit +fchown fd uid gid cb = runEffectFn4 fchownImpl fd uid gid (handleCallback1 cb) -- | Synchronize a file's in-core state with storage. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fdatasync_fd_callback) -- | for details. -fdatasync :: FileDescriptor -> Callback Unit -> Effect Unit -fdatasync fd cb = runEffectFn2 fdatasyncImpl fd (handleCallback cb) +fdatasync :: FileDescriptor -> Callback1 Unit -> Effect Unit +fdatasync fd cb = runEffectFn2 fdatasyncImpl fd (handleCallback1 cb) -- | Get file status information. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fstat_fd_callback) -- | for details. -fstat :: FileDescriptor -> Callback Stats -> Effect Unit -fstat fd cb = runEffectFn2 fstatImpl fd (handleCallback cb) +fstat :: FileDescriptor -> Callback1 Stats -> Effect Unit +fstat fd cb = runEffectFn2 fstatImpl fd (handleCallback1 cb) -- | Flushes a file descriptor to disk. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fsync_fd_callback) -- | for details. -fsync :: FileDescriptor -> Callback Unit -> Effect Unit -fsync fd cb = runEffectFn2 fsyncImpl fd (handleCallback cb) +fsync :: FileDescriptor -> Callback1 Unit -> Effect Unit +fsync fd cb = runEffectFn2 fsyncImpl fd (handleCallback1 cb) -- | Truncate a file to a specified length. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_ftruncate_fd_len_callback) -- | for details. -ftruncate :: FileDescriptor -> Int -> Callback Unit -> Effect Unit -ftruncate fd len cb = runEffectFn3 ftruncateImpl fd len (handleCallback cb) +ftruncate :: FileDescriptor -> Int -> Callback1 Unit -> Effect Unit +ftruncate fd len cb = runEffectFn3 ftruncateImpl fd len (handleCallback1 cb) -- | Change file timestamps for a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_futimes_fd_atime_mtime_callback) -- | for details. @@ -627,33 +618,33 @@ futimes :: FilePath -> DateTime -> DateTime - -> Callback Unit + -> Callback1 Unit -> Effect Unit -futimes file atime mtime cb = runEffectFn4 lutimesImpl file (datetimeToUnixEpochTimeInSeconds atime) (datetimeToUnixEpochTimeInSeconds mtime) (handleCallback cb) +futimes file atime mtime cb = runEffectFn4 lutimesImpl file (datetimeToUnixEpochTimeInSeconds atime) (datetimeToUnixEpochTimeInSeconds mtime) (handleCallback1 cb) -- | Perform pattern matching in file paths. See the [Node Documentation](https://nodejs.org/api/glob.html#globglob_pattern_options_callback) -- | for details. -glob :: Array FilePath -> Callback (Array FilePath) -> Effect Unit -glob pattern = glob' pattern { cwd: Nothing, exclude: Nothing } +glob :: Array FilePath -> Callback1 (Array FilePath) -> Effect Unit +glob pattern = glob' pattern globFilePathOptionsDefault -glob' :: Array FilePath -> { cwd :: Maybe FilePath, exclude :: Maybe (FilePath -> Boolean) } -> Callback (Array FilePath) -> Effect Unit -glob' pattern { cwd, exclude } cb = runEffectFn3 globImpl pattern { cwd: toNullable cwd, exclude: toNullable exclude, withFileTypes: false } (handleCallback cb) +glob' :: Array FilePath -> GlobFilePathOptions -> Callback1 (Array FilePath) -> Effect Unit +glob' pattern options cb = runEffectFn3 globImpl pattern (globFilePathOptionsToInternal options) (handleCallback1 cb) -globDirent :: Array FilePath -> Callback (Array (Dirent DirentNameTypeString)) -> Effect Unit -globDirent pattern = globDirent' pattern { cwd: Nothing, exclude: Nothing } +globDirent :: Array FilePath -> Callback1 (Array (Dirent DirentNameTypeString)) -> Effect Unit +globDirent pattern = globDirent' pattern globDirentOptionsDefault -globDirent' :: Array FilePath -> { cwd :: Maybe FilePath, exclude :: Maybe (Dirent DirentNameTypeString -> Boolean) } -> Callback (Array (Dirent DirentNameTypeString)) -> Effect Unit -globDirent' pattern { cwd, exclude } cb = runEffectFn3 globImpl pattern { cwd: toNullable cwd, exclude: toNullable exclude, withFileTypes: true } (handleCallback cb) +globDirent' :: Array FilePath -> GlobDirentOptions -> Callback1 (Array (Dirent DirentNameTypeString)) -> Effect Unit +globDirent' pattern options cb = runEffectFn3 globImpl pattern (globDirentOptionsToInternal options) (handleCallback1 cb) -- | Change permissions on a symbolic link. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_lchmod_path_mode_callback) -- | for details. -lchmod :: FilePath -> Perms -> Callback Unit -> Effect Unit -lchmod path perms cb = runEffectFn3 lchmodImpl path (permsToString perms) (handleCallback cb) +lchmod :: FilePath -> Perms -> Callback1 Unit -> Effect Unit +lchmod path perms cb = runEffectFn3 lchmodImpl path (permsToString perms) (handleCallback1 cb) -- | Change ownership of a symbolic link. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_lchown_path_uid_gid_callback) -- | for details. -lchown :: FilePath -> Int -> Int -> Callback Unit -> Effect Unit -lchown path uid gid cb = runEffectFn4 lchownImpl path uid gid (handleCallback cb) +lchown :: FilePath -> Int -> Int -> Callback1 Unit -> Effect Unit +lchown path uid gid cb = runEffectFn4 lchownImpl path uid gid (handleCallback1 cb) -- | Change timestamps for a symbolic link. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_lutimes_path_atime_mtime_callback) -- | for details. @@ -661,41 +652,36 @@ lutimes :: FilePath -> DateTime -> DateTime - -> Callback Unit + -> Callback1 Unit -> Effect Unit -lutimes file atime mtime cb = runEffectFn4 lutimesImpl file (datetimeToUnixEpochTimeInSeconds atime) (datetimeToUnixEpochTimeInSeconds mtime) (handleCallback cb) +lutimes file atime mtime cb = runEffectFn4 lutimesImpl file (datetimeToUnixEpochTimeInSeconds atime) (datetimeToUnixEpochTimeInSeconds mtime) (handleCallback1 cb) -- | TODO: path - Buffer Url, returns Promise -- | Open a file as a blob. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_class_filehandle) -- | for details. -- openAsBlob :: FilePath -> Promise Blob -> Effect Unit --- openAsBlob path cb = runEffectFn2 openAsBlobImpl path (handleCallback cb) - -type OpendirOptions = { encoding :: Encoding, bufferSize :: Int, recursive :: Boolean } - -opendirOptionsDefault :: OpendirOptions -opendirOptionsDefault = { bufferSize: 32, recursive: false, encoding: UTF8 } +-- openAsBlob path cb = runEffectFn2 openAsBlobImpl path (handleCallback1 cb) -- | Open a directory. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_opendir_path_options_callback) -- | for details. -opendir' :: FilePath -> OpendirOptions -> Callback Dir -> Effect Unit -opendir' path { encoding, bufferSize, recursive } cb = runEffectFn3 opendirImpl path { encoding: encodingToNode encoding, bufferSize, recursive } (handleCallback cb) +opendir' :: FilePath -> OpendirOptions -> Callback1 Dir -> Effect Unit +opendir' path options cb = runEffectFn3 opendirImpl path (opendirOptionsToInternal options) (handleCallback1 cb) -- | Open a directory. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_opendir_path_options_callback) -- | for details. -- | NOTE: encoding: 'buffer' is not supported, will throw error "TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received an instance of Buffer" -opendir :: FilePath -> Callback Dir -> Effect Unit +opendir :: FilePath -> Callback1 Dir -> Effect Unit opendir path = opendir' path opendirOptionsDefault -- | Read from a file descriptor into a buffer array. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_readv_fd_buffers_position_callback) -- | for details. -readv :: FileDescriptor -> Array Buffer -> Maybe FilePosition -> Callback (Tuple ByteCount (Array Buffer)) -> Effect Unit -readv fd buffers position cb = runEffectFn4 readvImpl fd buffers (toNullable position) (handleCallback2 cb) +readv :: FileDescriptor -> Array Buffer -> Maybe FilePosition -> Callback1 (Tuple ByteCount (Array Buffer)) -> Effect Unit +readv fd buffers position cb = runEffectFn4 readvImpl fd buffers (toNullable position) (handleCallback1Tuple cb) -- | Get file system statistics. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_statfs_path_callback) -- | for details. -statfs :: FilePath -> Callback Stats -> Effect Unit -statfs path cb = runEffectFn2 statfsImpl path (handleCallback cb) +statfs :: FilePath -> Callback1 Stats -> Effect Unit +statfs path cb = runEffectFn2 statfsImpl path (handleCallback1 cb) -- -- | Stop watching a file for changes. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_unwatchfile_filename_listener) -- -- | for details. @@ -714,5 +700,5 @@ statfs path cb = runEffectFn2 statfsImpl path (handleCallback cb) -- | Write from an array of buffers to a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_writev_fd_buffers_position_callback) -- | for details. -writev :: FileDescriptor -> Array Buffer -> Maybe FilePosition -> Callback (Tuple ByteCount (Array Buffer)) -> Effect Unit -writev fd buffers position cb = runEffectFn4 writevImpl fd buffers (toNullable position) (handleCallback2 cb) +writev :: FileDescriptor -> Array Buffer -> Maybe FilePosition -> Callback1 (Tuple ByteCount (Array Buffer)) -> Effect Unit +writev fd buffers position cb = runEffectFn4 writevImpl fd buffers (toNullable position) (handleCallback1Tuple cb) diff --git a/src/Node/FS/Constants.purs b/src/Node/FS/Constants.purs index c6bbcab..24f4880 100644 --- a/src/Node/FS/Constants.purs +++ b/src/Node/FS/Constants.purs @@ -88,3 +88,4 @@ fileFlagsToNode ff = case ff of AX -> "ax" A_PLUS -> "a+" AX_PLUS -> "ax+" + diff --git a/src/Node/FS/Dir.purs b/src/Node/FS/Dir.purs index 1ccd30b..18b9a25 100644 --- a/src/Node/FS/Dir.purs +++ b/src/Node/FS/Dir.purs @@ -2,38 +2,29 @@ module Node.FS.Dir where import Prelude -import Data.Either (Either(..)) -import Data.Maybe (Maybe(..)) +import Data.Either (Either) +import Data.Maybe (Maybe) import Data.Nullable (Nullable, toMaybe) import Effect (Effect) import Effect.Exception (Error) -import Effect.Uncurried (EffectFn1, EffectFn2, mkEffectFn1, mkEffectFn2, runEffectFn1, runEffectFn2) +import Effect.Uncurried (EffectFn1, EffectFn2, mkEffectFn1, runEffectFn1, runEffectFn2) import Node.FS.Dirent (Dirent, DirentNameTypeString) +import Node.FS.Internal.Utils (Callback0, JSCallback0, JSCallback1, handleCallback1) import Node.Path (FilePath) -type JSCallback1 = EffectFn1 (Nullable Error) Unit -type JSCallback2 a = EffectFn2 (Nullable Error) a Unit -type Callback1 = Maybe Error -> Effect Unit -type Callback2 a = Either Error a -> Effect Unit - -handleCallback2 :: forall a. Callback2 a -> JSCallback2 a -handleCallback2 cb = mkEffectFn2 \err a -> case toMaybe err of - Nothing -> cb (Right a) - Just err' -> cb (Left err') - -- Foreign imports for the Dir class foreign import data Dir :: Type -foreign import closeImpl :: EffectFn2 Dir JSCallback1 Unit +foreign import closeImpl :: EffectFn2 Dir JSCallback0 Unit foreign import closeSyncImpl :: EffectFn1 Dir Unit -foreign import readImpl :: EffectFn2 Dir (JSCallback2 (Nullable (Dirent DirentNameTypeString))) Unit +foreign import readImpl :: EffectFn2 Dir (JSCallback1 (Nullable (Dirent DirentNameTypeString))) Unit foreign import readSyncImpl :: EffectFn1 Dir (Nullable (Dirent DirentNameTypeString)) -- | Get the path of this directory as was provided to fs.opendir(), fs.opendirSync(), or fsPromises.opendir(). foreign import path :: Dir -> FilePath -- | Asynchronously close the directory's underlying resource handle. -close :: Dir -> Callback1 -> Effect Unit +close :: Dir -> Callback0 -> Effect Unit close dir callback = runEffectFn2 closeImpl dir (mkEffectFn1 $ (callback <<< toMaybe)) -- | Synchronously close the directory's underlying resource handle. @@ -42,7 +33,7 @@ closeSync = runEffectFn1 closeSyncImpl -- | Asynchronously read the next directory entry. read :: Dir -> (Either Error (Maybe (Dirent DirentNameTypeString)) -> Effect Unit) -> Effect Unit -read dir callback = runEffectFn2 readImpl dir (handleCallback2 (callback <<< map toMaybe)) +read dir callback = runEffectFn2 readImpl dir (handleCallback1 (callback <<< map toMaybe)) -- | Synchronously read the next directory entry. readSync :: Dir -> Effect (Maybe (Dirent DirentNameTypeString)) diff --git a/src/Node/FS/Internal/AffUtils.purs b/src/Node/FS/Internal/AffUtils.purs new file mode 100644 index 0000000..53d7957 --- /dev/null +++ b/src/Node/FS/Internal/AffUtils.purs @@ -0,0 +1,71 @@ +module Node.FS.Internal.AffUtils where + +import Prelude + +import Effect (Effect) +import Effect.Aff (Aff, makeAff, nonCanceler) +import Node.FS.Internal.Utils (Callback1) + +toAff + :: forall a + . (Callback1 a -> Effect Unit) + -> Aff a +toAff p = makeAff \k -> p k $> nonCanceler + +toAff1 + :: forall a x + . (x -> Callback1 a -> Effect Unit) + -> x + -> Aff a +toAff1 f a = toAff (f a) + +toAff2 + :: forall a x y + . (x -> y -> Callback1 a -> Effect Unit) + -> x + -> y + -> Aff a +toAff2 f a b = toAff (f a b) + +toAff3 + :: forall a x y z + . (x -> y -> z -> Callback1 a -> Effect Unit) + -> x + -> y + -> z + -> Aff a +toAff3 f a b c = toAff (f a b c) + +toAff4 + :: forall a v x y z + . (v -> x -> y -> z -> Callback1 a -> Effect Unit) + -> v + -> x + -> y + -> z + -> Aff a +toAff4 f a b c d = toAff (f a b c d) + +toAff5 + :: forall a w v x y z + . (w -> v -> x -> y -> z -> Callback1 a -> Effect Unit) + -> w + -> v + -> x + -> y + -> z + -> Aff a +toAff5 f a b c d e = toAff (f a b c d e) + +toAff6 + :: forall a w v x y z t + . (w -> v -> x -> y -> z -> t -> Callback1 a -> Effect Unit) + -> w + -> v + -> x + -> y + -> z + -> t + -> Aff a +toAff6 f a b c d e t = toAff (f a b c d e t) + diff --git a/src/Node/FS/Internal/Utils.purs b/src/Node/FS/Internal/Utils.purs new file mode 100644 index 0000000..3f488f2 --- /dev/null +++ b/src/Node/FS/Internal/Utils.purs @@ -0,0 +1,42 @@ +module Node.FS.Internal.Utils where + +import Prelude + +import Data.DateTime (DateTime) +import Data.DateTime.Instant (fromDateTime, unInstant) +import Data.Either (Either(..)) +import Data.Int (round) +import Data.Maybe (Maybe(..)) +import Data.Nullable (Nullable, toMaybe) +import Data.Time.Duration (Milliseconds(..)) +import Data.Tuple (Tuple(..)) +import Effect (Effect) +import Effect.Exception (Error) +import Effect.Uncurried (EffectFn1, EffectFn2, EffectFn3, mkEffectFn2, mkEffectFn3) + +type JSCallback0 = EffectFn1 (Nullable Error) Unit +type JSCallback1 a = EffectFn2 (Nullable Error) a Unit +type JSCallback2 a b = EffectFn3 (Nullable Error) a b Unit + +-- | Type synonym for callback functions. +type Callback0 = Maybe Error -> Effect Unit +type Callback1 a = Either Error a -> Effect Unit + +handleCallback1 :: forall a. Callback1 a -> JSCallback1 a +handleCallback1 cb = mkEffectFn2 \err a -> case toMaybe err of + Nothing -> cb (Right a) + Just err' -> cb (Left err') + +handleCallback1Tuple :: forall a b. Callback1 (Tuple a b) -> JSCallback2 a b +handleCallback1Tuple cb = mkEffectFn3 \err a b -> case toMaybe err of + Nothing -> cb (Right (Tuple a b)) + Just err' -> cb (Left err') + +---------------------- + +datetimeToUnixEpochTimeInSeconds :: DateTime -> Int +datetimeToUnixEpochTimeInSeconds date = ms (toEpochMilliseconds date) / 1000 + where + ms (Milliseconds n) = round n + toEpochMilliseconds = unInstant <<< fromDateTime + diff --git a/src/Node/FS/Options.purs b/src/Node/FS/Options.purs new file mode 100644 index 0000000..5af6a9a --- /dev/null +++ b/src/Node/FS/Options.purs @@ -0,0 +1,329 @@ +module Node.FS.Options where + +import Node.FS.Types (BufferLength, BufferOffset, FileMode, FilePosition) +import Prelude + +import Data.Function.Uncurried (Fn2, mkFn2) +import Data.Maybe (Maybe(..)) +import Data.Nullable (Nullable, toNullable) +import Data.Nullable as Nullable +import Foreign (Foreign) +import Foreign as Foreign +import Node.Buffer (Buffer) +import Node.Encoding (Encoding(..), encodingToNode) +import Node.FS.Constants (FileFlags(..), fileFlagsToNode) +import Node.FS.Dirent (Dirent, DirentNameTypeString) +import Node.FS.Perms (Perms, all, mkPerms, permsToString, read, write) +import Node.Path (FilePath) + +type RmdirOptions = { maxRetries :: Int, retryDelay :: Int } + +rmdirOptionsDefault :: RmdirOptions +rmdirOptionsDefault = { maxRetries: 0, retryDelay: 100 } + +type RmOptions = { force :: Boolean, maxRetries :: Int, recursive :: Boolean, retryDelay :: Int } + +rmOptionsDefault :: RmOptions +rmOptionsDefault = { force: false, maxRetries: 100, recursive: false, retryDelay: 1000 } + +---------- + +type MkdirOptionsInternal = { recursive :: Boolean, mode :: String } +type MkdirOptions = { recursive :: Boolean, mode :: Perms } + +mkdirOptionsDefault :: MkdirOptions +mkdirOptionsDefault = { recursive: false, mode: mkPerms all all all } + +mkdirOptionsToInternal :: MkdirOptions -> MkdirOptionsInternal +mkdirOptionsToInternal { recursive, mode } = { recursive, mode: permsToString mode } + +--------- + +type RealpathOptionsInternal = { encoding :: String } +type RealpathOptions = { encoding :: Encoding } + +realpathOptionsDefault :: RealpathOptions +realpathOptionsDefault = { encoding: UTF8 } + +realpathOptionsToInternal :: RealpathOptions -> RealpathOptionsInternal +realpathOptionsToInternal { encoding } = { encoding: encodingToNode encoding } + +--------- +type ReaddirOptionsInternal = + { encoding :: Foreign -- encoding string or "buffer" + , recursive :: Boolean + , withFileTypes :: Boolean + } + +type ReaddirFilePathOptions = { recursive :: Boolean, encoding :: Encoding } + +readdirFilePathOptionsDefault :: ReaddirFilePathOptions +readdirFilePathOptionsDefault = { recursive: false, encoding: UTF8 } + +readdirFilePathOptionsToInternal :: ReaddirFilePathOptions -> ReaddirOptionsInternal +readdirFilePathOptionsToInternal { recursive, encoding } = { recursive, encoding: Foreign.unsafeToForeign $ encodingToNode encoding, withFileTypes: false } + +type ReaddirBufferOptions = { recursive :: Boolean } + +readdirBufferOptionsDefault :: ReaddirBufferOptions +readdirBufferOptionsDefault = { recursive: false } + +readdirBufferOptionsToInternal :: ReaddirBufferOptions -> ReaddirOptionsInternal +readdirBufferOptionsToInternal { recursive } = { recursive, encoding: Foreign.unsafeToForeign "buffer", withFileTypes: false } + +type ReaddirDirentOptions = { recursive :: Boolean, encoding :: Encoding } + +readdirDirentOptionsDefault :: ReaddirDirentOptions +readdirDirentOptionsDefault = { recursive: false, encoding: UTF8 } + +readdirDirentOptionsToInternal :: ReaddirDirentOptions -> ReaddirOptionsInternal +readdirDirentOptionsToInternal { recursive, encoding } = { recursive, encoding: Foreign.unsafeToForeign $ encodingToNode encoding, withFileTypes: true } + +type ReaddirDirentBufferOptions = { recursive :: Boolean } + +readdirDirentBufferOptionsDefault :: ReaddirDirentBufferOptions +readdirDirentBufferOptionsDefault = { recursive: false } + +readdirDirentBufferOptionsToInternal :: ReaddirDirentBufferOptions -> ReaddirOptionsInternal +readdirDirentBufferOptionsToInternal { recursive } = { recursive, encoding: Foreign.unsafeToForeign "buffer", withFileTypes: true } + +--------- +type ReadFileOptionsInternal = + { encoding :: Nullable String -- if null - returns Buffer, if encoding string - String https://nodejs.org/docs/latest/api/fs.html#fsreadfilepath-options-callback + , flag :: String + -- , signal :: Nullable AbortSignal + } + +type ReadFileStringOptions = { flag :: FileFlags, encoding :: Encoding } + +readFileStringOptionsDefault :: ReadFileStringOptions +readFileStringOptionsDefault = { flag: R, encoding: UTF8 } + +readFileStringOptionsToInternal :: ReadFileStringOptions -> ReadFileOptionsInternal +readFileStringOptionsToInternal { flag, encoding } = { flag: fileFlagsToNode flag, encoding: Nullable.notNull $ encodingToNode encoding } + +type ReadFileBufferOptions = { flag :: FileFlags } + +readFileBufferOptionsDefault :: ReadFileBufferOptions +readFileBufferOptionsDefault = { flag: R } + +readFileBufferOptionsToInternal :: ReadFileBufferOptions -> ReadFileOptionsInternal +readFileBufferOptionsToInternal { flag } = { flag: fileFlagsToNode flag, encoding: Nullable.null } + +--------- +type WriteFileOptionsInternal = + { encoding :: Nullable String -- The encoding option is ignored if data is a buffer + , mode :: String + , flag :: String -- See support of file system flags. Default: 'w'. + , flush :: Boolean -- If all data is successfully written to the file, and flush is true, fs.fsync() is used to flush the data. Default: false. + -- , signal :: Nullable AbortSignal -- allows aborting an in-progress writeFile + } + +type WriteFileStringOptions = + { encoding :: Encoding + , mode :: Perms + , flag :: FileFlags + , flush :: Boolean + } + +writeFileStringOptionsDefault :: WriteFileStringOptions +writeFileStringOptionsDefault = + { encoding: UTF8 + , mode: mkPerms (read + write) (read + write) (read + write) + , flag: W + , flush: false + } + +writeFileStringOptionsToInternal :: WriteFileStringOptions -> WriteFileOptionsInternal +writeFileStringOptionsToInternal { encoding, mode, flag, flush } = { encoding: Nullable.notNull $ encodingToNode encoding, mode: permsToString mode, flag: fileFlagsToNode flag, flush } + +type WriteFileBufferOptions = + { mode :: Perms + , flag :: FileFlags + , flush :: Boolean + } + +writeFileBufferOptionsDefault :: WriteFileBufferOptions +writeFileBufferOptionsDefault = + { mode: mkPerms (read + write) (read + write) (read + write) + , flag: W + , flush: false + } + +writeFileBufferOptionsToInternal :: WriteFileBufferOptions -> WriteFileOptionsInternal +writeFileBufferOptionsToInternal { mode, flag, flush } = { mode: permsToString mode, flag: fileFlagsToNode flag, flush, encoding: Nullable.null } + +--------- +type AppendFileOptionsInternal = + { encoding :: Nullable String -- The encoding option is ignored if data is a buffer + , mode :: String + , flag :: String -- See support of file system flags. Default: 'w'. + , flush :: Boolean -- If all data is successfully written to the file, and flush is true, fs.fsync() is used to flush the data. Default: false. + } + +type AppendFileStringOptions = + { encoding :: Encoding + , mode :: Perms + , flag :: FileFlags + , flush :: Boolean + } + +appendFileStringOptionsDefault :: AppendFileStringOptions +appendFileStringOptionsDefault = + { encoding: UTF8 + , mode: mkPerms (read + write) (read + write) (read + write) + , flag: A + , flush: false + } + +appendFileStringOptionsToInternal :: AppendFileStringOptions -> AppendFileOptionsInternal +appendFileStringOptionsToInternal { encoding, mode, flag, flush } = { encoding: Nullable.notNull $ encodingToNode encoding, mode: permsToString mode, flag: fileFlagsToNode flag, flush } + +type AppendFileBufferOptions = + { mode :: Perms + , flag :: FileFlags + , flush :: Boolean + } + +appendFileBufferOptionsDefault :: AppendFileBufferOptions +appendFileBufferOptionsDefault = + { mode: mkPerms (read + write) (read + write) (read + write) + , flag: A + , flush: false + } + +appendFileBufferOptionsToInternal :: AppendFileBufferOptions -> AppendFileOptionsInternal +appendFileBufferOptionsToInternal { mode, flag, flush } = { mode: permsToString mode, flag: fileFlagsToNode flag, flush, encoding: Nullable.null } + +--------- +type FdReadOptionsInternal = + { buffer :: Nullable Buffer -- Default: `Buffer.alloc(16384)` + , offset :: BufferOffset -- Default: `0` + , length :: Nullable BufferLength -- Default: buffer.byteLength - offset + , position :: Nullable FilePosition + } + +type FdReadOptions = + { buffer :: Maybe Buffer + , offset :: BufferOffset + , length :: Maybe BufferLength + , position :: Maybe FilePosition -- If position is null or -1 , data will be read from the current file position, and the file position will be updated. If position is a non-negative integer, the file position will be unchanged. + } + +fdReadOptionsDefault :: FdReadOptions +fdReadOptionsDefault = + { buffer: Nothing + , offset: 0 + , length: Nothing + , position: Nothing + } + +fdReadOptionsToInternal :: FdReadOptions -> FdReadOptionsInternal +fdReadOptionsToInternal { buffer, offset, length, position } = { buffer: Nullable.toNullable buffer, offset, length: Nullable.toNullable length, position: Nullable.toNullable position } + +--------- +type FdWriteOptionsInternal = + { offset :: BufferOffset -- Default: `0` + , length :: Nullable BufferLength -- Default: buffer.byteLength - offset + , position :: Nullable FilePosition + } + +type FdWriteOptions = + { offset :: BufferOffset + , length :: Maybe BufferLength + , position :: Maybe FilePosition -- If position is null or -1 , data will be write from the current file position, and the file position will be updated. If position is a non-negative integer, the file position will be unchanged. + } + +fdWriteOptionsDefault :: FdWriteOptions +fdWriteOptionsDefault = + { offset: 0 + , length: Nothing + , position: Nothing + } + +fdWriteOptionsToInternal :: FdWriteOptions -> FdWriteOptionsInternal +fdWriteOptionsToInternal { offset, length, position } = { offset, length: Nullable.toNullable length, position: Nullable.toNullable position } + +------------------- + +type CpOptionsInternal = + { dereference :: Boolean + , errorOnExist :: Boolean + , filter :: Nullable (Fn2 FilePath FilePath Boolean) + , force :: Boolean + , mode :: FileMode + , preserveTimestamps :: Boolean + , recursive :: Boolean + , verbatimSymlinks :: Boolean + } + +data CpForce = CpForce_False | CpForce_TrueWithoutErrorOnExit | CpForce_TrueWithErrorOnExit + +type CpOptions = + { dereference :: Boolean -- Whether to dereference symlinks + , filter :: Maybe (FilePath -> FilePath -> Boolean) + , force :: CpForce + , mode :: FileMode -- Modifiers for copy operation + , preserveTimestamps :: Boolean -- Preserve timestamps from source + , recursive :: Boolean -- Copy directories recursively + , verbatimSymlinks :: Boolean -- Skip path resolution for symlinks + } + +cpOptionsDefault :: CpOptions +cpOptionsDefault = + { dereference: false + , filter: Nothing + , force: CpForce_TrueWithoutErrorOnExit + , mode: 0 + , preserveTimestamps: false + , recursive: false + , verbatimSymlinks: false + } + +cpOptionsToCpOptionsInternal :: CpOptions -> CpOptionsInternal +cpOptionsToCpOptionsInternal opts = + { dereference: opts.dereference + , errorOnExist: case opts.force of + CpForce_TrueWithErrorOnExit -> true + _ -> false + , filter: toNullable $ map mkFn2 (opts.filter) + , force: case opts.force of + CpForce_False -> false + _ -> true + , mode: opts.mode + , preserveTimestamps: opts.preserveTimestamps + , recursive: opts.recursive + , verbatimSymlinks: opts.verbatimSymlinks + } + +------------------ + +type GlobOptionsInternal filepathOrDirent = { cwd :: Nullable FilePath, exclude :: Nullable (filepathOrDirent -> Boolean), withFileTypes :: Boolean } + +type GlobFilePathOptions = { cwd :: Maybe FilePath, exclude :: Maybe (FilePath -> Boolean) } + +globFilePathOptionsDefault :: GlobFilePathOptions +globFilePathOptionsDefault = { cwd: Nothing, exclude: Nothing } + +globFilePathOptionsToInternal :: GlobFilePathOptions -> GlobOptionsInternal FilePath +globFilePathOptionsToInternal { cwd, exclude } = { cwd: toNullable cwd, exclude: toNullable exclude, withFileTypes: false } + +type GlobDirentOptions = { cwd :: Maybe FilePath, exclude :: Maybe (Dirent DirentNameTypeString -> Boolean) } + +globDirentOptionsDefault :: GlobDirentOptions +globDirentOptionsDefault = { cwd: Nothing, exclude: Nothing } + +globDirentOptionsToInternal :: GlobDirentOptions -> GlobOptionsInternal (Dirent DirentNameTypeString) +globDirentOptionsToInternal { cwd, exclude } = { cwd: toNullable cwd, exclude: toNullable exclude, withFileTypes: true } + +------------------ + +type OpendirOptionsInternal = { encoding :: String, bufferSize :: Int, recursive :: Boolean } +type OpendirOptions = { encoding :: Encoding, bufferSize :: Int, recursive :: Boolean } + +opendirOptionsDefault :: OpendirOptions +opendirOptionsDefault = { bufferSize: 32, recursive: false, encoding: UTF8 } + +opendirOptionsToInternal :: OpendirOptions -> OpendirOptionsInternal +opendirOptionsToInternal { encoding, bufferSize, recursive } = { encoding: encodingToNode encoding, bufferSize, recursive } + diff --git a/src/Node/FS/Sync.js b/src/Node/FS/Sync.js index 166b656..89e3178 100644 --- a/src/Node/FS/Sync.js +++ b/src/Node/FS/Sync.js @@ -27,20 +27,19 @@ export { writeSync as writeSyncImpl, fsyncSync as fsyncSyncImpl, closeSync as closeSyncImpl, - // TODO: implement - // cpSync as cpSyncImpl, - // fchmodSync as fchmodSyncImpl, - // fchownSync as fchownSyncImpl, - // fdatasyncSync as fdatasyncSyncImpl, - // fstatSync as fstatSyncImpl, - // ftruncateSync as ftruncateSyncImpl, - // futimesSync as futimesSyncImpl, - // globSync as globSyncImpl, - // lchmodSync as lchmodSyncImpl, - // lchownSync as lchownSyncImpl, - // lutimesSync as lutimesSyncImpl, - // opendirSync as opendirSyncImpl, - // readvSync as readvSyncImpl, - // statfsSync as statfsSyncImpl, - // writevSync as writevSyncImpl + cpSync as cpSyncImpl, + fchmodSync as fchmodSyncImpl, + fchownSync as fchownSyncImpl, + fdatasyncSync as fdatasyncSyncImpl, + fstatSync as fstatSyncImpl, + ftruncateSync as ftruncateSyncImpl, + futimesSync as futimesSyncImpl, + globSync as globSyncImpl, + lchmodSync as lchmodSyncImpl, + lchownSync as lchownSyncImpl, + lutimesSync as lutimesSyncImpl, + opendirSync as opendirSyncImpl, + readvSync as readvSyncImpl, + statfsSync as statfsSyncImpl, + writevSync as writevSyncImpl } from "node:fs"; diff --git a/src/Node/FS/Types.purs b/src/Node/FS/Types.purs new file mode 100644 index 0000000..94e5cc9 --- /dev/null +++ b/src/Node/FS/Types.purs @@ -0,0 +1,34 @@ +module Node.FS.Types where + +import Prelude + +import Data.Nullable (Nullable) +import Data.Nullable as Nullable + +foreign import data FileDescriptor :: Type + +type FileMode = Int +type FilePosition = Int +type BufferLength = Int +type BufferOffset = Int +type ByteCount = Int + +-- | Symlink varieties. +data SymlinkType = FileLink | DirLink | JunctionLink | AutodetectLink + +-- | Convert a `SymlinkType` to a `String` in the format expected by the +-- | Node.js filesystem API. +symlinkTypeToNode :: SymlinkType -> Nullable String +symlinkTypeToNode ty = case ty of + FileLink -> Nullable.notNull "file" + DirLink -> Nullable.notNull "dir" + JunctionLink -> Nullable.notNull "junction" + AutodetectLink -> Nullable.null + +instance showSymlinkType :: Show SymlinkType where + show FileLink = "FileLink" + show DirLink = "DirLink" + show JunctionLink = "JunctionLink" + show AutodetectLink = "AutodetectLink" + +derive instance eqSymlinkType :: Eq SymlinkType diff --git a/test/Test/Node/FS/OpendirAndDir.purs b/test/Test/Node/FS/OpendirAndDir.purs index 85487ee..8d49551 100644 --- a/test/Test/Node/FS/OpendirAndDir.purs +++ b/test/Test/Node/FS/OpendirAndDir.purs @@ -11,7 +11,8 @@ import Effect.Class (liftEffect) import Effect.Console (log) import Effect.Exception (Error) import Node.Encoding (Encoding(..)) -import Node.FS.Aff (opendirOptionsDefault, rmOptionsDefault) +import Node.FS.Aff +import Node.FS.Options import Node.FS.Aff as A import Node.FS.Aff.Dir (close, entries, read) import Node.FS.Dirent (Dirent, DirentNameTypeString) diff --git a/test/Test/Node/FS/Sync.purs b/test/Test/Node/FS/Sync.purs index 994ddc6..25327eb 100644 --- a/test/Test/Node/FS/Sync.purs +++ b/test/Test/Node/FS/Sync.purs @@ -11,12 +11,13 @@ import Effect.Exception (Error, catchException, error, message, throw, throwExce import Node.Buffer as Buffer import Node.Encoding (Encoding(..)) import Node.FS (FileFlags(..), SymlinkType(..)) -import Node.FS.Aff (rmOptionsDefault) +import Node.FS.Aff import Node.FS.Async as A import Node.FS.Constants (copyFile_EXCL, r_OK, w_OK) import Node.FS.Perms (mkPerms, permsAll) import Node.FS.Perms as Perms import Node.FS.Stats (statusChangedTime, accessedTime, modifiedTime, isSymbolicLink, isSocket, isFIFO, isCharacterDevice, isBlockDevice, isDirectory, isFile) +import Node.FS.Options import Node.FS.Sync (chmod) import Node.FS.Sync as S import Node.Path as Path From 4216697c8a4c58628f5e2a7eda26573b4ab45cb6 Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Sun, 6 Oct 2024 16:59:47 +0700 Subject: [PATCH 10/32] feat: sync -> implement --- src/Node/FS/Aff/Dir.purs | 11 +- src/Node/FS/Async.purs | 191 ++++++------ src/Node/FS/Dir.purs | 8 +- src/Node/FS/Internal/Utils.purs | 9 +- src/Node/FS/Options.purs | 8 +- src/Node/FS/Sync.js | 6 +- src/Node/FS/Sync.purs | 450 ++++++++++++++++++++++----- src/Node/FS/Types.purs | 33 +- test/Test/Node/FS/OpendirAndDir.purs | 16 +- test/Test/Node/FS/Sync.purs | 3 +- 10 files changed, 528 insertions(+), 207 deletions(-) diff --git a/src/Node/FS/Aff/Dir.purs b/src/Node/FS/Aff/Dir.purs index 2fa6fb0..c3abcc7 100644 --- a/src/Node/FS/Aff/Dir.purs +++ b/src/Node/FS/Aff/Dir.purs @@ -19,14 +19,14 @@ import Effect.Ref as Ref import Node.FS.Dir (Dir) import Node.FS.Dir as Dir import Node.FS.Dirent (Dirent, DirentNameTypeString) -import Node.FS.Internal.AffUtils +import Node.FS.Internal.AffUtils (toAff1) read :: Dir -> Aff (Maybe (Dirent DirentNameTypeString)) read = toAff1 Dir.read -close :: Dir -> Aff (Maybe Error) +close :: Dir -> Aff Unit close dir = makeAff \k -> do - Dir.close dir (k <<< Right) + Dir.close dir k pure nonCanceler entries :: Dir -> Aff (Array (Dirent DirentNameTypeString)) @@ -43,13 +43,12 @@ entries dir = do -- | Implementation - https://github.com/nodejs/node/blob/b2161d3a137e5a2582c71c798e140d2ba8f7c1d4/lib/internal/fs/dir.js#L257 -- | -- | Nodejs version ignores errors on read, doesnt ignore errors on close. --- | This purs version ignores error at close, doesnt ignore errors at read. --- | But in reality - behavior should be the same (proved in tests). +-- | Purescript version - the same (proved in tests). -- | -- | Possible errors: -- | - if dir is closed already - `read` and `close` will throw "Directory handle was closed" entriesIterate :: Dir -> ((Dirent DirentNameTypeString) -> Effect Unit) -> Aff Unit -entriesIterate dir handleDirent = finally (void $ close dir) $ makeAff \(k :: Either Error Unit -> Effect Unit) -> do +entriesIterate dir handleDirent = finally (close dir) $ makeAff \(k :: Either Error Unit -> Effect Unit) -> do stopRef <- Ref.new false go k stopRef pure $ effectCanceler $ Ref.write true stopRef diff --git a/src/Node/FS/Async.purs b/src/Node/FS/Async.purs index 0beecca..ac18dce 100644 --- a/src/Node/FS/Async.purs +++ b/src/Node/FS/Async.purs @@ -33,10 +33,15 @@ module Node.FS.Async , readdirDirentBuffer' , utimes , readFile + , readFile' , readTextFile + , readTextFile' , writeFile + , writeFile' , writeTextFile + , writeTextFile' , appendFile + , appendFile' , appendTextFile , fdOpen , fdRead @@ -87,7 +92,7 @@ import Node.Buffer (Buffer, size) import Node.Encoding (Encoding(..), encodingToNode) import Node.FS (FileDescriptor, ByteCount, FilePosition, BufferLength, BufferOffset, FileMode, SymlinkType, symlinkTypeToNode) import Node.FS.Constants -import Node.FS.Internal.Utils +import Node.FS.Internal.Utils import Node.FS.Options import Node.FS.Dir (Dir) import Node.FS.Dirent (Dirent, DirentNameTypeBuffer, DirentNameTypeString) @@ -96,30 +101,30 @@ import Node.FS.Stats (Stats) import Node.Path (FilePath) import Unsafe.Coerce (unsafeCoerce) -foreign import accessImpl :: EffectFn3 FilePath AccessMode (EffectFn1 (Nullable Error) Unit) Unit -foreign import copyFileImpl :: EffectFn4 FilePath FilePath CopyMode (JSCallback1 Unit) Unit +foreign import accessImpl :: EffectFn3 FilePath AccessMode JSCallback0 Unit +foreign import copyFileImpl :: EffectFn4 FilePath FilePath CopyMode JSCallback0 Unit foreign import mkdtempImpl :: EffectFn3 FilePath FilePath (JSCallback1 FilePath) Unit -foreign import renameImpl :: EffectFn3 FilePath FilePath (JSCallback1 Unit) Unit -foreign import truncateImpl :: EffectFn3 FilePath Int (JSCallback1 Unit) Unit -foreign import chownImpl :: EffectFn4 FilePath Int Int (JSCallback1 Unit) Unit -foreign import chmodImpl :: EffectFn3 FilePath String (JSCallback1 Unit) Unit +foreign import renameImpl :: EffectFn3 FilePath FilePath JSCallback0 Unit +foreign import truncateImpl :: EffectFn3 FilePath Int JSCallback0 Unit +foreign import chownImpl :: EffectFn4 FilePath Int Int JSCallback0 Unit +foreign import chmodImpl :: EffectFn3 FilePath String JSCallback0 Unit foreign import statImpl :: EffectFn2 FilePath (JSCallback1 Stats) Unit foreign import lstatImpl :: EffectFn2 FilePath (JSCallback1 Stats) Unit -foreign import linkImpl :: EffectFn3 FilePath FilePath (JSCallback1 Unit) Unit -foreign import symlinkImpl :: EffectFn4 FilePath FilePath (Nullable String) (JSCallback1 Unit) Unit +foreign import linkImpl :: EffectFn3 FilePath FilePath JSCallback0 Unit +foreign import symlinkImpl :: EffectFn4 FilePath FilePath (Nullable String) JSCallback0 Unit foreign import readlinkImpl :: EffectFn2 FilePath (JSCallback1 FilePath) Unit foreign import realpathImpl :: EffectFn3 FilePath RealpathOptionsInternal (JSCallback1 FilePath) Unit -foreign import unlinkImpl :: EffectFn2 FilePath (JSCallback1 Unit) Unit -foreign import rmdirImpl :: EffectFn3 FilePath RmdirOptions (JSCallback1 Unit) Unit -foreign import rmImpl :: EffectFn3 FilePath RmOptions (JSCallback1 Unit) Unit -foreign import mkdirImpl :: EffectFn3 FilePath MkdirOptionsInternal (JSCallback1 Unit) Unit +foreign import unlinkImpl :: EffectFn2 FilePath JSCallback0 Unit +foreign import rmdirImpl :: EffectFn3 FilePath RmdirOptions JSCallback0 Unit +foreign import rmImpl :: EffectFn3 FilePath RmOptions JSCallback0 Unit +foreign import mkdirImpl :: EffectFn3 FilePath MkdirOptionsInternal JSCallback0 Unit -- if { withFileTypes: false, recursive: false } => ['Tidy'] -- if { withFileTypes: false, recursive: true } => [ 'Tidy', 'Tidy/Codegen', 'Tidy/Codegen.purs', 'Tidy/Codegen/Class.purs', .. ] -foreign import readdirImpl :: forall filepathOrDirentOrBuffer . EffectFn3 FilePath ReaddirOptionsInternal (JSCallback1 (Array filepathOrDirentOrBuffer)) Unit -foreign import utimesImpl :: EffectFn4 FilePath Int Int (JSCallback1 Unit) Unit -foreign import readFileImpl :: forall stringOrBuffer . EffectFn3 FilePath ReadFileOptionsInternal (JSCallback1 stringOrBuffer) Unit -foreign import writeFileImpl :: forall stringOrBuffer . EffectFn4 FilePath stringOrBuffer WriteFileOptionsInternal (JSCallback1 Unit) Unit -foreign import appendFileImpl :: forall stringOrBuffer . EffectFn4 FilePath stringOrBuffer AppendFileOptionsInternal (JSCallback1 Unit) Unit +foreign import readdirImpl :: forall filepathOrDirentOrBuffer. EffectFn3 FilePath ReaddirOptionsInternal (JSCallback1 (Array filepathOrDirentOrBuffer)) Unit +foreign import utimesImpl :: EffectFn4 FilePath Int Int JSCallback0 Unit +foreign import readFileImpl :: forall stringOrBuffer. EffectFn3 FilePath ReadFileOptionsInternal (JSCallback1 stringOrBuffer) Unit +foreign import writeFileImpl :: forall stringOrBuffer. EffectFn4 FilePath stringOrBuffer WriteFileOptionsInternal JSCallback0 Unit +foreign import appendFileImpl :: forall stringOrBuffer. EffectFn4 FilePath stringOrBuffer AppendFileOptionsInternal JSCallback0 Unit foreign import openImpl :: EffectFn4 FilePath String (Nullable FileMode) (JSCallback1 FileDescriptor) Unit foreign import readImpl :: EffectFn6 FileDescriptor Buffer BufferOffset BufferLength (Nullable FilePosition) (JSCallback1 ByteCount) Unit @@ -137,19 +142,19 @@ writeWithOptionsImpl = unsafeCoerce writeImpl writeStringImpl :: EffectFn5 FileDescriptor String (Nullable FilePosition) String (JSCallback2 ByteCount String) Unit writeStringImpl = unsafeCoerce writeImpl -foreign import closeImpl :: EffectFn2 FileDescriptor (JSCallback1 Unit) Unit -foreign import cpImpl :: EffectFn4 FilePath FilePath CpOptionsInternal (JSCallback1 Unit) Unit -foreign import fchmodImpl :: EffectFn3 FileDescriptor String (JSCallback1 Unit) Unit -foreign import fchownImpl :: EffectFn4 FileDescriptor Int Int (JSCallback1 Unit) Unit -foreign import fdatasyncImpl :: EffectFn2 FileDescriptor (JSCallback1 Unit) Unit +foreign import closeImpl :: EffectFn2 FileDescriptor JSCallback0 Unit +foreign import cpImpl :: EffectFn4 FilePath FilePath CpOptionsInternal JSCallback0 Unit +foreign import fchmodImpl :: EffectFn3 FileDescriptor String JSCallback0 Unit +foreign import fchownImpl :: EffectFn4 FileDescriptor Int Int JSCallback0 Unit +foreign import fdatasyncImpl :: EffectFn2 FileDescriptor JSCallback0 Unit foreign import fstatImpl :: EffectFn2 FileDescriptor (JSCallback1 Stats) Unit -foreign import fsyncImpl :: EffectFn2 FileDescriptor (JSCallback1 Unit) Unit -foreign import ftruncateImpl :: EffectFn3 FileDescriptor Int (JSCallback1 Unit) Unit -foreign import futimesImpl :: EffectFn4 FileDescriptor Int Int (JSCallback1 Unit) Unit +foreign import fsyncImpl :: EffectFn2 FileDescriptor JSCallback0 Unit +foreign import ftruncateImpl :: EffectFn3 FileDescriptor Int JSCallback0 Unit +foreign import futimesImpl :: EffectFn4 FileDescriptor Int Int JSCallback0 Unit foreign import globImpl :: forall filepathOrDirent. EffectFn3 (Array FilePath) (GlobOptionsInternal filepathOrDirent) (JSCallback1 (Array filepathOrDirent)) Unit -foreign import lchmodImpl :: EffectFn3 FilePath String (JSCallback1 Unit) Unit -foreign import lchownImpl :: EffectFn4 FilePath Int Int (JSCallback1 Unit) Unit -foreign import lutimesImpl :: EffectFn4 FilePath Int Int (JSCallback1 Unit) Unit +foreign import lchmodImpl :: EffectFn3 FilePath String JSCallback0 Unit +foreign import lchownImpl :: EffectFn4 FilePath Int Int JSCallback0 Unit +foreign import lutimesImpl :: EffectFn4 FilePath Int Int JSCallback0 Unit -- foreign import openAsBlobImpl :: EffectFn2 FilePath (Promise Blob) Unit foreign import opendirImpl :: EffectFn3 FilePath OpendirOptionsInternal (JSCallback1 Dir) Unit foreign import readvImpl :: EffectFn4 FileDescriptor (Array Buffer) (Nullable FilePosition) (JSCallback2 ByteCount (Array Buffer)) Unit @@ -165,11 +170,11 @@ access path = access' path defaultAccessMode access' :: FilePath -> AccessMode -> (Maybe Error -> Effect Unit) -> Effect Unit access' path mode cb = runEffectFn3 accessImpl path mode $ mkEffectFn1 (cb <<< toMaybe) -copyFile :: FilePath -> FilePath -> Callback1 Unit -> Effect Unit +copyFile :: FilePath -> FilePath -> Callback0 -> Effect Unit copyFile src dest = copyFile' src dest defaultCopyMode -copyFile' :: FilePath -> FilePath -> CopyMode -> Callback1 Unit -> Effect Unit -copyFile' src dest mode cb = runEffectFn4 copyFileImpl src dest mode (handleCallback1 cb) +copyFile' :: FilePath -> FilePath -> CopyMode -> Callback0 -> Effect Unit +copyFile' src dest mode cb = runEffectFn4 copyFileImpl src dest mode (handleCallback0 cb) mkdtemp :: FilePath -> Callback1 FilePath -> Effect Unit mkdtemp prefix = mkdtemp' prefix UTF8 @@ -181,34 +186,34 @@ mkdtemp' prefix encoding cb = runEffectFn3 mkdtempImpl prefix (encodingToNode en rename :: FilePath -> FilePath - -> Callback1 Unit + -> Callback0 -> Effect Unit -rename oldFile newFile cb = runEffectFn3 renameImpl oldFile newFile (handleCallback1 cb) +rename oldFile newFile cb = runEffectFn3 renameImpl oldFile newFile (handleCallback0 cb) -- | Truncates a file to the specified length. truncate :: FilePath -> Int - -> Callback1 Unit + -> Callback0 -> Effect Unit -truncate file len cb = runEffectFn3 truncateImpl file len (handleCallback1 cb) +truncate file len cb = runEffectFn3 truncateImpl file len (handleCallback0 cb) -- | Changes the ownership of a file. chown :: FilePath -> Int -> Int - -> Callback1 Unit + -> Callback0 -> Effect Unit -chown file uid gid cb = runEffectFn4 chownImpl file uid gid (handleCallback1 cb) +chown file uid gid cb = runEffectFn4 chownImpl file uid gid (handleCallback0 cb) -- | Changes the permissions of a file. chmod :: FilePath -> Perms - -> Callback1 Unit + -> Callback0 -> Effect Unit -chmod file perms cb = runEffectFn3 chmodImpl file (permsToString perms) (handleCallback1 cb) +chmod file perms cb = runEffectFn3 chmodImpl file (permsToString perms) (handleCallback0 cb) -- | Gets file statistics. stat @@ -230,18 +235,18 @@ lstat file cb = runEffectFn2 lstatImpl file (handleCallback1 $ cb) link :: FilePath -> FilePath - -> Callback1 Unit + -> Callback0 -> Effect Unit -link src dst cb = runEffectFn3 linkImpl src dst (handleCallback1 cb) +link src dst cb = runEffectFn3 linkImpl src dst (handleCallback0 cb) -- | Creates a symlink. symlink :: FilePath -> FilePath -> SymlinkType - -> Callback1 Unit + -> Callback0 -> Effect Unit -symlink src dest ty cb = runEffectFn4 symlinkImpl src dest (symlinkTypeToNode ty) (handleCallback1 cb) +symlink src dest ty cb = runEffectFn4 symlinkImpl src dest (symlinkTypeToNode ty) (handleCallback0 cb) -- | Reads the value of a symlink. readlink @@ -269,14 +274,14 @@ realpath' path options cb = runEffectFn3 realpathImpl path (realpathOptionsToInt -- | Deletes a file. unlink :: FilePath - -> Callback1 Unit + -> Callback0 -> Effect Unit -unlink file cb = runEffectFn2 unlinkImpl file (handleCallback1 cb) +unlink file cb = runEffectFn2 unlinkImpl file (handleCallback0 cb) -- | Deletes a directory. rmdir :: FilePath - -> Callback1 Unit + -> Callback0 -> Effect Unit rmdir path cb = rmdir' path rmdirOptionsDefault cb @@ -284,14 +289,14 @@ rmdir path cb = rmdir' path rmdirOptionsDefault cb rmdir' :: FilePath -> RmdirOptions - -> Callback1 Unit + -> Callback0 -> Effect Unit -rmdir' path opts cb = runEffectFn3 rmdirImpl path opts (handleCallback1 cb) +rmdir' path opts cb = runEffectFn3 rmdirImpl path opts (handleCallback0 cb) -- | Deletes a file or directory. rm :: FilePath - -> Callback1 Unit + -> Callback0 -> Effect Unit rm path = rm' path rmOptionsDefault @@ -299,14 +304,14 @@ rm path = rm' path rmOptionsDefault rm' :: FilePath -> RmOptions - -> Callback1 Unit + -> Callback0 -> Effect Unit -rm' path opts cb = runEffectFn3 rmImpl path opts (handleCallback1 cb) +rm' path opts cb = runEffectFn3 rmImpl path opts (handleCallback0 cb) -- | Makes a new directory. mkdir :: FilePath - -> Callback1 Unit + -> Callback0 -> Effect Unit mkdir path = mkdir' path mkdirOptionsDefault @@ -314,9 +319,9 @@ mkdir path = mkdir' path mkdirOptionsDefault mkdir' :: FilePath -> MkdirOptions - -> Callback1 Unit + -> Callback0 -> Effect Unit -mkdir' file opts cb = runEffectFn3 mkdirImpl file (mkdirOptionsToInternal opts) (handleCallback1 cb) +mkdir' file opts cb = runEffectFn3 mkdirImpl file (mkdirOptionsToInternal opts) (handleCallback0 cb) -- | Reads the contents of a directory. readdir @@ -383,9 +388,9 @@ utimes :: FilePath -> DateTime -> DateTime - -> Callback1 Unit + -> Callback0 -> Effect Unit -utimes file atime mtime cb = runEffectFn4 utimesImpl file (datetimeToUnixEpochTimeInSeconds atime) (datetimeToUnixEpochTimeInSeconds mtime) (handleCallback1 cb) +utimes file atime mtime cb = runEffectFn4 utimesImpl file (datetimeToUnixEpochTimeInSeconds atime) (datetimeToUnixEpochTimeInSeconds mtime) (handleCallback0 cb) -- | Reads the entire contents of a text file with the specified encoding. readTextFile @@ -421,7 +426,7 @@ writeTextFile :: Encoding -> FilePath -> String - -> Callback1 Unit + -> Callback0 -> Effect Unit writeTextFile encoding file buff = writeTextFile' file buff (writeFileStringOptionsDefault { encoding = encoding }) @@ -429,15 +434,15 @@ writeTextFile' :: FilePath -> String -> WriteFileStringOptions - -> Callback1 Unit + -> Callback0 -> Effect Unit -writeTextFile' file buff options cb = runEffectFn4 writeFileImpl file buff (writeFileStringOptionsToInternal options) (handleCallback1 cb) +writeTextFile' file buff options cb = runEffectFn4 writeFileImpl file buff (writeFileStringOptionsToInternal options) (handleCallback0 cb) -- | Writes a buffer to a file. writeFile :: FilePath -> Buffer - -> Callback1 Unit + -> Callback0 -> Effect Unit writeFile file buff = writeFile' file buff writeFileBufferOptionsDefault @@ -445,32 +450,32 @@ writeFile' :: FilePath -> Buffer -> WriteFileBufferOptions - -> Callback1 Unit + -> Callback0 -> Effect Unit -writeFile' file buff options cb = runEffectFn4 writeFileImpl file buff (writeFileBufferOptionsToInternal options) (handleCallback1 cb) +writeFile' file buff options cb = runEffectFn4 writeFileImpl file buff (writeFileBufferOptionsToInternal options) (handleCallback0 cb) -- | Appends text to a file using the specified encoding. appendTextFile :: Encoding -> FilePath -> String - -> Callback1 Unit + -> Callback0 -> Effect Unit -appendTextFile encoding file buff = appendTextFile' file buff (appendFileStringOptionsDefault { encoding = encoding }) +appendTextFile encoding file buff = appendTextFile' file buff (appendFileStringOptionsDefault { encoding = encoding }) appendTextFile' :: FilePath -> String -> AppendFileStringOptions - -> Callback1 Unit + -> Callback0 -> Effect Unit -appendTextFile' file buff options cb = runEffectFn4 appendFileImpl file buff (appendFileStringOptionsToInternal options) (handleCallback1 cb) +appendTextFile' file buff options cb = runEffectFn4 appendFileImpl file buff (appendFileStringOptionsToInternal options) (handleCallback0 cb) -- | Appends a buffer to a file. appendFile :: FilePath -> Buffer - -> Callback1 Unit + -> Callback0 -> Effect Unit appendFile file buff = appendFile' file buff appendFileBufferOptionsDefault @@ -478,9 +483,9 @@ appendFile' :: FilePath -> Buffer -> AppendFileBufferOptions - -> Callback1 Unit + -> Callback0 -> Effect Unit -appendFile' file buff options cb = runEffectFn4 appendFileImpl file buff (appendFileBufferOptionsToInternal options) (handleCallback1 cb) +appendFile' file buff options cb = runEffectFn4 appendFileImpl file buff (appendFileBufferOptionsToInternal options) (handleCallback0 cb) -- | Open a file asynchronously. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_open_path_flags_mode_callback) -- | for details. @@ -570,32 +575,32 @@ fdAppend fd buff cb = do -- | for details. fdClose :: FileDescriptor - -> Callback1 Unit + -> Callback0 -> Effect Unit -fdClose fd cb = runEffectFn2 closeImpl fd (handleCallback1 cb) +fdClose fd cb = runEffectFn2 closeImpl fd (handleCallback0 cb) -- | Copy a file asynchronously. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fspromises_copyfile_src_dest_mode) -- | for details. -cp :: FilePath -> FilePath -> Callback1 Unit -> Effect Unit +cp :: FilePath -> FilePath -> Callback0 -> Effect Unit cp src dest = cp' src dest cpOptionsDefault -cp' :: FilePath -> FilePath -> CpOptions -> Callback1 Unit -> Effect Unit -cp' src dest opts cb = runEffectFn4 cpImpl src dest (cpOptionsToCpOptionsInternal opts) (handleCallback1 cb) +cp' :: FilePath -> FilePath -> CpOptions -> Callback0 -> Effect Unit +cp' src dest opts cb = runEffectFn4 cpImpl src dest (cpOptionsToCpOptionsInternal opts) (handleCallback0 cb) -- | Change permissions on a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fchmod_fd_mode_callback) -- | for details. -fchmod :: FileDescriptor -> Perms -> Callback1 Unit -> Effect Unit -fchmod fd perms cb = runEffectFn3 fchmodImpl fd (permsToString perms) (handleCallback1 cb) +fchmod :: FileDescriptor -> Perms -> Callback0 -> Effect Unit +fchmod fd perms cb = runEffectFn3 fchmodImpl fd (permsToString perms) (handleCallback0 cb) -- | Change ownership of a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fchown_fd_uid_gid_callback) -- | for details. -fchown :: FileDescriptor -> Int -> Int -> Callback1 Unit -> Effect Unit -fchown fd uid gid cb = runEffectFn4 fchownImpl fd uid gid (handleCallback1 cb) +fchown :: FileDescriptor -> Int -> Int -> Callback0 -> Effect Unit +fchown fd uid gid cb = runEffectFn4 fchownImpl fd uid gid (handleCallback0 cb) -- | Synchronize a file's in-core state with storage. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fdatasync_fd_callback) -- | for details. -fdatasync :: FileDescriptor -> Callback1 Unit -> Effect Unit -fdatasync fd cb = runEffectFn2 fdatasyncImpl fd (handleCallback1 cb) +fdatasync :: FileDescriptor -> Callback0 -> Effect Unit +fdatasync fd cb = runEffectFn2 fdatasyncImpl fd (handleCallback0 cb) -- | Get file status information. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fstat_fd_callback) -- | for details. @@ -604,13 +609,13 @@ fstat fd cb = runEffectFn2 fstatImpl fd (handleCallback1 cb) -- | Flushes a file descriptor to disk. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fsync_fd_callback) -- | for details. -fsync :: FileDescriptor -> Callback1 Unit -> Effect Unit -fsync fd cb = runEffectFn2 fsyncImpl fd (handleCallback1 cb) +fsync :: FileDescriptor -> Callback0 -> Effect Unit +fsync fd cb = runEffectFn2 fsyncImpl fd (handleCallback0 cb) -- | Truncate a file to a specified length. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_ftruncate_fd_len_callback) -- | for details. -ftruncate :: FileDescriptor -> Int -> Callback1 Unit -> Effect Unit -ftruncate fd len cb = runEffectFn3 ftruncateImpl fd len (handleCallback1 cb) +ftruncate :: FileDescriptor -> Int -> Callback0 -> Effect Unit +ftruncate fd len cb = runEffectFn3 ftruncateImpl fd len (handleCallback0 cb) -- | Change file timestamps for a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_futimes_fd_atime_mtime_callback) -- | for details. @@ -618,9 +623,9 @@ futimes :: FilePath -> DateTime -> DateTime - -> Callback1 Unit + -> Callback0 -> Effect Unit -futimes file atime mtime cb = runEffectFn4 lutimesImpl file (datetimeToUnixEpochTimeInSeconds atime) (datetimeToUnixEpochTimeInSeconds mtime) (handleCallback1 cb) +futimes file atime mtime cb = runEffectFn4 lutimesImpl file (datetimeToUnixEpochTimeInSeconds atime) (datetimeToUnixEpochTimeInSeconds mtime) (handleCallback0 cb) -- | Perform pattern matching in file paths. See the [Node Documentation](https://nodejs.org/api/glob.html#globglob_pattern_options_callback) -- | for details. @@ -638,13 +643,13 @@ globDirent' pattern options cb = runEffectFn3 globImpl pattern (globDirentOption -- | Change permissions on a symbolic link. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_lchmod_path_mode_callback) -- | for details. -lchmod :: FilePath -> Perms -> Callback1 Unit -> Effect Unit -lchmod path perms cb = runEffectFn3 lchmodImpl path (permsToString perms) (handleCallback1 cb) +lchmod :: FilePath -> Perms -> Callback0 -> Effect Unit +lchmod path perms cb = runEffectFn3 lchmodImpl path (permsToString perms) (handleCallback0 cb) -- | Change ownership of a symbolic link. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_lchown_path_uid_gid_callback) -- | for details. -lchown :: FilePath -> Int -> Int -> Callback1 Unit -> Effect Unit -lchown path uid gid cb = runEffectFn4 lchownImpl path uid gid (handleCallback1 cb) +lchown :: FilePath -> Int -> Int -> Callback0 -> Effect Unit +lchown path uid gid cb = runEffectFn4 lchownImpl path uid gid (handleCallback0 cb) -- | Change timestamps for a symbolic link. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_lutimes_path_atime_mtime_callback) -- | for details. @@ -652,9 +657,9 @@ lutimes :: FilePath -> DateTime -> DateTime - -> Callback1 Unit + -> Callback0 -> Effect Unit -lutimes file atime mtime cb = runEffectFn4 lutimesImpl file (datetimeToUnixEpochTimeInSeconds atime) (datetimeToUnixEpochTimeInSeconds mtime) (handleCallback1 cb) +lutimes file atime mtime cb = runEffectFn4 lutimesImpl file (datetimeToUnixEpochTimeInSeconds atime) (datetimeToUnixEpochTimeInSeconds mtime) (handleCallback0 cb) -- | TODO: path - Buffer Url, returns Promise -- | Open a file as a blob. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_class_filehandle) diff --git a/src/Node/FS/Dir.purs b/src/Node/FS/Dir.purs index 18b9a25..27cb661 100644 --- a/src/Node/FS/Dir.purs +++ b/src/Node/FS/Dir.purs @@ -9,7 +9,7 @@ import Effect (Effect) import Effect.Exception (Error) import Effect.Uncurried (EffectFn1, EffectFn2, mkEffectFn1, runEffectFn1, runEffectFn2) import Node.FS.Dirent (Dirent, DirentNameTypeString) -import Node.FS.Internal.Utils (Callback0, JSCallback0, JSCallback1, handleCallback1) +import Node.FS.Internal.Utils (Callback0, JSCallback0, JSCallback1, Callback1, handleCallback0, handleCallback1) import Node.Path (FilePath) -- Foreign imports for the Dir class @@ -25,15 +25,15 @@ foreign import path :: Dir -> FilePath -- | Asynchronously close the directory's underlying resource handle. close :: Dir -> Callback0 -> Effect Unit -close dir callback = runEffectFn2 closeImpl dir (mkEffectFn1 $ (callback <<< toMaybe)) +close dir cb = runEffectFn2 closeImpl dir (handleCallback0 cb) -- | Synchronously close the directory's underlying resource handle. closeSync :: Dir -> Effect Unit closeSync = runEffectFn1 closeSyncImpl -- | Asynchronously read the next directory entry. -read :: Dir -> (Either Error (Maybe (Dirent DirentNameTypeString)) -> Effect Unit) -> Effect Unit -read dir callback = runEffectFn2 readImpl dir (handleCallback1 (callback <<< map toMaybe)) +read :: Dir -> (Callback1 (Maybe (Dirent DirentNameTypeString))) -> Effect Unit +read dir cb = runEffectFn2 readImpl dir (handleCallback1 (cb <<< map toMaybe)) -- | Synchronously read the next directory entry. readSync :: Dir -> Effect (Maybe (Dirent DirentNameTypeString)) diff --git a/src/Node/FS/Internal/Utils.purs b/src/Node/FS/Internal/Utils.purs index 3f488f2..fcf8896 100644 --- a/src/Node/FS/Internal/Utils.purs +++ b/src/Node/FS/Internal/Utils.purs @@ -12,16 +12,21 @@ import Data.Time.Duration (Milliseconds(..)) import Data.Tuple (Tuple(..)) import Effect (Effect) import Effect.Exception (Error) -import Effect.Uncurried (EffectFn1, EffectFn2, EffectFn3, mkEffectFn2, mkEffectFn3) +import Effect.Uncurried (EffectFn1, EffectFn2, EffectFn3, mkEffectFn1, mkEffectFn2, mkEffectFn3) type JSCallback0 = EffectFn1 (Nullable Error) Unit type JSCallback1 a = EffectFn2 (Nullable Error) a Unit type JSCallback2 a b = EffectFn3 (Nullable Error) a b Unit -- | Type synonym for callback functions. -type Callback0 = Maybe Error -> Effect Unit +type Callback0 = Either Error Unit -> Effect Unit -- TODO: better Maybe Error -> Unit? type Callback1 a = Either Error a -> Effect Unit +handleCallback0 :: Callback0 -> JSCallback0 +handleCallback0 cb = mkEffectFn1 \err -> case toMaybe err of + Nothing -> cb (Right unit) + Just err' -> cb (Left err') + handleCallback1 :: forall a. Callback1 a -> JSCallback1 a handleCallback1 cb = mkEffectFn2 \err a -> case toMaybe err of Nothing -> cb (Right a) diff --git a/src/Node/FS/Options.purs b/src/Node/FS/Options.purs index 5af6a9a..251dbc8 100644 --- a/src/Node/FS/Options.purs +++ b/src/Node/FS/Options.purs @@ -1,6 +1,6 @@ module Node.FS.Options where -import Node.FS.Types (BufferLength, BufferOffset, FileMode, FilePosition) +import Node.FS.Types (BufferLength, BufferOffset, EncodingString, FileMode, FilePosition) import Prelude import Data.Function.Uncurried (Fn2, mkFn2) @@ -11,7 +11,7 @@ import Foreign (Foreign) import Foreign as Foreign import Node.Buffer (Buffer) import Node.Encoding (Encoding(..), encodingToNode) -import Node.FS.Constants (FileFlags(..), fileFlagsToNode) +import Node.FS.Constants (FileFlags(..), fileFlagsToNode) import Node.FS.Dirent (Dirent, DirentNameTypeString) import Node.FS.Perms (Perms, all, mkPerms, permsToString, read, write) import Node.Path (FilePath) @@ -39,7 +39,7 @@ mkdirOptionsToInternal { recursive, mode } = { recursive, mode: permsToString mo --------- -type RealpathOptionsInternal = { encoding :: String } +type RealpathOptionsInternal = { encoding :: EncodingString } type RealpathOptions = { encoding :: Encoding } realpathOptionsDefault :: RealpathOptions @@ -318,7 +318,7 @@ globDirentOptionsToInternal { cwd, exclude } = { cwd: toNullable cwd, exclude: t ------------------ -type OpendirOptionsInternal = { encoding :: String, bufferSize :: Int, recursive :: Boolean } +type OpendirOptionsInternal = { encoding :: EncodingString, bufferSize :: Int, recursive :: Boolean } type OpendirOptions = { encoding :: Encoding, bufferSize :: Int, recursive :: Boolean } opendirOptionsDefault :: OpendirOptions diff --git a/src/Node/FS/Sync.js b/src/Node/FS/Sync.js index 89e3178..20237a0 100644 --- a/src/Node/FS/Sync.js +++ b/src/Node/FS/Sync.js @@ -1,7 +1,7 @@ export { - accessSync as accessImpl, - copyFileSync as copyFileImpl, - mkdtempSync as mkdtempImpl, + accessSync as accessSyncImpl, + copyFileSync as copyFileSyncImpl, + mkdtempSync as mkdtempSyncImpl, renameSync as renameSyncImpl, truncateSync as truncateSyncImpl, chownSync as chownSyncImpl, diff --git a/src/Node/FS/Sync.purs b/src/Node/FS/Sync.purs index 4a17b62..5388829 100644 --- a/src/Node/FS/Sync.purs +++ b/src/Node/FS/Sync.purs @@ -9,8 +9,8 @@ module Node.FS.Sync , truncate , chown , chmod - , stat , lstat + , stat , link , symlink , readlink @@ -24,23 +24,66 @@ module Node.FS.Sync , mkdir , mkdir' , readdir + , readdir' + , readdirBuffer + , readdirBuffer' + , readdirDirent + , readdirDirent' + , readdirDirentBuffer + , readdirDirentBuffer' , utimes , readFile + , readFile' , readTextFile + , readTextFile' , writeFile + , writeFile' , writeTextFile + , writeTextFile' , appendFile + , appendFile' , appendTextFile , exists , fdOpen , fdRead + , fdRead' , fdNext , fdWrite + , fdWrite' + , fdWriteString , fdAppend , fdFlush , fdClose + , cp + , cp' + , fchmod + , fchown + , fdatasync + , fstat + , fsync + , ftruncate + , futimes + , glob + , glob' + , globDirent + , globDirent' + , lchmod + , lchown + , lutimes + -- , openAsBlob + , opendir + , opendir' + , readv + , statfs + -- , unwatchFile + -- , watch + -- , watchFile + , writev ) where +import Node.FS.Constants +import Node.FS.Options +import Node.FS.Types import Prelude import Data.DateTime (DateTime) @@ -52,40 +95,21 @@ import Data.Nullable (Nullable, toNullable) import Data.Time.Duration (Milliseconds(..)) import Effect (Effect) import Effect.Exception (Error, try) -import Effect.Uncurried (EffectFn1, EffectFn2, EffectFn3, EffectFn5, runEffectFn1, runEffectFn2, runEffectFn3, runEffectFn5) +import Effect.Uncurried (EffectFn1, EffectFn2, EffectFn3, EffectFn4, EffectFn5, runEffectFn1, runEffectFn2, runEffectFn3, runEffectFn4, runEffectFn5) import Node.Buffer (Buffer, size) import Node.Encoding (Encoding(..), encodingToNode) -import Node.FS (FileDescriptor, ByteCount, FilePosition, BufferLength, BufferOffset, FileMode, SymlinkType, symlinkTypeToNode) -import Node.FS.Constants (AccessMode, CopyMode, FileFlags, defaultAccessMode, defaultCopyMode, fileFlagsToNode) +import Node.FS.Dir (Dir) +import Node.FS.Dirent (Dirent, DirentNameTypeBuffer, DirentNameTypeString) +import Node.FS.Internal.Utils (datetimeToUnixEpochTimeInSeconds) import Node.FS.Perms (Perms, permsToString, all, mkPerms) import Node.FS.Stats (Stats) import Node.Path (FilePath) +import Prim.TypeError (class Warn, Text) +import Unsafe.Coerce (unsafeCoerce) -access :: FilePath -> Effect (Maybe Error) -access = flip access' defaultAccessMode - -access' :: FilePath -> AccessMode -> Effect (Maybe Error) -access' path mode = do - map blush $ try $ runEffectFn2 accessImpl path mode - -foreign import accessImpl :: EffectFn2 FilePath AccessMode (Maybe Error) - -copyFile :: FilePath -> FilePath -> Effect Unit -copyFile src dest = runEffectFn3 copyFileImpl src dest defaultCopyMode - -copyFile' :: FilePath -> FilePath -> CopyMode -> Effect Unit -copyFile' src dest mode = runEffectFn3 copyFileImpl src dest mode - -foreign import copyFileImpl :: EffectFn3 FilePath FilePath CopyMode Unit - -mkdtemp :: String -> Effect String -mkdtemp prefix = mkdtemp' prefix UTF8 - -mkdtemp' :: String -> Encoding -> Effect String -mkdtemp' prefix encoding = runEffectFn2 mkdtempImpl prefix (encodingToNode encoding) - -foreign import mkdtempImpl :: EffectFn2 String String String - +foreign import accessSyncImpl :: EffectFn2 FilePath AccessMode Unit +foreign import copyFileSyncImpl :: EffectFn3 FilePath FilePath CopyMode Unit +foreign import mkdtempSyncImpl :: EffectFn2 FilePath FilePath FilePath foreign import renameSyncImpl :: EffectFn2 FilePath FilePath Unit foreign import truncateSyncImpl :: EffectFn2 FilePath Int Unit foreign import chownSyncImpl :: EffectFn3 FilePath Int Int Unit @@ -95,22 +119,70 @@ foreign import lstatSyncImpl :: EffectFn1 FilePath Stats foreign import linkSyncImpl :: EffectFn2 FilePath FilePath Unit foreign import symlinkSyncImpl :: EffectFn3 FilePath FilePath (Nullable String) Unit foreign import readlinkSyncImpl :: EffectFn1 FilePath FilePath -foreign import realpathSyncImpl :: forall cache. EffectFn2 FilePath { | cache } FilePath +foreign import realpathSyncImpl :: EffectFn2 FilePath RealpathOptionsInternal FilePath foreign import unlinkSyncImpl :: EffectFn1 FilePath Unit -foreign import rmdirSyncImpl :: EffectFn2 FilePath { maxRetries :: Int, retryDelay :: Int } Unit -foreign import rmSyncImpl :: EffectFn2 FilePath { force :: Boolean, maxRetries :: Int, recursive :: Boolean, retryDelay :: Int } Unit -foreign import mkdirSyncImpl :: EffectFn2 FilePath { recursive :: Boolean, mode :: String } Unit -foreign import readdirSyncImpl :: EffectFn1 FilePath (Array FilePath) +foreign import rmdirSyncImpl :: EffectFn2 FilePath RmdirOptions Unit +foreign import rmSyncImpl :: EffectFn2 FilePath RmOptions Unit +foreign import mkdirSyncImpl :: EffectFn2 FilePath MkdirOptionsInternal Unit +foreign import readdirSyncImpl :: forall filepathOrDirentOrBuffer. EffectFn2 FilePath ReaddirOptionsInternal (Array filepathOrDirentOrBuffer) foreign import utimesSyncImpl :: EffectFn3 FilePath Int Int Unit -foreign import readFileSyncImpl :: forall a opts. EffectFn2 FilePath { | opts } a -foreign import writeFileSyncImpl :: forall a opts. EffectFn3 FilePath a { | opts } Unit -foreign import appendFileSyncImpl :: forall a opts. EffectFn3 FilePath a { | opts } Unit +foreign import readFileSyncImpl :: forall stringOrBuffer. EffectFn2 FilePath ReadFileOptionsInternal stringOrBuffer +foreign import writeFileSyncImpl :: forall stringOrBuffer. EffectFn3 FilePath stringOrBuffer WriteFileOptionsInternal Unit +foreign import appendFileSyncImpl :: forall stringOrBuffer. EffectFn3 FilePath stringOrBuffer AppendFileOptionsInternal Unit foreign import existsSyncImpl :: EffectFn1 FilePath Boolean foreign import openSyncImpl :: EffectFn3 FilePath String (Nullable FileMode) FileDescriptor foreign import readSyncImpl :: EffectFn5 FileDescriptor Buffer BufferOffset BufferLength (Nullable FilePosition) ByteCount + +-- https://nodejs.org/docs/latest/api/fs.html#fsreadfd-options-callback +readWithOptionsSyncImpl :: EffectFn2 FileDescriptor FdReadOptionsInternal ByteCount +readWithOptionsSyncImpl = unsafeCoerce readSyncImpl + foreign import writeSyncImpl :: EffectFn5 FileDescriptor Buffer BufferOffset BufferLength (Nullable FilePosition) ByteCount -foreign import fsyncSyncImpl :: EffectFn1 FileDescriptor Unit + +-- https://nodejs.org/docs/latest/api/fs.html#fsreadfd-options-callback +writeWithOptionsSyncImpl :: EffectFn2 FileDescriptor FdWriteOptionsInternal ByteCount +writeWithOptionsSyncImpl = unsafeCoerce writeSyncImpl + +-- https://nodejs.org/docs/latest/api/fs.html#fsreadfd-options-callback +writeStringSyncImpl :: EffectFn4 FileDescriptor String (Nullable FilePosition) String ByteCount +writeStringSyncImpl = unsafeCoerce writeSyncImpl + foreign import closeSyncImpl :: EffectFn1 FileDescriptor Unit +foreign import cpSyncImpl :: EffectFn3 FilePath FilePath CpOptionsInternal Unit +foreign import fchmodSyncImpl :: EffectFn2 FileDescriptor String Unit +foreign import fchownSyncImpl :: EffectFn3 FileDescriptor Int Int Unit +foreign import fdatasyncSyncImpl :: EffectFn1 FileDescriptor Unit +foreign import fstatSyncImpl :: EffectFn1 FileDescriptor Stats +foreign import fsyncSyncImpl :: EffectFn1 FileDescriptor Unit +foreign import ftruncateSyncImpl :: EffectFn2 FileDescriptor Int Unit +foreign import futimesSyncImpl :: EffectFn3 FileDescriptor Int Int Unit +foreign import globSyncImpl :: forall filepathOrDirent. EffectFn2 (Array FilePath) (GlobOptionsInternal filepathOrDirent) (Array filepathOrDirent) +foreign import lchmodSyncImpl :: EffectFn2 FilePath String Unit +foreign import lchownSyncImpl :: EffectFn3 FilePath Int Int Unit +foreign import lutimesSyncImpl :: EffectFn3 FilePath Int Int Unit +foreign import opendirSyncImpl :: EffectFn2 FilePath OpendirOptionsInternal Dir +foreign import readvSyncImpl :: EffectFn3 FileDescriptor (Array Buffer) (Nullable FilePosition) ByteCount +foreign import statfsSyncImpl :: EffectFn1 FilePath Stats +foreign import writevSyncImpl :: EffectFn3 FileDescriptor (Array Buffer) (Nullable FilePosition) ByteCount + +access :: FilePath -> Effect (Maybe Error) +access = flip access' defaultAccessMode + +access' :: FilePath -> AccessMode -> Effect (Maybe Error) +access' path mode = do + map blush $ try $ runEffectFn2 accessSyncImpl path mode + +copyFile :: FilePath -> FilePath -> Effect Unit +copyFile src dest = runEffectFn3 copyFileSyncImpl src dest defaultCopyMode + +copyFile' :: FilePath -> FilePath -> CopyMode -> Effect Unit +copyFile' src dest mode = runEffectFn3 copyFileSyncImpl src dest mode + +mkdtemp :: String -> Effect String +mkdtemp prefix = mkdtemp' prefix UTF8 + +mkdtemp' :: String -> Encoding -> Effect String +mkdtemp' prefix encoding = runEffectFn2 mkdtempSyncImpl prefix (encodingToNode encoding) -- | Renames a file. rename :: FilePath -> FilePath -> Effect Unit @@ -177,16 +249,15 @@ readlink path = runEffectFn1 readlinkSyncImpl path realpath :: FilePath -> Effect FilePath -realpath path = runEffectFn2 realpathSyncImpl path {} +realpath path = realpath' path realpathOptionsDefault -- | Find the canonicalized absolute location for a path using a cache object for -- | already resolved paths. realpath' - :: forall cache - . FilePath - -> { | cache } + :: FilePath + -> RealpathOptions -> Effect FilePath -realpath' path cache = runEffectFn2 realpathSyncImpl path cache +realpath' path options = runEffectFn2 realpathSyncImpl path (realpathOptionsToInternal options) -- | Deletes a file. unlink @@ -198,12 +269,12 @@ unlink file = runEffectFn1 unlinkSyncImpl file rmdir :: FilePath -> Effect Unit -rmdir path = rmdir' path { maxRetries: 0, retryDelay: 100 } +rmdir path = rmdir' path rmdirOptionsDefault -- | Deletes a directory with options. rmdir' :: FilePath - -> { maxRetries :: Int, retryDelay :: Int } + -> RmdirOptions -> Effect Unit rmdir' path opts = runEffectFn2 rmdirSyncImpl path opts @@ -211,12 +282,12 @@ rmdir' path opts = runEffectFn2 rmdirSyncImpl path opts rm :: FilePath -> Effect Unit -rm path = rm' path { force: false, maxRetries: 100, recursive: false, retryDelay: 1000 } +rm path = rm' path rmOptionsDefault -- | Deletes a file or directory with options. rm' :: FilePath - -> { force :: Boolean, maxRetries :: Int, recursive :: Boolean, retryDelay :: Int } + -> RmOptions -> Effect Unit rm' path opts = runEffectFn2 rmSyncImpl path opts @@ -224,20 +295,66 @@ rm' path opts = runEffectFn2 rmSyncImpl path opts mkdir :: FilePath -> Effect Unit -mkdir path = mkdir' path { recursive: false, mode: mkPerms all all all } +mkdir path = mkdir' path mkdirOptionsDefault -- | Makes a new directory with the specified permissions. mkdir' :: FilePath - -> { recursive :: Boolean, mode :: Perms } + -> MkdirOptions -> Effect Unit -mkdir' file { recursive, mode: perms } = runEffectFn2 mkdirSyncImpl file { recursive, mode: permsToString perms } +mkdir' file opts = runEffectFn2 mkdirSyncImpl file (mkdirOptionsToInternal opts) -- | Reads the contents of a directory. readdir :: FilePath -> Effect (Array FilePath) -readdir file = runEffectFn1 readdirSyncImpl file +readdir file = readdir' file readdirFilePathOptionsDefault + +-- | Reads the contents of a directory. +readdir' + :: FilePath + -> ReaddirFilePathOptions + -> Effect (Array FilePath) +readdir' file options = runEffectFn2 readdirSyncImpl file (readdirFilePathOptionsToInternal options) + +-- | Reads the contents of a directory. +readdirBuffer + :: FilePath + -> Effect (Array Buffer) +readdirBuffer file = readdirBuffer' file readdirBufferOptionsDefault + +-- | Reads the contents of a directory. +readdirBuffer' + :: FilePath + -> ReaddirBufferOptions + -> Effect (Array Buffer) +readdirBuffer' file options = runEffectFn2 readdirSyncImpl file (readdirBufferOptionsToInternal options) + +-- | Reads the contents of a directory. +readdirDirent + :: FilePath + -> Effect (Array (Dirent DirentNameTypeString)) +readdirDirent file = readdirDirent' file readdirDirentOptionsDefault + +-- | Reads the contents of a directory. +readdirDirent' + :: FilePath + -> ReaddirDirentOptions + -> Effect (Array (Dirent DirentNameTypeString)) +readdirDirent' file options = runEffectFn2 readdirSyncImpl file (readdirDirentOptionsToInternal options) + +-- | Reads the contents of a directory. +readdirDirentBuffer + :: FilePath + -> Effect (Array (Dirent DirentNameTypeBuffer)) +readdirDirentBuffer file = readdirDirentBuffer' file readdirDirentBufferOptionsDefault + +-- | Reads the contents of a directory. +readdirDirentBuffer' + :: FilePath + -> ReaddirDirentBufferOptions + -> Effect (Array (Dirent DirentNameTypeBuffer)) +readdirDirentBuffer' file options = runEffectFn2 readdirSyncImpl file (readdirDirentBufferOptionsToInternal options) -- | Sets the accessed and modified times for the specified file. utimes @@ -245,31 +362,32 @@ utimes -> DateTime -> DateTime -> Effect Unit -utimes file atime mtime = runEffectFn3 utimesSyncImpl file (fromDate atime) (fromDate mtime) - where - fromDate date = ms (toEpochMilliseconds date) / 1000 - ms (Milliseconds n) = round n - toEpochMilliseconds = unInstant <<< fromDateTime - --- | Reads the entire contents of a file returning the result as a raw buffer. -readFile - :: FilePath - -> Effect Buffer -readFile file = runEffectFn2 readFileSyncImpl file {} +utimes file atime mtime = runEffectFn3 utimesSyncImpl file (datetimeToUnixEpochTimeInSeconds atime) (datetimeToUnixEpochTimeInSeconds mtime) -- | Reads the entire contents of a text file with the specified encoding. readTextFile :: Encoding -> FilePath -> Effect String -readTextFile encoding file = runEffectFn2 readFileSyncImpl file { encoding: show encoding } +readTextFile encoding file = readTextFile' file (readFileStringOptionsDefault { encoding = encoding }) --- | Writes a buffer to a file. -writeFile +readTextFile' :: FilePath - -> Buffer - -> Effect Unit -writeFile file buff = runEffectFn3 writeFileSyncImpl file buff {} + -> ReadFileStringOptions + -> Effect String +readTextFile' file options = runEffectFn2 readFileSyncImpl file (readFileStringOptionsToInternal options) + +-- | Reads the entire contents of a file returning the result as a raw buffer. +readFile + :: FilePath + -> Effect Buffer +readFile file = readFile' file readFileBufferOptionsDefault + +readFile' + :: FilePath + -> ReadFileBufferOptions + -> Effect Buffer +readFile' file options = runEffectFn2 readFileSyncImpl file (readFileBufferOptionsToInternal options) -- | Writes text to a file using the specified encoding. writeTextFile @@ -277,14 +395,28 @@ writeTextFile -> FilePath -> String -> Effect Unit -writeTextFile encoding file text = runEffectFn3 writeFileSyncImpl file text { encoding: show encoding } +writeTextFile encoding file buff = writeTextFile' file buff (writeFileStringOptionsDefault { encoding = encoding }) --- | Appends the contents of a buffer to a file. -appendFile +writeTextFile' + :: FilePath + -> String + -> WriteFileStringOptions + -> Effect Unit +writeTextFile' file buff options = runEffectFn3 writeFileSyncImpl file buff (writeFileStringOptionsToInternal options) + +-- | Writes a buffer to a file. +writeFile :: FilePath -> Buffer -> Effect Unit -appendFile file buff = runEffectFn3 appendFileSyncImpl file buff {} +writeFile file buff = writeFile' file buff writeFileBufferOptionsDefault + +writeFile' + :: FilePath + -> Buffer + -> WriteFileBufferOptions + -> Effect Unit +writeFile' file buff options = runEffectFn3 writeFileSyncImpl file buff (writeFileBufferOptionsToInternal options) -- | Appends text to a file using the specified encoding. appendTextFile @@ -292,12 +424,31 @@ appendTextFile -> FilePath -> String -> Effect Unit -appendTextFile encoding file buff = runEffectFn3 appendFileSyncImpl file buff { encoding: show encoding } +appendTextFile encoding file buff = appendTextFile' file buff (appendFileStringOptionsDefault { encoding = encoding }) --- | Check if the path exists. -exists +appendTextFile' + :: FilePath + -> String + -> AppendFileStringOptions + -> Effect Unit +appendTextFile' file buff options = runEffectFn3 appendFileSyncImpl file buff (appendFileStringOptionsToInternal options) + +-- | Appends a buffer to a file. +appendFile + :: FilePath + -> Buffer + -> Effect Unit +appendFile file buff = appendFile' file buff appendFileBufferOptionsDefault + +appendFile' :: FilePath - -> Effect Boolean + -> Buffer + -> AppendFileBufferOptions + -> Effect Unit +appendFile' file buff options = runEffectFn3 appendFileSyncImpl file buff (appendFileBufferOptionsToInternal options) + +-- | Check if the path exists. +exists :: FilePath -> Effect Boolean exists file = runEffectFn1 existsSyncImpl file -- | Open a file synchronously. See the [Node documentation](http://nodejs.org/api/fs.html#fs_fs_opensync_path_flags_mode) @@ -321,6 +472,14 @@ fdRead fdRead fd buff off len pos = runEffectFn5 readSyncImpl fd buff off len (toNullable pos) +-- | Read from a file asynchronously. See the [Node Documentation](https://nodejs.org/docs/latest/api/fs.html#fsreadfd-options-callback) +-- | for details. +fdRead' + :: FileDescriptor + -> FdReadOptions + -> Effect ByteCount +fdRead' fd options = runEffectFn2 readWithOptionsSyncImpl fd (fdReadOptionsToInternal options) + -- | Convenience function to fill the whole buffer from the current -- | file position. fdNext @@ -343,6 +502,23 @@ fdWrite fdWrite fd buff off len pos = runEffectFn5 writeSyncImpl fd buff off len (toNullable pos) +-- | Write from a file asynchronously. See the [Node Documentation](https://nodejs.org/docs/latest/api/fs.html#fswritefd-options-callback) +-- | for details. +fdWrite' + :: FileDescriptor + -> FdWriteOptions + -> Effect ByteCount +fdWrite' fd options = runEffectFn2 writeWithOptionsSyncImpl fd (fdWriteOptionsToInternal options) + +-- It is unsafe to use fs.write() multiple times on the same file without waiting for the callback. For this scenario, fs.createWriteStream() is recommended. +fdWriteString + :: FileDescriptor + -> String + -> Maybe FilePosition + -> Encoding + -> Effect ByteCount +fdWriteString fd string pos encoding = runEffectFn4 writeStringSyncImpl fd string (toNullable pos) (encodingToNode encoding) + -- | Convenience function to append the whole buffer to the current -- | file position. fdAppend @@ -355,14 +531,122 @@ fdAppend fd buff = do -- | Flush a file synchronously. See the [Node documentation](http://nodejs.org/api/fs.html#fs_fs_fsyncsync_fd) -- | for details. -fdFlush - :: FileDescriptor - -> Effect Unit -fdFlush fd = runEffectFn1 fsyncSyncImpl fd +fdFlush :: Warn (Text "Deprecated, use fsync") => FileDescriptor -> Effect Unit +fdFlush = fsync -- | Close a file synchronously. See the [Node documentation](http://nodejs.org/api/fs.html#fs_fs_closesync_fd) -- | for details. -fdClose - :: FileDescriptor - -> Effect Unit +fdClose :: FileDescriptor -> Effect Unit fdClose fd = runEffectFn1 closeSyncImpl fd + +-- | Copy a file asynchronously. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fspromises_copyfile_src_dest_mode) +-- | for details. +cp :: FilePath -> FilePath -> Effect Unit +cp src dest = cp' src dest cpOptionsDefault + +cp' :: FilePath -> FilePath -> CpOptions -> Effect Unit +cp' src dest opts = runEffectFn3 cpSyncImpl src dest (cpOptionsToCpOptionsInternal opts) + +-- | Change permissions on a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fchmod_fd_mode_callback) +-- | for details. +fchmod :: FileDescriptor -> Perms -> Effect Unit +fchmod fd perms = runEffectFn2 fchmodSyncImpl fd (permsToString perms) + +-- | Change ownership of a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fchown_fd_uid_gid_callback) +-- | for details. +fchown :: FileDescriptor -> Int -> Int -> Effect Unit +fchown fd uid gid = runEffectFn3 fchownSyncImpl fd uid gid + +-- | Synchronize a file's in-core state with storage. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fdatasync_fd_callback) +-- | for details. +fdatasync :: FileDescriptor -> Effect Unit +fdatasync fd = runEffectFn1 fdatasyncSyncImpl fd + +-- | Get file status information. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fstat_fd_callback) +-- | for details. +fstat :: FileDescriptor -> Effect Stats +fstat fd = runEffectFn1 fstatSyncImpl fd + +-- | Flush a file synchronously. See the [Node documentation](http://nodejs.org/api/fs.html#fs_fs_fsyncsync_fd) +-- | for details. +fsync :: FileDescriptor -> Effect Unit +fsync fd = runEffectFn1 fsyncSyncImpl fd + +-- | Truncate a file to a specified length. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_ftruncate_fd_len_callback) +-- | for details. +ftruncate :: FileDescriptor -> Int -> Effect Unit +ftruncate fd len = runEffectFn2 ftruncateSyncImpl fd len + +-- | Change file timestamps for a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_futimes_fd_atime_mtime_callback) +-- | for details. +futimes + :: FilePath + -> DateTime + -> DateTime + -> Effect Unit +futimes file atime mtime = runEffectFn3 lutimesSyncImpl file (datetimeToUnixEpochTimeInSeconds atime) (datetimeToUnixEpochTimeInSeconds mtime) + +-- | Perform pattern matching in file paths. See the [Node Documentation](https://nodejs.org/api/glob.html#globglob_pattern_options_callback) +-- | for details. +glob :: Array FilePath -> Effect (Array FilePath) +glob pattern = glob' pattern globFilePathOptionsDefault + +glob' :: Array FilePath -> GlobFilePathOptions -> Effect (Array FilePath) +glob' pattern options = runEffectFn2 globSyncImpl pattern (globFilePathOptionsToInternal options) + +globDirent :: Array FilePath -> Effect (Array (Dirent DirentNameTypeString)) +globDirent pattern = globDirent' pattern globDirentOptionsDefault + +globDirent' :: Array FilePath -> GlobDirentOptions -> Effect (Array (Dirent DirentNameTypeString)) +globDirent' pattern options = runEffectFn2 globSyncImpl pattern (globDirentOptionsToInternal options) + +-- | Change permissions on a symbolic link. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_lchmod_path_mode_callback) +-- | for details. +lchmod :: FilePath -> Perms -> Effect Unit +lchmod path perms = runEffectFn2 lchmodSyncImpl path (permsToString perms) + +-- | Change ownership of a symbolic link. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_lchown_path_uid_gid_callback) +-- | for details. +lchown :: FilePath -> Int -> Int -> Effect Unit +lchown path uid gid = runEffectFn3 lchownSyncImpl path uid gid + +-- | Change timestamps for a symbolic link. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_lutimes_path_atime_mtime_callback) +-- | for details. +lutimes + :: FilePath + -> DateTime + -> DateTime + -> Effect Unit +lutimes file atime mtime = runEffectFn3 lutimesSyncImpl file (datetimeToUnixEpochTimeInSeconds atime) (datetimeToUnixEpochTimeInSeconds mtime) + +-- | TODO: path - Buffer Url, returns Promise +-- | Open a file as a blob. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_class_filehandle) +-- | for details. +-- openAsBlob :: FilePath -> Promise Blob -> Effect Unit +-- openAsBlob path = runEffectFn2 openAsBlobSyncImpl path + +-- | Open a directory. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_opendir_path_options_callback) +-- | for details. +opendir' :: FilePath -> OpendirOptions -> Effect Dir +opendir' path options = runEffectFn2 opendirSyncImpl path (opendirOptionsToInternal options) + +-- | Open a directory. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_opendir_path_options_callback) +-- | for details. +-- | NOTE: encoding: 'buffer' is not supported, will throw error "TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received an instance of Buffer" +opendir :: FilePath -> Effect Dir +opendir path = opendir' path opendirOptionsDefault + +-- | Read from a file descriptor into a buffer array. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_readv_fd_buffers_position_callback) +-- | for details. +readv :: FileDescriptor -> Array Buffer -> Maybe FilePosition -> Effect ByteCount +readv fd buffers position = runEffectFn3 readvSyncImpl fd buffers (toNullable position) + +-- | Get file system statistics. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_statfs_path_callback) +-- | for details. +statfs :: FilePath -> Effect Stats +statfs = runEffectFn1 statfsSyncImpl + +-- | Write from an array of buffers to a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_writev_fd_buffers_position_callback) +-- | for details. +writev :: FileDescriptor -> Array Buffer -> Maybe FilePosition -> Effect ByteCount +writev fd buffers position = runEffectFn3 writevSyncImpl fd buffers (toNullable position) diff --git a/src/Node/FS/Types.purs b/src/Node/FS/Types.purs index 94e5cc9..f035804 100644 --- a/src/Node/FS/Types.purs +++ b/src/Node/FS/Types.purs @@ -12,6 +12,35 @@ type FilePosition = Int type BufferLength = Int type BufferOffset = Int type ByteCount = Int +type EncodingString = String + +-- newtype FileMode = FileMode Int +-- newtype FilePosition = FilePosition Int +-- newtype BufferLength = BufferLength Int +-- newtype BufferOffset = BufferOffset Int +-- newtype ByteCount = ByteCount Int +-- -- newtype EncodingString = EncodingString String +-- +-- derive newtype instance Eq FileMode +-- derive newtype instance Eq FilePosition +-- derive newtype instance Eq BufferLength +-- derive newtype instance Eq BufferOffset +-- derive newtype instance Eq ByteCount +-- -- derive newtype instance Eq EncodingString +-- +-- derive newtype instance Show FileMode +-- derive newtype instance Show FilePosition +-- derive newtype instance Show BufferLength +-- derive newtype instance Show BufferOffset +-- derive newtype instance Show ByteCount +-- -- derive newtype instance Show EncodingString +-- +-- derive newtype instance Ord FileMode +-- derive newtype instance Ord FilePosition +-- derive newtype instance Ord BufferLength +-- derive newtype instance Ord BufferOffset +-- derive newtype instance Ord ByteCount +-- -- derive newtype instance Ord EncodingString -- | Symlink varieties. data SymlinkType = FileLink | DirLink | JunctionLink | AutodetectLink @@ -25,10 +54,10 @@ symlinkTypeToNode ty = case ty of JunctionLink -> Nullable.notNull "junction" AutodetectLink -> Nullable.null -instance showSymlinkType :: Show SymlinkType where +instance Show SymlinkType where show FileLink = "FileLink" show DirLink = "DirLink" show JunctionLink = "JunctionLink" show AutodetectLink = "AutodetectLink" -derive instance eqSymlinkType :: Eq SymlinkType +derive instance Eq SymlinkType diff --git a/test/Test/Node/FS/OpendirAndDir.purs b/test/Test/Node/FS/OpendirAndDir.purs index 8d49551..5a0451e 100644 --- a/test/Test/Node/FS/OpendirAndDir.purs +++ b/test/Test/Node/FS/OpendirAndDir.purs @@ -11,8 +11,7 @@ import Effect.Class (liftEffect) import Effect.Console (log) import Effect.Exception (Error) import Node.Encoding (Encoding(..)) -import Node.FS.Aff -import Node.FS.Options +import Node.FS.Options (opendirOptionsDefault, rmOptionsDefault) import Node.FS.Aff as A import Node.FS.Aff.Dir (close, entries, read) import Node.FS.Dirent (Dirent, DirentNameTypeString) @@ -22,7 +21,8 @@ import Node.Path as Path import Test.Assert (assertEqual) outerTmpDir :: FilePath -outerTmpDir = Path.concat ["tmp", "dir-entries-test"] +outerTmpDir = Path.concat [ "tmp", "dir-entries-test" ] + -- outerTmpDir = Path.concat [".", "tmp", "dir-entries-test"] prepare :: Aff Unit @@ -96,11 +96,11 @@ test2 = do } close dir >>= \file -> liftEffect $ assertEqual { actual: show file - , expected: "Nothing" + , expected: "unit" } - close dir >>= \maybeError -> liftEffect $ assertEqual - { actual: String.take 74 $ show maybeError - , expected: "(Just Error [ERR_DIR_CLOSED]: Directory handle was closed\n at Dir.close" + try (close dir) >>= \(error :: Either Error Unit) -> liftEffect $ assertEqual + { actual: String.take 74 $ show error + , expected: "(Left Error [ERR_DIR_CLOSED]: Directory handle was closed\n at Dir.close" } try (read dir) >>= \(eitherFile :: Either Error (Maybe (Dirent DirentNameTypeString))) -> liftEffect $ assertEqual { actual: String.take 74 $ show eitherFile @@ -110,5 +110,5 @@ test2 = do main :: Effect Unit main = launchAff_ do prepare - test1 + -- test1 test2 diff --git a/test/Test/Node/FS/Sync.purs b/test/Test/Node/FS/Sync.purs index 25327eb..de6a4a9 100644 --- a/test/Test/Node/FS/Sync.purs +++ b/test/Test/Node/FS/Sync.purs @@ -11,13 +11,12 @@ import Effect.Exception (Error, catchException, error, message, throw, throwExce import Node.Buffer as Buffer import Node.Encoding (Encoding(..)) import Node.FS (FileFlags(..), SymlinkType(..)) -import Node.FS.Aff import Node.FS.Async as A import Node.FS.Constants (copyFile_EXCL, r_OK, w_OK) import Node.FS.Perms (mkPerms, permsAll) import Node.FS.Perms as Perms import Node.FS.Stats (statusChangedTime, accessedTime, modifiedTime, isSymbolicLink, isSocket, isFIFO, isCharacterDevice, isBlockDevice, isDirectory, isFile) -import Node.FS.Options +import Node.FS.Options (rmOptionsDefault) import Node.FS.Sync (chmod) import Node.FS.Sync as S import Node.Path as Path From b226943d4017500197eab9d622cf9ceb81c002e8 Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Sun, 6 Oct 2024 17:15:16 +0700 Subject: [PATCH 11/32] feat: aff -> forgot some functions --- src/Node/FS/Aff.purs | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/Node/FS/Aff.purs b/src/Node/FS/Aff.purs index e1438d0..0ff4987 100644 --- a/src/Node/FS/Aff.purs +++ b/src/Node/FS/Aff.purs @@ -33,10 +33,15 @@ module Node.FS.Aff , readdirDirentBuffer' , utimes , readFile + , readFile' , readTextFile + , readTextFile' , writeFile + , writeFile' , writeTextFile + , writeTextFile' , appendFile + , appendFile' , appendTextFile , fdOpen , fdRead @@ -85,7 +90,7 @@ import Node.Buffer (Buffer) import Node.Encoding (Encoding) import Node.FS.Types (BufferLength, BufferOffset, ByteCount, FileDescriptor, FileMode, FilePosition, SymlinkType) import Node.FS.Internal.AffUtils (toAff1, toAff2, toAff3, toAff4, toAff5) -import Node.FS.Options (CpOptions, FdReadOptions, FdWriteOptions, OpendirOptions, RealpathOptions, RmOptions, RmdirOptions) +import Node.FS.Options (AppendFileBufferOptions, CpOptions, FdReadOptions, FdWriteOptions, GlobDirentOptions, GlobFilePathOptions, MkdirOptions, OpendirOptions, ReadFileBufferOptions, ReadFileStringOptions, ReaddirBufferOptions, ReaddirDirentBufferOptions, ReaddirDirentOptions, ReaddirFilePathOptions, RealpathOptions, RmOptions, RmdirOptions, WriteFileBufferOptions, WriteFileStringOptions) import Node.FS.Constants (AccessMode, CopyMode, FileFlags) import Node.FS.Async as A import Node.FS.Dir (Dir) @@ -226,7 +231,7 @@ mkdir = toAff1 A.mkdir -- | -- | Makes a new directory with all of its options. -- | -mkdir' :: FilePath -> { recursive :: Boolean, mode :: Perms } -> Aff Unit +mkdir' :: FilePath -> MkdirOptions -> Aff Unit mkdir' = toAff2 A.mkdir' -- | @@ -236,7 +241,7 @@ readdir :: FilePath -> Aff (Array FilePath) readdir = toAff1 A.readdir -- | Reads the contents of a directory with options. -readdir' :: FilePath -> { recursive :: Boolean, encoding :: Encoding } -> Aff (Array FilePath) +readdir' :: FilePath -> ReaddirFilePathOptions -> Aff (Array FilePath) readdir' = toAff2 A.readdir' -- | Reads the contents of a directory and returns an Aff (Array Buffer). @@ -244,7 +249,7 @@ readdirBuffer :: FilePath -> Aff (Array Buffer) readdirBuffer = toAff1 A.readdirBuffer -- | Reads the contents of a directory with options and returns Aff (Array Buffer). -readdirBuffer' :: FilePath -> { recursive :: Boolean } -> Aff (Array Buffer) +readdirBuffer' :: FilePath -> ReaddirBufferOptions -> Aff (Array Buffer) readdirBuffer' = toAff2 A.readdirBuffer' -- | Reads the contents of a directory and returns an Aff (Array (Dirent DirentNameTypeString)). @@ -252,7 +257,7 @@ readdirDirent :: FilePath -> Aff (Array (Dirent DirentNameTypeString)) readdirDirent = toAff1 A.readdirDirent -- | Reads the contents of a directory with options and returns Aff (Array (Dirent DirentNameTypeString)). -readdirDirent' :: FilePath -> { recursive :: Boolean, encoding :: Encoding } -> Aff (Array (Dirent DirentNameTypeString)) +readdirDirent' :: FilePath -> ReaddirDirentOptions -> Aff (Array (Dirent DirentNameTypeString)) readdirDirent' = toAff2 A.readdirDirent' -- | Reads the contents of a directory. @@ -264,7 +269,7 @@ readdirDirentBuffer = toAff1 A.readdirDirentBuffer -- | Reads the contents of a directory. readdirDirentBuffer' :: FilePath - -> { recursive :: Boolean } + -> ReaddirDirentBufferOptions -> Aff (Array (Dirent DirentNameTypeBuffer)) readdirDirentBuffer' = toAff2 A.readdirDirentBuffer' @@ -280,30 +285,45 @@ utimes = toAff3 A.utimes readFile :: FilePath -> Aff Buffer readFile = toAff1 A.readFile +readFile' :: FilePath -> ReadFileBufferOptions -> Aff Buffer +readFile' = toAff2 A.readFile' + -- | -- | Reads the entire contents of a text file with the specified encoding. -- | readTextFile :: Encoding -> FilePath -> Aff String readTextFile = toAff2 A.readTextFile +readTextFile' :: FilePath -> ReadFileStringOptions -> Aff String +readTextFile' = toAff2 A.readTextFile' + -- | -- | Writes a buffer to a file. -- | writeFile :: FilePath -> Buffer -> Aff Unit writeFile = toAff2 A.writeFile +writeFile' :: FilePath -> Buffer -> WriteFileBufferOptions -> Aff Unit +writeFile' = toAff3 A.writeFile' + -- | -- | Writes text to a file using the specified encoding. -- | writeTextFile :: Encoding -> FilePath -> String -> Aff Unit writeTextFile = toAff3 A.writeTextFile +writeTextFile' :: FilePath -> String -> WriteFileStringOptions -> Aff Unit +writeTextFile' = toAff3 A.writeTextFile' + -- | -- | Appends the contents of a buffer to a file. -- | appendFile :: FilePath -> Buffer -> Aff Unit appendFile = toAff2 A.appendFile +appendFile' :: FilePath -> Buffer -> AppendFileBufferOptions -> Aff Unit +appendFile' = toAff3 A.appendFile' + -- | -- | Appends text to a file using the specified encoding. -- | @@ -429,13 +449,13 @@ futimes = toAff3 A.futimes glob :: Array FilePath -> Aff (Array FilePath) glob = toAff1 A.glob -glob' :: Array FilePath -> { cwd :: Maybe FilePath, exclude :: Maybe (FilePath -> Boolean) } -> Aff (Array FilePath) +glob' :: Array FilePath -> GlobFilePathOptions -> Aff (Array FilePath) glob' = toAff2 A.glob' globDirent :: Array FilePath -> Aff (Array (Dirent DirentNameTypeString)) globDirent = toAff1 A.globDirent -globDirent' :: Array FilePath -> { cwd :: Maybe FilePath, exclude :: Maybe (Dirent DirentNameTypeString -> Boolean) } -> Aff (Array (Dirent DirentNameTypeString)) +globDirent' :: Array FilePath -> GlobDirentOptions -> Aff (Array (Dirent DirentNameTypeString)) globDirent' = toAff2 A.globDirent' -- | Change permissions on a symbolic link. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_lchmod_path_mode_callback) From 1319b6b60420cba657c375a5edad20e59cfc24e0 Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Sun, 6 Oct 2024 17:22:03 +0700 Subject: [PATCH 12/32] fix: suggestions --- src/Node/FS.purs | 6 +----- src/Node/FS/Async.purs | 8 ++++---- src/Node/FS/Dir.purs | 4 +--- src/Node/FS/Sync.purs | 11 ++++------- 4 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/Node/FS.purs b/src/Node/FS.purs index 644e7cf..135321d 100644 --- a/src/Node/FS.purs +++ b/src/Node/FS.purs @@ -1,8 +1,4 @@ module Node.FS (module Exports) where -import Prelude - -import Data.Nullable (Nullable) -import Data.Nullable as Nullable import Node.FS.Constants (FileFlags(..), fileFlagsToNode) as Exports -import Node.FS.Types as Exports +import Node.FS.Types (BufferLength, BufferOffset, ByteCount, EncodingString, FileDescriptor, FileMode, FilePosition, SymlinkType(..), symlinkTypeToNode) as Exports diff --git a/src/Node/FS/Async.purs b/src/Node/FS/Async.purs index ac18dce..72be567 100644 --- a/src/Node/FS/Async.purs +++ b/src/Node/FS/Async.purs @@ -87,13 +87,13 @@ import Data.Nullable (Nullable, toMaybe, toNullable) import Data.Tuple (Tuple) import Effect (Effect) import Effect.Exception (Error) -import Effect.Uncurried (EffectFn1, EffectFn2, EffectFn3, EffectFn4, EffectFn5, EffectFn6, mkEffectFn1, runEffectFn2, runEffectFn3, runEffectFn4, runEffectFn5, runEffectFn6) +import Effect.Uncurried (EffectFn2, EffectFn3, EffectFn4, EffectFn5, EffectFn6, mkEffectFn1, runEffectFn2, runEffectFn3, runEffectFn4, runEffectFn5, runEffectFn6) import Node.Buffer (Buffer, size) import Node.Encoding (Encoding(..), encodingToNode) import Node.FS (FileDescriptor, ByteCount, FilePosition, BufferLength, BufferOffset, FileMode, SymlinkType, symlinkTypeToNode) -import Node.FS.Constants -import Node.FS.Internal.Utils -import Node.FS.Options +import Node.FS.Constants (AccessMode, CopyMode, FileFlags, defaultAccessMode, defaultCopyMode, fileFlagsToNode) +import Node.FS.Internal.Utils (Callback0, Callback1, JSCallback0, JSCallback1, JSCallback2, datetimeToUnixEpochTimeInSeconds, handleCallback0, handleCallback1, handleCallback1Tuple) +import Node.FS.Options (AppendFileBufferOptions, AppendFileOptionsInternal, AppendFileStringOptions, CpOptions, CpOptionsInternal, FdReadOptions, FdReadOptionsInternal, FdWriteOptions, FdWriteOptionsInternal, GlobDirentOptions, GlobFilePathOptions, GlobOptionsInternal, MkdirOptions, MkdirOptionsInternal, OpendirOptions, OpendirOptionsInternal, ReadFileBufferOptions, ReadFileOptionsInternal, ReadFileStringOptions, ReaddirBufferOptions, ReaddirDirentBufferOptions, ReaddirDirentOptions, ReaddirFilePathOptions, ReaddirOptionsInternal, RealpathOptions, RealpathOptionsInternal, RmOptions, RmdirOptions, WriteFileBufferOptions, WriteFileOptionsInternal, WriteFileStringOptions, appendFileBufferOptionsDefault, appendFileBufferOptionsToInternal, appendFileStringOptionsDefault, appendFileStringOptionsToInternal, cpOptionsDefault, cpOptionsToCpOptionsInternal, fdReadOptionsToInternal, fdWriteOptionsToInternal, globDirentOptionsDefault, globDirentOptionsToInternal, globFilePathOptionsDefault, globFilePathOptionsToInternal, mkdirOptionsDefault, mkdirOptionsToInternal, opendirOptionsDefault, opendirOptionsToInternal, readFileBufferOptionsDefault, readFileBufferOptionsToInternal, readFileStringOptionsDefault, readFileStringOptionsToInternal, readdirBufferOptionsDefault, readdirBufferOptionsToInternal, readdirDirentBufferOptionsDefault, readdirDirentBufferOptionsToInternal, readdirDirentOptionsDefault, readdirDirentOptionsToInternal, readdirFilePathOptionsDefault, readdirFilePathOptionsToInternal, realpathOptionsDefault, realpathOptionsToInternal, rmOptionsDefault, rmdirOptionsDefault, writeFileBufferOptionsDefault, writeFileBufferOptionsToInternal, writeFileStringOptionsDefault, writeFileStringOptionsToInternal) import Node.FS.Dir (Dir) import Node.FS.Dirent (Dirent, DirentNameTypeBuffer, DirentNameTypeString) import Node.FS.Perms (Perms, permsToString) diff --git a/src/Node/FS/Dir.purs b/src/Node/FS/Dir.purs index 27cb661..2030cc2 100644 --- a/src/Node/FS/Dir.purs +++ b/src/Node/FS/Dir.purs @@ -2,12 +2,10 @@ module Node.FS.Dir where import Prelude -import Data.Either (Either) import Data.Maybe (Maybe) import Data.Nullable (Nullable, toMaybe) import Effect (Effect) -import Effect.Exception (Error) -import Effect.Uncurried (EffectFn1, EffectFn2, mkEffectFn1, runEffectFn1, runEffectFn2) +import Effect.Uncurried (EffectFn1, EffectFn2, runEffectFn1, runEffectFn2) import Node.FS.Dirent (Dirent, DirentNameTypeString) import Node.FS.Internal.Utils (Callback0, JSCallback0, JSCallback1, Callback1, handleCallback0, handleCallback1) import Node.Path (FilePath) diff --git a/src/Node/FS/Sync.purs b/src/Node/FS/Sync.purs index 5388829..0504fc3 100644 --- a/src/Node/FS/Sync.purs +++ b/src/Node/FS/Sync.purs @@ -81,18 +81,15 @@ module Node.FS.Sync , writev ) where -import Node.FS.Constants -import Node.FS.Options -import Node.FS.Types +import Node.FS.Constants (AccessMode, CopyMode, FileFlags, defaultAccessMode, defaultCopyMode, fileFlagsToNode) +import Node.FS.Options (AppendFileBufferOptions, AppendFileOptionsInternal, AppendFileStringOptions, CpOptions, CpOptionsInternal, FdReadOptions, FdReadOptionsInternal, FdWriteOptions, FdWriteOptionsInternal, GlobDirentOptions, GlobFilePathOptions, GlobOptionsInternal, MkdirOptions, MkdirOptionsInternal, OpendirOptions, OpendirOptionsInternal, ReadFileBufferOptions, ReadFileOptionsInternal, ReadFileStringOptions, ReaddirBufferOptions, ReaddirDirentBufferOptions, ReaddirDirentOptions, ReaddirFilePathOptions, ReaddirOptionsInternal, RealpathOptions, RealpathOptionsInternal, RmOptions, RmdirOptions, WriteFileBufferOptions, WriteFileOptionsInternal, WriteFileStringOptions, appendFileBufferOptionsDefault, appendFileBufferOptionsToInternal, appendFileStringOptionsDefault, appendFileStringOptionsToInternal, cpOptionsDefault, cpOptionsToCpOptionsInternal, fdReadOptionsToInternal, fdWriteOptionsToInternal, globDirentOptionsDefault, globDirentOptionsToInternal, globFilePathOptionsDefault, globFilePathOptionsToInternal, mkdirOptionsDefault, mkdirOptionsToInternal, opendirOptionsDefault, opendirOptionsToInternal, readFileBufferOptionsDefault, readFileBufferOptionsToInternal, readFileStringOptionsDefault, readFileStringOptionsToInternal, readdirBufferOptionsDefault, readdirBufferOptionsToInternal, readdirDirentBufferOptionsDefault, readdirDirentBufferOptionsToInternal, readdirDirentOptionsDefault, readdirDirentOptionsToInternal, readdirFilePathOptionsDefault, readdirFilePathOptionsToInternal, realpathOptionsDefault, realpathOptionsToInternal, rmOptionsDefault, rmdirOptionsDefault, writeFileBufferOptionsDefault, writeFileBufferOptionsToInternal, writeFileStringOptionsDefault, writeFileStringOptionsToInternal) +import Node.FS.Types (BufferLength, BufferOffset, ByteCount, FileDescriptor, FileMode, FilePosition, SymlinkType, symlinkTypeToNode) import Prelude import Data.DateTime (DateTime) -import Data.DateTime.Instant (fromDateTime, unInstant) import Data.Either (blush) -import Data.Int (round) import Data.Maybe (Maybe(..)) import Data.Nullable (Nullable, toNullable) -import Data.Time.Duration (Milliseconds(..)) import Effect (Effect) import Effect.Exception (Error, try) import Effect.Uncurried (EffectFn1, EffectFn2, EffectFn3, EffectFn4, EffectFn5, runEffectFn1, runEffectFn2, runEffectFn3, runEffectFn4, runEffectFn5) @@ -101,7 +98,7 @@ import Node.Encoding (Encoding(..), encodingToNode) import Node.FS.Dir (Dir) import Node.FS.Dirent (Dirent, DirentNameTypeBuffer, DirentNameTypeString) import Node.FS.Internal.Utils (datetimeToUnixEpochTimeInSeconds) -import Node.FS.Perms (Perms, permsToString, all, mkPerms) +import Node.FS.Perms (Perms, permsToString) import Node.FS.Stats (Stats) import Node.Path (FilePath) import Prim.TypeError (class Warn, Text) From 6f00cdfe31b743ce0ea0a85c7f84db3f9d5e22bb Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Sun, 6 Oct 2024 17:26:31 +0700 Subject: [PATCH 13/32] feat: remove Node.FS.Sync.fdFlush --- CHANGELOG.md | 26 ++------------------------ src/Node/FS/Sync.purs | 7 ------- test/Test/Node/FS/Sync.purs | 2 +- 3 files changed, 3 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 771a510..1c26ba7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ Breaking changes: New features: -- Add functions to `Node.FS.Async` +- Add functions to `Node.FS.Async`, `Node.FS.Aff`, `Node.FS.Sync` - readdir' - readdirBuffer @@ -39,29 +39,7 @@ New features: - statfs - writev -- Add functions to `Node.FS.Aff` - - - cp - - cp' - - fchmod - - fchown - - fdatasync - - fstat - - fsync - - ftruncate - - futimes - - glob - - glob' - - globDirent - - globDirent' - - lchmod - - lchown - - lutimes - - opendir - - opendir' - - readv - - statfs - - writev +- Deprecate `Node.FS.Sync.fdFlush`, `Node.FS.Sync.fsync` should be used instead - Add modules `Dir`, `Dir.Aff`, `Dirent` diff --git a/src/Node/FS/Sync.purs b/src/Node/FS/Sync.purs index 0504fc3..236590e 100644 --- a/src/Node/FS/Sync.purs +++ b/src/Node/FS/Sync.purs @@ -52,7 +52,6 @@ module Node.FS.Sync , fdWrite' , fdWriteString , fdAppend - , fdFlush , fdClose , cp , cp' @@ -101,7 +100,6 @@ import Node.FS.Internal.Utils (datetimeToUnixEpochTimeInSeconds) import Node.FS.Perms (Perms, permsToString) import Node.FS.Stats (Stats) import Node.Path (FilePath) -import Prim.TypeError (class Warn, Text) import Unsafe.Coerce (unsafeCoerce) foreign import accessSyncImpl :: EffectFn2 FilePath AccessMode Unit @@ -526,11 +524,6 @@ fdAppend fd buff = do sz <- size buff fdWrite fd buff 0 sz Nothing --- | Flush a file synchronously. See the [Node documentation](http://nodejs.org/api/fs.html#fs_fs_fsyncsync_fd) --- | for details. -fdFlush :: Warn (Text "Deprecated, use fsync") => FileDescriptor -> Effect Unit -fdFlush = fsync - -- | Close a file synchronously. See the [Node documentation](http://nodejs.org/api/fs.html#fs_fs_closesync_fd) -- | for details. fdClose :: FileDescriptor -> Effect Unit diff --git a/test/Test/Node/FS/Sync.purs b/test/Test/Node/FS/Sync.purs index de6a4a9..2897b67 100644 --- a/test/Test/Node/FS/Sync.purs +++ b/test/Test/Node/FS/Sync.purs @@ -153,7 +153,7 @@ main = do fd0 <- S.fdOpen fdFile W (Just 420) buf0 <- Buffer.fromString "[ 42 ]" UTF8 _bytes0 <- S.fdAppend fd0 buf0 - S.fdFlush fd0 + S.fsync fd0 S.fdClose fd0 fd1 <- S.fdOpen fdFile R Nothing buf1 <- Buffer.create =<< Buffer.size buf0 From 602a6a8e1032983d9aca3a281ec9bbe8208331ac Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Sun, 6 Oct 2024 17:46:33 +0700 Subject: [PATCH 14/32] fix: write --- src/Node/FS/Aff.purs | 3 ++- src/Node/FS/Async.purs | 16 ++++++++-------- src/Node/FS/Sync.purs | 24 ++++++++++++------------ 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/Node/FS/Aff.purs b/src/Node/FS/Aff.purs index 0ff4987..802c758 100644 --- a/src/Node/FS/Aff.purs +++ b/src/Node/FS/Aff.purs @@ -378,9 +378,10 @@ fdWrite = toAff5 A.fdWrite -- | for details. fdWrite' :: FileDescriptor + -> Buffer -> FdWriteOptions -> Aff (Tuple ByteCount Buffer) -fdWrite' = toAff2 A.fdWrite' +fdWrite' = toAff3 A.fdWrite' -- It is unsafe to use fs.write() multiple times on the same file without waiting for the callback. For this scenario, fs.createWriteStream() is recommended. fdWriteString diff --git a/src/Node/FS/Async.purs b/src/Node/FS/Async.purs index 72be567..6706dda 100644 --- a/src/Node/FS/Async.purs +++ b/src/Node/FS/Async.purs @@ -92,12 +92,13 @@ import Node.Buffer (Buffer, size) import Node.Encoding (Encoding(..), encodingToNode) import Node.FS (FileDescriptor, ByteCount, FilePosition, BufferLength, BufferOffset, FileMode, SymlinkType, symlinkTypeToNode) import Node.FS.Constants (AccessMode, CopyMode, FileFlags, defaultAccessMode, defaultCopyMode, fileFlagsToNode) -import Node.FS.Internal.Utils (Callback0, Callback1, JSCallback0, JSCallback1, JSCallback2, datetimeToUnixEpochTimeInSeconds, handleCallback0, handleCallback1, handleCallback1Tuple) -import Node.FS.Options (AppendFileBufferOptions, AppendFileOptionsInternal, AppendFileStringOptions, CpOptions, CpOptionsInternal, FdReadOptions, FdReadOptionsInternal, FdWriteOptions, FdWriteOptionsInternal, GlobDirentOptions, GlobFilePathOptions, GlobOptionsInternal, MkdirOptions, MkdirOptionsInternal, OpendirOptions, OpendirOptionsInternal, ReadFileBufferOptions, ReadFileOptionsInternal, ReadFileStringOptions, ReaddirBufferOptions, ReaddirDirentBufferOptions, ReaddirDirentOptions, ReaddirFilePathOptions, ReaddirOptionsInternal, RealpathOptions, RealpathOptionsInternal, RmOptions, RmdirOptions, WriteFileBufferOptions, WriteFileOptionsInternal, WriteFileStringOptions, appendFileBufferOptionsDefault, appendFileBufferOptionsToInternal, appendFileStringOptionsDefault, appendFileStringOptionsToInternal, cpOptionsDefault, cpOptionsToCpOptionsInternal, fdReadOptionsToInternal, fdWriteOptionsToInternal, globDirentOptionsDefault, globDirentOptionsToInternal, globFilePathOptionsDefault, globFilePathOptionsToInternal, mkdirOptionsDefault, mkdirOptionsToInternal, opendirOptionsDefault, opendirOptionsToInternal, readFileBufferOptionsDefault, readFileBufferOptionsToInternal, readFileStringOptionsDefault, readFileStringOptionsToInternal, readdirBufferOptionsDefault, readdirBufferOptionsToInternal, readdirDirentBufferOptionsDefault, readdirDirentBufferOptionsToInternal, readdirDirentOptionsDefault, readdirDirentOptionsToInternal, readdirFilePathOptionsDefault, readdirFilePathOptionsToInternal, realpathOptionsDefault, realpathOptionsToInternal, rmOptionsDefault, rmdirOptionsDefault, writeFileBufferOptionsDefault, writeFileBufferOptionsToInternal, writeFileStringOptionsDefault, writeFileStringOptionsToInternal) import Node.FS.Dir (Dir) import Node.FS.Dirent (Dirent, DirentNameTypeBuffer, DirentNameTypeString) +import Node.FS.Internal.Utils (Callback0, Callback1, JSCallback0, JSCallback1, JSCallback2, datetimeToUnixEpochTimeInSeconds, handleCallback0, handleCallback1, handleCallback1Tuple) +import Node.FS.Options (AppendFileBufferOptions, AppendFileOptionsInternal, AppendFileStringOptions, CpOptions, CpOptionsInternal, FdReadOptions, FdReadOptionsInternal, FdWriteOptions, FdWriteOptionsInternal, GlobDirentOptions, GlobFilePathOptions, GlobOptionsInternal, MkdirOptions, MkdirOptionsInternal, OpendirOptions, OpendirOptionsInternal, ReadFileBufferOptions, ReadFileOptionsInternal, ReadFileStringOptions, ReaddirBufferOptions, ReaddirDirentBufferOptions, ReaddirDirentOptions, ReaddirFilePathOptions, ReaddirOptionsInternal, RealpathOptions, RealpathOptionsInternal, RmOptions, RmdirOptions, WriteFileBufferOptions, WriteFileOptionsInternal, WriteFileStringOptions, appendFileBufferOptionsDefault, appendFileBufferOptionsToInternal, appendFileStringOptionsDefault, appendFileStringOptionsToInternal, cpOptionsDefault, cpOptionsToCpOptionsInternal, fdReadOptionsToInternal, fdWriteOptionsToInternal, globDirentOptionsDefault, globDirentOptionsToInternal, globFilePathOptionsDefault, globFilePathOptionsToInternal, mkdirOptionsDefault, mkdirOptionsToInternal, opendirOptionsDefault, opendirOptionsToInternal, readFileBufferOptionsDefault, readFileBufferOptionsToInternal, readFileStringOptionsDefault, readFileStringOptionsToInternal, readdirBufferOptionsDefault, readdirBufferOptionsToInternal, readdirDirentBufferOptionsDefault, readdirDirentBufferOptionsToInternal, readdirDirentOptionsDefault, readdirDirentOptionsToInternal, readdirFilePathOptionsDefault, readdirFilePathOptionsToInternal, realpathOptionsDefault, realpathOptionsToInternal, rmOptionsDefault, rmdirOptionsDefault, writeFileBufferOptionsDefault, writeFileBufferOptionsToInternal, writeFileStringOptionsDefault, writeFileStringOptionsToInternal) import Node.FS.Perms (Perms, permsToString) import Node.FS.Stats (Stats) +import Node.FS.Types (EncodingString) import Node.Path (FilePath) import Unsafe.Coerce (unsafeCoerce) @@ -134,12 +135,10 @@ readWithOptionsImpl = unsafeCoerce readImpl foreign import writeImpl :: EffectFn6 FileDescriptor Buffer BufferOffset BufferLength (Nullable FilePosition) (JSCallback1 ByteCount) Unit --- https://nodejs.org/docs/latest/api/fs.html#fsreadfd-options-callback -writeWithOptionsImpl :: EffectFn3 FileDescriptor FdWriteOptionsInternal (JSCallback2 ByteCount Buffer) Unit -writeWithOptionsImpl = unsafeCoerce writeImpl +writeBufferWithOptionsImpl :: EffectFn4 FileDescriptor Buffer FdWriteOptionsInternal (JSCallback2 ByteCount Buffer) Unit +writeBufferWithOptionsImpl = unsafeCoerce writeImpl --- https://nodejs.org/docs/latest/api/fs.html#fsreadfd-options-callback -writeStringImpl :: EffectFn5 FileDescriptor String (Nullable FilePosition) String (JSCallback2 ByteCount String) Unit +writeStringImpl :: EffectFn5 FileDescriptor String (Nullable FilePosition) EncodingString (JSCallback2 ByteCount String) Unit writeStringImpl = unsafeCoerce writeImpl foreign import closeImpl :: EffectFn2 FileDescriptor JSCallback0 Unit @@ -545,10 +544,11 @@ fdWrite fd buff off len pos cb = runEffectFn6 writeImpl fd buff off len (toNulla -- | for details. fdWrite' :: FileDescriptor + -> Buffer -> FdWriteOptions -> Callback1 (Tuple ByteCount Buffer) -> Effect Unit -fdWrite' fd options cb = runEffectFn3 writeWithOptionsImpl fd (fdWriteOptionsToInternal options) (handleCallback1Tuple cb) +fdWrite' fd buffer options cb = runEffectFn4 writeBufferWithOptionsImpl fd buffer (fdWriteOptionsToInternal options) (handleCallback1Tuple cb) -- It is unsafe to use fs.write() multiple times on the same file without waiting for the callback. For this scenario, fs.createWriteStream() is recommended. fdWriteString diff --git a/src/Node/FS/Sync.purs b/src/Node/FS/Sync.purs index 236590e..f13c3dd 100644 --- a/src/Node/FS/Sync.purs +++ b/src/Node/FS/Sync.purs @@ -80,9 +80,6 @@ module Node.FS.Sync , writev ) where -import Node.FS.Constants (AccessMode, CopyMode, FileFlags, defaultAccessMode, defaultCopyMode, fileFlagsToNode) -import Node.FS.Options (AppendFileBufferOptions, AppendFileOptionsInternal, AppendFileStringOptions, CpOptions, CpOptionsInternal, FdReadOptions, FdReadOptionsInternal, FdWriteOptions, FdWriteOptionsInternal, GlobDirentOptions, GlobFilePathOptions, GlobOptionsInternal, MkdirOptions, MkdirOptionsInternal, OpendirOptions, OpendirOptionsInternal, ReadFileBufferOptions, ReadFileOptionsInternal, ReadFileStringOptions, ReaddirBufferOptions, ReaddirDirentBufferOptions, ReaddirDirentOptions, ReaddirFilePathOptions, ReaddirOptionsInternal, RealpathOptions, RealpathOptionsInternal, RmOptions, RmdirOptions, WriteFileBufferOptions, WriteFileOptionsInternal, WriteFileStringOptions, appendFileBufferOptionsDefault, appendFileBufferOptionsToInternal, appendFileStringOptionsDefault, appendFileStringOptionsToInternal, cpOptionsDefault, cpOptionsToCpOptionsInternal, fdReadOptionsToInternal, fdWriteOptionsToInternal, globDirentOptionsDefault, globDirentOptionsToInternal, globFilePathOptionsDefault, globFilePathOptionsToInternal, mkdirOptionsDefault, mkdirOptionsToInternal, opendirOptionsDefault, opendirOptionsToInternal, readFileBufferOptionsDefault, readFileBufferOptionsToInternal, readFileStringOptionsDefault, readFileStringOptionsToInternal, readdirBufferOptionsDefault, readdirBufferOptionsToInternal, readdirDirentBufferOptionsDefault, readdirDirentBufferOptionsToInternal, readdirDirentOptionsDefault, readdirDirentOptionsToInternal, readdirFilePathOptionsDefault, readdirFilePathOptionsToInternal, realpathOptionsDefault, realpathOptionsToInternal, rmOptionsDefault, rmdirOptionsDefault, writeFileBufferOptionsDefault, writeFileBufferOptionsToInternal, writeFileStringOptionsDefault, writeFileStringOptionsToInternal) -import Node.FS.Types (BufferLength, BufferOffset, ByteCount, FileDescriptor, FileMode, FilePosition, SymlinkType, symlinkTypeToNode) import Prelude import Data.DateTime (DateTime) @@ -94,11 +91,14 @@ import Effect.Exception (Error, try) import Effect.Uncurried (EffectFn1, EffectFn2, EffectFn3, EffectFn4, EffectFn5, runEffectFn1, runEffectFn2, runEffectFn3, runEffectFn4, runEffectFn5) import Node.Buffer (Buffer, size) import Node.Encoding (Encoding(..), encodingToNode) +import Node.FS.Constants (AccessMode, CopyMode, FileFlags, defaultAccessMode, defaultCopyMode, fileFlagsToNode) import Node.FS.Dir (Dir) import Node.FS.Dirent (Dirent, DirentNameTypeBuffer, DirentNameTypeString) import Node.FS.Internal.Utils (datetimeToUnixEpochTimeInSeconds) +import Node.FS.Options (AppendFileBufferOptions, AppendFileOptionsInternal, AppendFileStringOptions, CpOptions, CpOptionsInternal, FdReadOptions, FdReadOptionsInternal, FdWriteOptions, FdWriteOptionsInternal, GlobDirentOptions, GlobFilePathOptions, GlobOptionsInternal, MkdirOptions, MkdirOptionsInternal, OpendirOptions, OpendirOptionsInternal, ReadFileBufferOptions, ReadFileOptionsInternal, ReadFileStringOptions, ReaddirBufferOptions, ReaddirDirentBufferOptions, ReaddirDirentOptions, ReaddirFilePathOptions, ReaddirOptionsInternal, RealpathOptions, RealpathOptionsInternal, RmOptions, RmdirOptions, WriteFileBufferOptions, WriteFileOptionsInternal, WriteFileStringOptions, appendFileBufferOptionsDefault, appendFileBufferOptionsToInternal, appendFileStringOptionsDefault, appendFileStringOptionsToInternal, cpOptionsDefault, cpOptionsToCpOptionsInternal, fdReadOptionsToInternal, fdWriteOptionsToInternal, globDirentOptionsDefault, globDirentOptionsToInternal, globFilePathOptionsDefault, globFilePathOptionsToInternal, mkdirOptionsDefault, mkdirOptionsToInternal, opendirOptionsDefault, opendirOptionsToInternal, readFileBufferOptionsDefault, readFileBufferOptionsToInternal, readFileStringOptionsDefault, readFileStringOptionsToInternal, readdirBufferOptionsDefault, readdirBufferOptionsToInternal, readdirDirentBufferOptionsDefault, readdirDirentBufferOptionsToInternal, readdirDirentOptionsDefault, readdirDirentOptionsToInternal, readdirFilePathOptionsDefault, readdirFilePathOptionsToInternal, realpathOptionsDefault, realpathOptionsToInternal, rmOptionsDefault, rmdirOptionsDefault, writeFileBufferOptionsDefault, writeFileBufferOptionsToInternal, writeFileStringOptionsDefault, writeFileStringOptionsToInternal) import Node.FS.Perms (Perms, permsToString) import Node.FS.Stats (Stats) +import Node.FS.Types (BufferLength, BufferOffset, ByteCount, FileDescriptor, FileMode, FilePosition, SymlinkType, EncodingString, symlinkTypeToNode) import Node.Path (FilePath) import Unsafe.Coerce (unsafeCoerce) @@ -135,11 +135,11 @@ readWithOptionsSyncImpl = unsafeCoerce readSyncImpl foreign import writeSyncImpl :: EffectFn5 FileDescriptor Buffer BufferOffset BufferLength (Nullable FilePosition) ByteCount -- https://nodejs.org/docs/latest/api/fs.html#fsreadfd-options-callback -writeWithOptionsSyncImpl :: EffectFn2 FileDescriptor FdWriteOptionsInternal ByteCount -writeWithOptionsSyncImpl = unsafeCoerce writeSyncImpl +writeBufferWithOptionsSyncImpl :: EffectFn3 FileDescriptor Buffer FdWriteOptionsInternal ByteCount +writeBufferWithOptionsSyncImpl = unsafeCoerce writeSyncImpl -- https://nodejs.org/docs/latest/api/fs.html#fsreadfd-options-callback -writeStringSyncImpl :: EffectFn4 FileDescriptor String (Nullable FilePosition) String ByteCount +writeStringSyncImpl :: EffectFn4 FileDescriptor String (Nullable FilePosition) EncodingString ByteCount writeStringSyncImpl = unsafeCoerce writeSyncImpl foreign import closeSyncImpl :: EffectFn1 FileDescriptor Unit @@ -164,8 +164,7 @@ access :: FilePath -> Effect (Maybe Error) access = flip access' defaultAccessMode access' :: FilePath -> AccessMode -> Effect (Maybe Error) -access' path mode = do - map blush $ try $ runEffectFn2 accessSyncImpl path mode +access' path mode = map blush $ try $ runEffectFn2 accessSyncImpl path mode copyFile :: FilePath -> FilePath -> Effect Unit copyFile src dest = runEffectFn3 copyFileSyncImpl src dest defaultCopyMode @@ -467,7 +466,7 @@ fdRead fdRead fd buff off len pos = runEffectFn5 readSyncImpl fd buff off len (toNullable pos) --- | Read from a file asynchronously. See the [Node Documentation](https://nodejs.org/docs/latest/api/fs.html#fsreadfd-options-callback) +-- | Read from a file synchronously. See the [Node Documentation](https://nodejs.org/docs/latest/api/fs.html#fsreadsyncfd-buffer-offset-length-position) -- | for details. fdRead' :: FileDescriptor @@ -497,13 +496,14 @@ fdWrite fdWrite fd buff off len pos = runEffectFn5 writeSyncImpl fd buff off len (toNullable pos) --- | Write from a file asynchronously. See the [Node Documentation](https://nodejs.org/docs/latest/api/fs.html#fswritefd-options-callback) +-- | Write from a file synchronously. See the [Node Documentation](https://nodejs.org/docs/latest/api/fs.html#fswritefd-options-callback) -- | for details. fdWrite' :: FileDescriptor + -> Buffer -> FdWriteOptions -> Effect ByteCount -fdWrite' fd options = runEffectFn2 writeWithOptionsSyncImpl fd (fdWriteOptionsToInternal options) +fdWrite' fd buffer options = runEffectFn3 writeBufferWithOptionsSyncImpl fd buffer (fdWriteOptionsToInternal options) -- It is unsafe to use fs.write() multiple times on the same file without waiting for the callback. For this scenario, fs.createWriteStream() is recommended. fdWriteString @@ -529,7 +529,7 @@ fdAppend fd buff = do fdClose :: FileDescriptor -> Effect Unit fdClose fd = runEffectFn1 closeSyncImpl fd --- | Copy a file asynchronously. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fspromises_copyfile_src_dest_mode) +-- | Copy a file synchronously. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fspromises_copyfile_src_dest_mode) -- | for details. cp :: FilePath -> FilePath -> Effect Unit cp src dest = cp' src dest cpOptionsDefault From 9b146deee7c3f96d57cc9d7e5a025bdbc88f8d5f Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Sun, 6 Oct 2024 18:03:20 +0700 Subject: [PATCH 15/32] fix(#81): add copyFile_NO_FLAGS, make it default --- src/Node/FS/Constants.js | 6 +----- src/Node/FS/Constants.purs | 8 +++++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/Node/FS/Constants.js b/src/Node/FS/Constants.js index b71e93c..2cdddc7 100644 --- a/src/Node/FS/Constants.js +++ b/src/Node/FS/Constants.js @@ -1,17 +1,13 @@ import { constants } from "node:fs"; export const f_OK = constants.F_OK; - export const r_OK = constants.R_OK; - export const w_OK = constants.W_OK; - export const x_OK = constants.X_OK; +export const copyFile_NO_FLAGS = 0; export const copyFile_EXCL = constants.COPYFILE_EXCL; - export const copyFile_FICLONE = constants.COPYFILE_FICLONE; - export const copyFile_FICLONE_FORCE = constants.COPYFILE_FICLONE_FORCE; export const appendCopyMode = (l, r) => l | r; diff --git a/src/Node/FS/Constants.purs b/src/Node/FS/Constants.purs index 24f4880..1d9c4e7 100644 --- a/src/Node/FS/Constants.purs +++ b/src/Node/FS/Constants.purs @@ -7,7 +7,7 @@ import Data.Function.Uncurried (Fn2, runFn2) -- | the mode parameter passed to `access` and `accessSync`. foreign import data AccessMode :: Type --- | the file is visible to the calling process. +-- | the file is visible to the calling process. -- | This is useful for determining if a file exists, but says nothing about rwx permissions. Default if no mode is specified. foreign import f_OK :: AccessMode @@ -25,6 +25,9 @@ defaultAccessMode = f_OK :: AccessMode -- | A constant used in `copyFile`. foreign import data CopyMode :: Type +-- | By default, `dest` is overwritten if it already exists. +foreign import copyFile_NO_FLAGS :: CopyMode + -- | If present, the copy operation will fail with an error if the destination path already exists. foreign import copyFile_EXCL :: CopyMode @@ -34,7 +37,7 @@ foreign import copyFile_FICLONE :: CopyMode -- | If present, the copy operation will attempt to create a copy-on-write reflink. If the underlying platform does not support copy-on-write, then the operation will fail with an error. foreign import copyFile_FICLONE_FORCE :: CopyMode -defaultCopyMode = copyFile_EXCL :: CopyMode +defaultCopyMode = copyFile_NO_FLAGS :: CopyMode foreign import appendCopyMode :: Fn2 CopyMode CopyMode CopyMode @@ -88,4 +91,3 @@ fileFlagsToNode ff = case ff of AX -> "ax" A_PLUS -> "a+" AX_PLUS -> "ax+" - From 6575fd1eae9d9811d0d1ce0be8027da756c5b329 Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Sun, 6 Oct 2024 18:09:05 +0700 Subject: [PATCH 16/32] fix: --strict --- spago.lock | 1 + spago.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/spago.lock b/spago.lock index 49fc213..876a950 100644 --- a/spago.lock +++ b/spago.lock @@ -12,6 +12,7 @@ "either", "enums", "exceptions", + "foreign", "functions", "integers", "js-date", diff --git a/spago.yaml b/spago.yaml index a37a130..558e38b 100644 --- a/spago.yaml +++ b/spago.yaml @@ -14,6 +14,7 @@ package: - either - enums - exceptions + - foreign - functions - integers - js-date From b0a8cca30aa77f5803a3dff98e330f6e267d0a0a Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Sun, 6 Oct 2024 23:03:39 +0700 Subject: [PATCH 17/32] fix: futimes, feat: add readlinkBuffer --- src/Node/FS/Aff.purs | 6 +++++- src/Node/FS/Async.purs | 21 ++++++++++++++------- src/Node/FS/Sync.purs | 16 ++++++++++------ 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/Node/FS/Aff.purs b/src/Node/FS/Aff.purs index 802c758..af722e3 100644 --- a/src/Node/FS/Aff.purs +++ b/src/Node/FS/Aff.purs @@ -14,6 +14,7 @@ module Node.FS.Aff , link , symlink , readlink + , readlinkBuffer , realpath , realpath' , unlink @@ -179,6 +180,9 @@ symlink = toAff3 A.symlink readlink :: FilePath -> Aff FilePath readlink = toAff1 A.readlink +readlinkBuffer :: FilePath -> Aff Buffer +readlinkBuffer = toAff1 A.readlinkBuffer + -- | -- | Find the canonicalized absolute location for a path. -- | @@ -442,7 +446,7 @@ ftruncate = toAff2 A.ftruncate -- | Change file timestamps for a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_futimes_fd_atime_mtime_callback) -- | for details. -futimes :: FilePath -> DateTime -> DateTime -> Aff Unit +futimes :: FileDescriptor -> DateTime -> DateTime -> Aff Unit futimes = toAff3 A.futimes -- | Perform pattern matching in file paths. See the [Node Documentation](https://nodejs.org/api/glob.html#globglob_pattern_options_callback) diff --git a/src/Node/FS/Async.purs b/src/Node/FS/Async.purs index 6706dda..0f32438 100644 --- a/src/Node/FS/Async.purs +++ b/src/Node/FS/Async.purs @@ -14,6 +14,7 @@ module Node.FS.Async , link , symlink , readlink + , readlinkBuffer , realpath , realpath' , unlink @@ -114,6 +115,10 @@ foreign import lstatImpl :: EffectFn2 FilePath (JSCallback1 Stats) Unit foreign import linkImpl :: EffectFn3 FilePath FilePath JSCallback0 Unit foreign import symlinkImpl :: EffectFn4 FilePath FilePath (Nullable String) JSCallback0 Unit foreign import readlinkImpl :: EffectFn2 FilePath (JSCallback1 FilePath) Unit + +readlinkBufferImpl :: EffectFn3 FilePath String (JSCallback1 Buffer) Unit +readlinkBufferImpl = unsafeCoerce readlinkImpl + foreign import realpathImpl :: EffectFn3 FilePath RealpathOptionsInternal (JSCallback1 FilePath) Unit foreign import unlinkImpl :: EffectFn2 FilePath JSCallback0 Unit foreign import rmdirImpl :: EffectFn3 FilePath RmdirOptions JSCallback0 Unit @@ -254,6 +259,13 @@ readlink -> Effect Unit readlink path cb = runEffectFn2 readlinkImpl path (handleCallback1 cb) +-- | Reads the value of a symlink, returns buffer. +readlinkBuffer + :: FilePath + -> Callback1 Buffer + -> Effect Unit +readlinkBuffer path cb = runEffectFn3 readlinkBufferImpl path "buffer" (handleCallback1 cb) + -- | Find the canonicalized absolute location for a path. realpath :: FilePath @@ -619,13 +631,8 @@ ftruncate fd len cb = runEffectFn3 ftruncateImpl fd len (handleCallback0 cb) -- | Change file timestamps for a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_futimes_fd_atime_mtime_callback) -- | for details. -futimes - :: FilePath - -> DateTime - -> DateTime - -> Callback0 - -> Effect Unit -futimes file atime mtime cb = runEffectFn4 lutimesImpl file (datetimeToUnixEpochTimeInSeconds atime) (datetimeToUnixEpochTimeInSeconds mtime) (handleCallback0 cb) +futimes :: FileDescriptor -> DateTime -> DateTime -> Callback0 -> Effect Unit +futimes fd atime mtime cb = runEffectFn4 futimesImpl fd (datetimeToUnixEpochTimeInSeconds atime) (datetimeToUnixEpochTimeInSeconds mtime) (handleCallback0 cb) -- | Perform pattern matching in file paths. See the [Node Documentation](https://nodejs.org/api/glob.html#globglob_pattern_options_callback) -- | for details. diff --git a/src/Node/FS/Sync.purs b/src/Node/FS/Sync.purs index f13c3dd..0a8067f 100644 --- a/src/Node/FS/Sync.purs +++ b/src/Node/FS/Sync.purs @@ -14,6 +14,7 @@ module Node.FS.Sync , link , symlink , readlink + , readlinkBuffer , realpath , realpath' , unlink @@ -114,6 +115,10 @@ foreign import lstatSyncImpl :: EffectFn1 FilePath Stats foreign import linkSyncImpl :: EffectFn2 FilePath FilePath Unit foreign import symlinkSyncImpl :: EffectFn3 FilePath FilePath (Nullable String) Unit foreign import readlinkSyncImpl :: EffectFn1 FilePath FilePath + +readlinkBufferSyncImpl :: EffectFn2 FilePath String Buffer +readlinkBufferSyncImpl = unsafeCoerce readlinkSyncImpl + foreign import realpathSyncImpl :: EffectFn2 FilePath RealpathOptionsInternal FilePath foreign import unlinkSyncImpl :: EffectFn1 FilePath Unit foreign import rmdirSyncImpl :: EffectFn2 FilePath RmdirOptions Unit @@ -239,6 +244,9 @@ readlink -> Effect FilePath readlink path = runEffectFn1 readlinkSyncImpl path +readlinkBuffer :: FilePath -> Effect Buffer +readlinkBuffer path = runEffectFn2 readlinkBufferSyncImpl path "buffer" + -- | Find the canonicalized absolute location for a path. realpath :: FilePath @@ -569,12 +577,8 @@ ftruncate fd len = runEffectFn2 ftruncateSyncImpl fd len -- | Change file timestamps for a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_futimes_fd_atime_mtime_callback) -- | for details. -futimes - :: FilePath - -> DateTime - -> DateTime - -> Effect Unit -futimes file atime mtime = runEffectFn3 lutimesSyncImpl file (datetimeToUnixEpochTimeInSeconds atime) (datetimeToUnixEpochTimeInSeconds mtime) +futimes :: FileDescriptor -> DateTime -> DateTime -> Effect Unit +futimes fd atime mtime = runEffectFn3 futimesSyncImpl fd (datetimeToUnixEpochTimeInSeconds atime) (datetimeToUnixEpochTimeInSeconds mtime) -- | Perform pattern matching in file paths. See the [Node Documentation](https://nodejs.org/api/glob.html#globglob_pattern_options_callback) -- | for details. From 20f566a0e77351c7d7591b89e825cf9863b06cea Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Tue, 8 Oct 2024 13:28:40 +0700 Subject: [PATCH 18/32] feat: show for Dir, fix: show for Dirent --- src/Node/FS/Dir.js | 2 ++ src/Node/FS/Dir.purs | 5 +++++ src/Node/FS/Dirent.purs | 2 +- test/Test/Node/FS/OpendirAndDir.purs | 22 +++++++++++++--------- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/Node/FS/Dir.js b/src/Node/FS/Dir.js index 38e76c0..17abb12 100644 --- a/src/Node/FS/Dir.js +++ b/src/Node/FS/Dir.js @@ -1,3 +1,5 @@ +export { inspect as showDirObj } from "util"; + export const closeImpl = (dir, callback) => dir.close(callback); export const closeSyncImpl = (dir) => dir.close(); export const path = (dir) => dir.path; diff --git a/src/Node/FS/Dir.purs b/src/Node/FS/Dir.purs index 2030cc2..c9e7a07 100644 --- a/src/Node/FS/Dir.purs +++ b/src/Node/FS/Dir.purs @@ -13,6 +13,11 @@ import Node.Path (FilePath) -- Foreign imports for the Dir class foreign import data Dir :: Type +foreign import showDirObj :: Dir -> String + +instance Show Dir where + show s = showDirObj s + foreign import closeImpl :: EffectFn2 Dir JSCallback0 Unit foreign import closeSyncImpl :: EffectFn1 Dir Unit foreign import readImpl :: EffectFn2 Dir (JSCallback1 (Nullable (Dirent DirentNameTypeString))) Unit diff --git a/src/Node/FS/Dirent.purs b/src/Node/FS/Dirent.purs index a11ba98..c544f17 100644 --- a/src/Node/FS/Dirent.purs +++ b/src/Node/FS/Dirent.purs @@ -55,4 +55,4 @@ foreign import parentPath :: forall direntnametype. Dirent direntnametype -> Fil foreign import showDirentObj :: forall direntnametype. Dirent direntnametype -> String instance Show (Dirent direntnametype) where - show s = "Dirent " <> showDirentObj s + show s = showDirentObj s diff --git a/test/Test/Node/FS/OpendirAndDir.purs b/test/Test/Node/FS/OpendirAndDir.purs index 5a0451e..e43350d 100644 --- a/test/Test/Node/FS/OpendirAndDir.purs +++ b/test/Test/Node/FS/OpendirAndDir.purs @@ -38,31 +38,35 @@ prepare = do test1 :: Aff Unit test1 = do dir <- A.opendir' outerTmpDir (opendirOptionsDefault { recursive = true }) + liftEffect $ assertEqual + { actual: show dir + , expected: "Dir {}" + } files' <- entries dir liftEffect $ assertEqual { actual: show files' , expected: - """[Dirent Dirent { + """[Dirent { name: 'dir1', parentPath: 'tmp/dir-entries-test', path: 'tmp/dir-entries-test', [Symbol(type)]: 2 -},Dirent Dirent { +},Dirent { name: '1.txt', parentPath: 'tmp/dir-entries-test', path: 'tmp/dir-entries-test', [Symbol(type)]: 1 -},Dirent Dirent { +},Dirent { name: '2.txt', parentPath: 'tmp/dir-entries-test', path: 'tmp/dir-entries-test', [Symbol(type)]: 1 -},Dirent Dirent { +},Dirent { name: '3.txt', parentPath: 'tmp/dir-entries-test/dir1', path: 'tmp/dir-entries-test/dir1', [Symbol(type)]: 1 -},Dirent Dirent { +},Dirent { name: '4.txt', parentPath: 'tmp/dir-entries-test/dir1', path: 'tmp/dir-entries-test/dir1', @@ -80,15 +84,15 @@ test2 = do dir <- A.opendir' outerTmpDir (opendirOptionsDefault { recursive = false }) read dir >>= \file -> liftEffect $ assertEqual { actual: show file - , expected: "(Just Dirent Dirent {\n name: 'dir1',\n parentPath: 'tmp/dir-entries-test',\n path: 'tmp/dir-entries-test',\n [Symbol(type)]: 2\n})" + , expected: "(Just Dirent {\n name: 'dir1',\n parentPath: 'tmp/dir-entries-test',\n path: 'tmp/dir-entries-test',\n [Symbol(type)]: 2\n})" } read dir >>= \file -> liftEffect $ assertEqual { actual: show file - , expected: "(Just Dirent Dirent {\n name: '1.txt',\n parentPath: 'tmp/dir-entries-test',\n path: 'tmp/dir-entries-test',\n [Symbol(type)]: 1\n})" + , expected: "(Just Dirent {\n name: '1.txt',\n parentPath: 'tmp/dir-entries-test',\n path: 'tmp/dir-entries-test',\n [Symbol(type)]: 1\n})" } read dir >>= \file -> liftEffect $ assertEqual { actual: show file - , expected: "(Just Dirent Dirent {\n name: '2.txt',\n parentPath: 'tmp/dir-entries-test',\n path: 'tmp/dir-entries-test',\n [Symbol(type)]: 1\n})" + , expected: "(Just Dirent {\n name: '2.txt',\n parentPath: 'tmp/dir-entries-test',\n path: 'tmp/dir-entries-test',\n [Symbol(type)]: 1\n})" } read dir >>= \file -> liftEffect $ assertEqual { actual: show file @@ -110,5 +114,5 @@ test2 = do main :: Effect Unit main = launchAff_ do prepare - -- test1 + test1 test2 From 43d512ba01e1e7d4384e4d6e3fae61083e0b2d82 Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Fri, 11 Oct 2024 16:40:46 +0700 Subject: [PATCH 19/32] feat: reproduce TypeError [ERR_INVALID_ARG_TYPE]: The "options.filter" property must be of type function. Received null --- test/Test/Node/FS/Sync.purs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/Test/Node/FS/Sync.purs b/test/Test/Node/FS/Sync.purs index 2897b67..ab27c19 100644 --- a/test/Test/Node/FS/Sync.purs +++ b/test/Test/Node/FS/Sync.purs @@ -192,6 +192,10 @@ main = do S.copyFile readableFixturePath destReadPath unlessM (S.exists destReadPath) do throw $ destReadPath <> " does not exist after copy" + let destReadPath2 = Path.concat [ tempDir, "readable2.txt" ] + S.cp readableFixturePath destReadPath2 + unlessM (S.exists destReadPath2) do + throw $ destReadPath2 <> " does not exist after copy" copyErr <- try $ S.copyFile' readableFixturePath destReadPath copyFile_EXCL case copyErr of From 1df3ebd0fb0278957df42544e8bdbfb1de6c9c77 Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Fri, 11 Oct 2024 17:07:46 +0700 Subject: [PATCH 20/32] fix: TypeError [ERR_INVALID_ARG_TYPE]: The "options.filter" property must be of type function. Received null --- spago.lock | 7 ++-- spago.yaml | 2 +- src/Node/FS/Internal/Undefinable.js | 12 ++++++ src/Node/FS/Internal/Undefinable.purs | 55 +++++++++++++++++++++++++++ src/Node/FS/Options.purs | 10 +++-- 5 files changed, 78 insertions(+), 8 deletions(-) create mode 100644 src/Node/FS/Internal/Undefinable.js create mode 100644 src/Node/FS/Internal/Undefinable.purs diff --git a/spago.lock b/spago.lock index 876a950..2c01805 100644 --- a/spago.lock +++ b/spago.lock @@ -143,7 +143,7 @@ }, "package_set": { "address": { - "registry": "60.3.0" + "registry": "60.5.0" }, "compiler": ">=0.15.15 <0.16.0", "content": { @@ -358,6 +358,7 @@ "js-promise-aff": "1.0.0", "js-timers": "6.1.0", "js-uri": "3.1.0", + "jsdom": "1.0.0", "json": "1.1.0", "json-codecs": "5.0.0", "justifill": "0.5.0", @@ -547,8 +548,8 @@ "soundfonts": "4.1.0", "sparse-matrices": "2.0.1", "sparse-polynomials": "3.0.1", - "spec": "8.0.0", - "spec-discovery": "8.3.0", + "spec": "8.1.0", + "spec-discovery": "8.4.0", "spec-mocha": "5.1.1", "spec-node": "0.0.2", "spec-quickcheck": "5.0.2", diff --git a/spago.yaml b/spago.yaml index 558e38b..f9c54c8 100644 --- a/spago.yaml +++ b/spago.yaml @@ -40,5 +40,5 @@ package: - node-event-emitter workspace: packageSet: - registry: 60.3.0 + registry: 60.5.0 extraPackages: {} diff --git a/src/Node/FS/Internal/Undefinable.js b/src/Node/FS/Internal/Undefinable.js new file mode 100644 index 0000000..622ebdc --- /dev/null +++ b/src/Node/FS/Internal/Undefinable.js @@ -0,0 +1,12 @@ +/* eslint-disable no-eq-null, eqeqeq */ + +const undefinedImpl = undefined; +export { undefinedImpl as undefined }; + +export function undefinable(a, r, f) { + return a === undefined ? r : f(a); +} + +export function notUndefined(x) { + return x; +} diff --git a/src/Node/FS/Internal/Undefinable.purs b/src/Node/FS/Internal/Undefinable.purs new file mode 100644 index 0000000..668ce79 --- /dev/null +++ b/src/Node/FS/Internal/Undefinable.purs @@ -0,0 +1,55 @@ +-- | This module defines types and functions for working with undefinable types +-- | using the FFI. + +module Node.FS.Internal.Undefinable + ( Undefinable + , undefined + , notUndefined + , toMaybe + , toUndefinable + ) where + +import Prelude + +import Data.Eq (class Eq1) +import Data.Function (on) +import Data.Function.Uncurried (Fn3, runFn3) +import Data.Maybe (Maybe(..), maybe) +import Data.Ord (class Ord1) + +foreign import data Undefinable :: Type -> Type + +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. +foreign import notUndefined :: forall a. a -> Undefinable a + +-- | Takes `Nothing` to `undefined`, and `Just a` to `a`. +toUndefinable :: forall a. Maybe a -> Undefinable a +toUndefinable = maybe undefined notUndefined + +-- | 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 + eq = eq `on` toMaybe + +instance eq1Undefinable :: Eq1 Undefinable where + eq1 = eq + +instance ordUndefinable :: Ord a => Ord (Undefinable a) where + compare = compare `on` toMaybe + +instance ord1Undefinable :: Ord1 Undefinable where + compare1 = compare diff --git a/src/Node/FS/Options.purs b/src/Node/FS/Options.purs index 251dbc8..cb53da4 100644 --- a/src/Node/FS/Options.purs +++ b/src/Node/FS/Options.purs @@ -1,6 +1,5 @@ module Node.FS.Options where -import Node.FS.Types (BufferLength, BufferOffset, EncodingString, FileMode, FilePosition) import Prelude import Data.Function.Uncurried (Fn2, mkFn2) @@ -13,7 +12,10 @@ import Node.Buffer (Buffer) import Node.Encoding (Encoding(..), encodingToNode) import Node.FS.Constants (FileFlags(..), fileFlagsToNode) import Node.FS.Dirent (Dirent, DirentNameTypeString) +import Node.FS.Internal.Undefinable (Undefinable) +import Node.FS.Internal.Undefinable as Undefinable import Node.FS.Perms (Perms, all, mkPerms, permsToString, read, write) +import Node.FS.Types (BufferLength, BufferOffset, EncodingString, FileMode, FilePosition) import Node.Path (FilePath) type RmdirOptions = { maxRetries :: Int, retryDelay :: Int } @@ -249,7 +251,8 @@ fdWriteOptionsToInternal { offset, length, position } = { offset, length: Nullab type CpOptionsInternal = { dereference :: Boolean , errorOnExist :: Boolean - , filter :: Nullable (Fn2 FilePath FilePath Boolean) + -- if null - will throw "TypeError [ERR_INVALID_ARG_TYPE]: The "options.filter" property must be of type function. Received null" + , filter :: Undefinable (Fn2 FilePath FilePath Boolean) , force :: Boolean , mode :: FileMode , preserveTimestamps :: Boolean @@ -286,7 +289,7 @@ cpOptionsToCpOptionsInternal opts = , errorOnExist: case opts.force of CpForce_TrueWithErrorOnExit -> true _ -> false - , filter: toNullable $ map mkFn2 (opts.filter) + , filter: Undefinable.toUndefinable $ map mkFn2 (opts.filter) , force: case opts.force of CpForce_False -> false _ -> true @@ -326,4 +329,3 @@ opendirOptionsDefault = { bufferSize: 32, recursive: false, encoding: UTF8 } opendirOptionsToInternal :: OpendirOptions -> OpendirOptionsInternal opendirOptionsToInternal { encoding, bufferSize, recursive } = { encoding: encodingToNode encoding, bufferSize, recursive } - From 84bba3884665a62eb21d837cac7ae5a222f0f3a2 Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Fri, 11 Oct 2024 17:22:35 +0700 Subject: [PATCH 21/32] fix: cp options -> should be CopyMode --- src/Node/FS/Options.purs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Node/FS/Options.purs b/src/Node/FS/Options.purs index cb53da4..4f88659 100644 --- a/src/Node/FS/Options.purs +++ b/src/Node/FS/Options.purs @@ -10,12 +10,12 @@ import Foreign (Foreign) import Foreign as Foreign import Node.Buffer (Buffer) import Node.Encoding (Encoding(..), encodingToNode) -import Node.FS.Constants (FileFlags(..), fileFlagsToNode) +import Node.FS.Constants (CopyMode, FileFlags(..), copyFile_NO_FLAGS, fileFlagsToNode) import Node.FS.Dirent (Dirent, DirentNameTypeString) import Node.FS.Internal.Undefinable (Undefinable) import Node.FS.Internal.Undefinable as Undefinable import Node.FS.Perms (Perms, all, mkPerms, permsToString, read, write) -import Node.FS.Types (BufferLength, BufferOffset, EncodingString, FileMode, FilePosition) +import Node.FS.Types (BufferLength, BufferOffset, EncodingString, FilePosition) import Node.Path (FilePath) type RmdirOptions = { maxRetries :: Int, retryDelay :: Int } @@ -254,7 +254,7 @@ type CpOptionsInternal = -- if null - will throw "TypeError [ERR_INVALID_ARG_TYPE]: The "options.filter" property must be of type function. Received null" , filter :: Undefinable (Fn2 FilePath FilePath Boolean) , force :: Boolean - , mode :: FileMode + , mode :: CopyMode , preserveTimestamps :: Boolean , recursive :: Boolean , verbatimSymlinks :: Boolean @@ -266,7 +266,7 @@ type CpOptions = { dereference :: Boolean -- Whether to dereference symlinks , filter :: Maybe (FilePath -> FilePath -> Boolean) , force :: CpForce - , mode :: FileMode -- Modifiers for copy operation + , mode :: CopyMode -- Modifiers for copy operation , preserveTimestamps :: Boolean -- Preserve timestamps from source , recursive :: Boolean -- Copy directories recursively , verbatimSymlinks :: Boolean -- Skip path resolution for symlinks @@ -277,7 +277,7 @@ cpOptionsDefault = { dereference: false , filter: Nothing , force: CpForce_TrueWithoutErrorOnExit - , mode: 0 + , mode: copyFile_NO_FLAGS , preserveTimestamps: false , recursive: false , verbatimSymlinks: false From 50972bad97d3ebbf60ba352d3d7700e3005f1b0b Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Fri, 11 Oct 2024 19:48:13 +0700 Subject: [PATCH 22/32] fix: cp -> split on cpFile and cpDir bc recursive is required for dirs --- src/Node/FS/Aff.purs | 28 +++++++++++----- src/Node/FS/Async.purs | 28 +++++++++++----- src/Node/FS/Options.purs | 65 +++++++++++++++++++++++++++---------- src/Node/FS/Sync.purs | 28 +++++++++++----- test/Test/Node/FS/Sync.purs | 32 ++++++++++++++---- 5 files changed, 134 insertions(+), 47 deletions(-) diff --git a/src/Node/FS/Aff.purs b/src/Node/FS/Aff.purs index af722e3..3f355d8 100644 --- a/src/Node/FS/Aff.purs +++ b/src/Node/FS/Aff.purs @@ -53,8 +53,10 @@ module Node.FS.Aff , fdWriteString , fdAppend , fdClose - , cp - , cp' + , cpFile + , cpFile' + , cpDir + , cpDir' , fchmod , fchown , fdatasync @@ -91,7 +93,7 @@ import Node.Buffer (Buffer) import Node.Encoding (Encoding) import Node.FS.Types (BufferLength, BufferOffset, ByteCount, FileDescriptor, FileMode, FilePosition, SymlinkType) import Node.FS.Internal.AffUtils (toAff1, toAff2, toAff3, toAff4, toAff5) -import Node.FS.Options (AppendFileBufferOptions, CpOptions, FdReadOptions, FdWriteOptions, GlobDirentOptions, GlobFilePathOptions, MkdirOptions, OpendirOptions, ReadFileBufferOptions, ReadFileStringOptions, ReaddirBufferOptions, ReaddirDirentBufferOptions, ReaddirDirentOptions, ReaddirFilePathOptions, RealpathOptions, RmOptions, RmdirOptions, WriteFileBufferOptions, WriteFileStringOptions) +import Node.FS.Options (AppendFileBufferOptions, CpDirOptions, CpFileOptions, FdReadOptions, FdWriteOptions, GlobDirentOptions, GlobFilePathOptions, MkdirOptions, OpendirOptions, ReadFileBufferOptions, ReadFileStringOptions, ReaddirBufferOptions, ReaddirDirentBufferOptions, ReaddirDirentOptions, ReaddirFilePathOptions, RealpathOptions, RmOptions, RmdirOptions, WriteFileBufferOptions, WriteFileStringOptions) import Node.FS.Constants (AccessMode, CopyMode, FileFlags) import Node.FS.Async as A import Node.FS.Dir (Dir) @@ -406,13 +408,23 @@ fdAppend = toAff2 A.fdAppend fdClose :: FileDescriptor -> Aff Unit fdClose = toAff1 A.fdClose --- | Copy a file asynchronously. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fspromises_copyfile_src_dest_mode) +-- | Copy a file asynchronously using a `cp` command. +-- | See the [Node Documentation](https://nodejs.org/api/fs.html#fscpsrc-dest-options-callback) -- | for details. -cp :: FilePath -> FilePath -> Aff Unit -cp = toAff2 A.cp +cpFile :: FilePath -> FilePath -> Aff Unit +cpFile = toAff2 A.cpFile -cp' :: FilePath -> FilePath -> CpOptions -> Aff Unit -cp' = toAff3 A.cp' +cpFile' :: FilePath -> FilePath -> CpFileOptions -> Aff Unit +cpFile' = toAff3 A.cpFile' + +-- | Copy a directory asynchronously using a `cp` command with option `recursive = true`. +-- | See the [Node Documentation](https://nodejs.org/api/fs.html#fscpsrc-dest-options-callback) +-- | for details. +cpDir :: FilePath -> FilePath -> Aff Unit +cpDir = toAff2 A.cpDir + +cpDir' :: FilePath -> FilePath -> CpDirOptions -> Aff Unit +cpDir' = toAff3 A.cpDir' -- | Change permissions on a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fchmod_fd_mode_callback) -- | for details. diff --git a/src/Node/FS/Async.purs b/src/Node/FS/Async.purs index 0f32438..bbb4ba9 100644 --- a/src/Node/FS/Async.purs +++ b/src/Node/FS/Async.purs @@ -53,8 +53,10 @@ module Node.FS.Async , fdWriteString , fdAppend , fdClose - , cp - , cp' + , cpFile + , cpFile' + , cpDir + , cpDir' , fchmod , fchown , fdatasync @@ -96,7 +98,7 @@ import Node.FS.Constants (AccessMode, CopyMode, FileFlags, defaultAccessMode, de import Node.FS.Dir (Dir) import Node.FS.Dirent (Dirent, DirentNameTypeBuffer, DirentNameTypeString) import Node.FS.Internal.Utils (Callback0, Callback1, JSCallback0, JSCallback1, JSCallback2, datetimeToUnixEpochTimeInSeconds, handleCallback0, handleCallback1, handleCallback1Tuple) -import Node.FS.Options (AppendFileBufferOptions, AppendFileOptionsInternal, AppendFileStringOptions, CpOptions, CpOptionsInternal, FdReadOptions, FdReadOptionsInternal, FdWriteOptions, FdWriteOptionsInternal, GlobDirentOptions, GlobFilePathOptions, GlobOptionsInternal, MkdirOptions, MkdirOptionsInternal, OpendirOptions, OpendirOptionsInternal, ReadFileBufferOptions, ReadFileOptionsInternal, ReadFileStringOptions, ReaddirBufferOptions, ReaddirDirentBufferOptions, ReaddirDirentOptions, ReaddirFilePathOptions, ReaddirOptionsInternal, RealpathOptions, RealpathOptionsInternal, RmOptions, RmdirOptions, WriteFileBufferOptions, WriteFileOptionsInternal, WriteFileStringOptions, appendFileBufferOptionsDefault, appendFileBufferOptionsToInternal, appendFileStringOptionsDefault, appendFileStringOptionsToInternal, cpOptionsDefault, cpOptionsToCpOptionsInternal, fdReadOptionsToInternal, fdWriteOptionsToInternal, globDirentOptionsDefault, globDirentOptionsToInternal, globFilePathOptionsDefault, globFilePathOptionsToInternal, mkdirOptionsDefault, mkdirOptionsToInternal, opendirOptionsDefault, opendirOptionsToInternal, readFileBufferOptionsDefault, readFileBufferOptionsToInternal, readFileStringOptionsDefault, readFileStringOptionsToInternal, readdirBufferOptionsDefault, readdirBufferOptionsToInternal, readdirDirentBufferOptionsDefault, readdirDirentBufferOptionsToInternal, readdirDirentOptionsDefault, readdirDirentOptionsToInternal, readdirFilePathOptionsDefault, readdirFilePathOptionsToInternal, realpathOptionsDefault, realpathOptionsToInternal, rmOptionsDefault, rmdirOptionsDefault, writeFileBufferOptionsDefault, writeFileBufferOptionsToInternal, writeFileStringOptionsDefault, writeFileStringOptionsToInternal) +import Node.FS.Options (AppendFileBufferOptions, AppendFileOptionsInternal, AppendFileStringOptions, CpDirOptions, CpFileOptions, CpOptionsInternal, FdReadOptions, FdReadOptionsInternal, FdWriteOptions, FdWriteOptionsInternal, GlobDirentOptions, GlobFilePathOptions, GlobOptionsInternal, MkdirOptions, MkdirOptionsInternal, OpendirOptions, OpendirOptionsInternal, ReadFileBufferOptions, ReadFileOptionsInternal, ReadFileStringOptions, ReaddirBufferOptions, ReaddirDirentBufferOptions, ReaddirDirentOptions, ReaddirFilePathOptions, ReaddirOptionsInternal, RealpathOptions, RealpathOptionsInternal, RmOptions, RmdirOptions, WriteFileBufferOptions, WriteFileOptionsInternal, WriteFileStringOptions, appendFileBufferOptionsDefault, appendFileBufferOptionsToInternal, appendFileStringOptionsDefault, appendFileStringOptionsToInternal, cpDirOptionsDefault, cpDirOptionsToCpOptionsInternal, cpFileOptionsDefault, cpFileOptionsToCpOptionsInternal, fdReadOptionsToInternal, fdWriteOptionsToInternal, globDirentOptionsDefault, globDirentOptionsToInternal, globFilePathOptionsDefault, globFilePathOptionsToInternal, mkdirOptionsDefault, mkdirOptionsToInternal, opendirOptionsDefault, opendirOptionsToInternal, readFileBufferOptionsDefault, readFileBufferOptionsToInternal, readFileStringOptionsDefault, readFileStringOptionsToInternal, readdirBufferOptionsDefault, readdirBufferOptionsToInternal, readdirDirentBufferOptionsDefault, readdirDirentBufferOptionsToInternal, readdirDirentOptionsDefault, readdirDirentOptionsToInternal, readdirFilePathOptionsDefault, readdirFilePathOptionsToInternal, realpathOptionsDefault, realpathOptionsToInternal, rmOptionsDefault, rmdirOptionsDefault, writeFileBufferOptionsDefault, writeFileBufferOptionsToInternal, writeFileStringOptionsDefault, writeFileStringOptionsToInternal) import Node.FS.Perms (Perms, permsToString) import Node.FS.Stats (Stats) import Node.FS.Types (EncodingString) @@ -591,13 +593,23 @@ fdClose -> Effect Unit fdClose fd cb = runEffectFn2 closeImpl fd (handleCallback0 cb) --- | Copy a file asynchronously. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fspromises_copyfile_src_dest_mode) +-- | Copy a file asynchronously using a `cp` command. +-- | See the [Node Documentation](https://nodejs.org/api/fs.html#fscpsrc-dest-options-callback) -- | for details. -cp :: FilePath -> FilePath -> Callback0 -> Effect Unit -cp src dest = cp' src dest cpOptionsDefault +cpFile :: FilePath -> FilePath -> Callback0 -> Effect Unit +cpFile src dest = cpFile' src dest cpFileOptionsDefault -cp' :: FilePath -> FilePath -> CpOptions -> Callback0 -> Effect Unit -cp' src dest opts cb = runEffectFn4 cpImpl src dest (cpOptionsToCpOptionsInternal opts) (handleCallback0 cb) +cpFile' :: FilePath -> FilePath -> CpFileOptions -> Callback0 -> Effect Unit +cpFile' src dest opts cb = runEffectFn4 cpImpl src dest (cpFileOptionsToCpOptionsInternal opts) (handleCallback0 cb) + +-- | Copy a directory asynchronously using a `cp` command with option `recursive = true`. +-- | See the [Node Documentation](https://nodejs.org/api/fs.html#fscpsrc-dest-options-callback) +-- | for details. +cpDir :: FilePath -> FilePath -> Callback0 -> Effect Unit +cpDir src dest = cpDir' src dest cpDirOptionsDefault + +cpDir' :: FilePath -> FilePath -> CpDirOptions -> Callback0 -> Effect Unit +cpDir' src dest opts cb = runEffectFn4 cpImpl src dest (cpDirOptionsToCpOptionsInternal opts) (handleCallback0 cb) -- | Change permissions on a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fchmod_fd_mode_callback) -- | for details. diff --git a/src/Node/FS/Options.purs b/src/Node/FS/Options.purs index 4f88659..8b6864f 100644 --- a/src/Node/FS/Options.purs +++ b/src/Node/FS/Options.purs @@ -250,41 +250,56 @@ fdWriteOptionsToInternal { offset, length, position } = { offset, length: Nullab type CpOptionsInternal = { dereference :: Boolean - , errorOnExist :: Boolean + , errorOnExist :: Boolean -- Whether to dereference symlinks -- if null - will throw "TypeError [ERR_INVALID_ARG_TYPE]: The "options.filter" property must be of type function. Received null" , filter :: Undefinable (Fn2 FilePath FilePath Boolean) , force :: Boolean - , mode :: CopyMode - , preserveTimestamps :: Boolean - , recursive :: Boolean - , verbatimSymlinks :: Boolean + , mode :: CopyMode -- Modifiers for copy operation + , preserveTimestamps :: Boolean -- Preserve timestamps from source + , recursive :: Boolean -- Copy directories recursively + , verbatimSymlinks :: Boolean -- Skip path resolution for symlinks } data CpForce = CpForce_False | CpForce_TrueWithoutErrorOnExit | CpForce_TrueWithErrorOnExit -type CpOptions = - { dereference :: Boolean -- Whether to dereference symlinks +type CpDirOptions = + { dereference :: Boolean , filter :: Maybe (FilePath -> FilePath -> Boolean) , force :: CpForce - , mode :: CopyMode -- Modifiers for copy operation - , preserveTimestamps :: Boolean -- Preserve timestamps from source - , recursive :: Boolean -- Copy directories recursively - , verbatimSymlinks :: Boolean -- Skip path resolution for symlinks + , mode :: CopyMode + , preserveTimestamps :: Boolean + , verbatimSymlinks :: Boolean + } + +type CpFileOptions = + { dereference :: Boolean + , force :: CpForce + , mode :: CopyMode + , preserveTimestamps :: Boolean + , verbatimSymlinks :: Boolean } -cpOptionsDefault :: CpOptions -cpOptionsDefault = +cpDirOptionsDefault :: CpDirOptions +cpDirOptionsDefault = { dereference: false , filter: Nothing , force: CpForce_TrueWithoutErrorOnExit , mode: copyFile_NO_FLAGS , preserveTimestamps: false - , recursive: false , verbatimSymlinks: false } -cpOptionsToCpOptionsInternal :: CpOptions -> CpOptionsInternal -cpOptionsToCpOptionsInternal opts = +cpFileOptionsDefault :: CpFileOptions +cpFileOptionsDefault = + { dereference: false + , force: CpForce_TrueWithoutErrorOnExit + , mode: copyFile_NO_FLAGS + , preserveTimestamps: false + , verbatimSymlinks: false + } + +cpDirOptionsToCpOptionsInternal :: CpDirOptions -> CpOptionsInternal +cpDirOptionsToCpOptionsInternal opts = { dereference: opts.dereference , errorOnExist: case opts.force of CpForce_TrueWithErrorOnExit -> true @@ -295,7 +310,23 @@ cpOptionsToCpOptionsInternal opts = _ -> true , mode: opts.mode , preserveTimestamps: opts.preserveTimestamps - , recursive: opts.recursive + , recursive: true + , verbatimSymlinks: opts.verbatimSymlinks + } + +cpFileOptionsToCpOptionsInternal :: CpFileOptions -> CpOptionsInternal +cpFileOptionsToCpOptionsInternal opts = + { dereference: opts.dereference + , errorOnExist: case opts.force of + CpForce_TrueWithErrorOnExit -> true + _ -> false + , filter: Undefinable.undefined + , force: case opts.force of + CpForce_False -> false + _ -> true + , mode: opts.mode + , preserveTimestamps: opts.preserveTimestamps + , recursive: false , verbatimSymlinks: opts.verbatimSymlinks } diff --git a/src/Node/FS/Sync.purs b/src/Node/FS/Sync.purs index 0a8067f..442e3e3 100644 --- a/src/Node/FS/Sync.purs +++ b/src/Node/FS/Sync.purs @@ -54,8 +54,10 @@ module Node.FS.Sync , fdWriteString , fdAppend , fdClose - , cp - , cp' + , cpFile + , cpFile' + , cpDir + , cpDir' , fchmod , fchown , fdatasync @@ -96,7 +98,7 @@ import Node.FS.Constants (AccessMode, CopyMode, FileFlags, defaultAccessMode, de import Node.FS.Dir (Dir) import Node.FS.Dirent (Dirent, DirentNameTypeBuffer, DirentNameTypeString) import Node.FS.Internal.Utils (datetimeToUnixEpochTimeInSeconds) -import Node.FS.Options (AppendFileBufferOptions, AppendFileOptionsInternal, AppendFileStringOptions, CpOptions, CpOptionsInternal, FdReadOptions, FdReadOptionsInternal, FdWriteOptions, FdWriteOptionsInternal, GlobDirentOptions, GlobFilePathOptions, GlobOptionsInternal, MkdirOptions, MkdirOptionsInternal, OpendirOptions, OpendirOptionsInternal, ReadFileBufferOptions, ReadFileOptionsInternal, ReadFileStringOptions, ReaddirBufferOptions, ReaddirDirentBufferOptions, ReaddirDirentOptions, ReaddirFilePathOptions, ReaddirOptionsInternal, RealpathOptions, RealpathOptionsInternal, RmOptions, RmdirOptions, WriteFileBufferOptions, WriteFileOptionsInternal, WriteFileStringOptions, appendFileBufferOptionsDefault, appendFileBufferOptionsToInternal, appendFileStringOptionsDefault, appendFileStringOptionsToInternal, cpOptionsDefault, cpOptionsToCpOptionsInternal, fdReadOptionsToInternal, fdWriteOptionsToInternal, globDirentOptionsDefault, globDirentOptionsToInternal, globFilePathOptionsDefault, globFilePathOptionsToInternal, mkdirOptionsDefault, mkdirOptionsToInternal, opendirOptionsDefault, opendirOptionsToInternal, readFileBufferOptionsDefault, readFileBufferOptionsToInternal, readFileStringOptionsDefault, readFileStringOptionsToInternal, readdirBufferOptionsDefault, readdirBufferOptionsToInternal, readdirDirentBufferOptionsDefault, readdirDirentBufferOptionsToInternal, readdirDirentOptionsDefault, readdirDirentOptionsToInternal, readdirFilePathOptionsDefault, readdirFilePathOptionsToInternal, realpathOptionsDefault, realpathOptionsToInternal, rmOptionsDefault, rmdirOptionsDefault, writeFileBufferOptionsDefault, writeFileBufferOptionsToInternal, writeFileStringOptionsDefault, writeFileStringOptionsToInternal) +import Node.FS.Options (AppendFileBufferOptions, AppendFileOptionsInternal, AppendFileStringOptions, CpDirOptions, CpFileOptions, CpOptionsInternal, FdReadOptions, FdReadOptionsInternal, FdWriteOptions, FdWriteOptionsInternal, GlobDirentOptions, GlobFilePathOptions, GlobOptionsInternal, MkdirOptions, MkdirOptionsInternal, OpendirOptions, OpendirOptionsInternal, ReadFileBufferOptions, ReadFileOptionsInternal, ReadFileStringOptions, ReaddirBufferOptions, ReaddirDirentBufferOptions, ReaddirDirentOptions, ReaddirFilePathOptions, ReaddirOptionsInternal, RealpathOptions, RealpathOptionsInternal, RmOptions, RmdirOptions, WriteFileBufferOptions, WriteFileOptionsInternal, WriteFileStringOptions, appendFileBufferOptionsDefault, appendFileBufferOptionsToInternal, appendFileStringOptionsDefault, appendFileStringOptionsToInternal, cpDirOptionsDefault, cpDirOptionsToCpOptionsInternal, cpFileOptionsDefault, cpFileOptionsToCpOptionsInternal, fdReadOptionsToInternal, fdWriteOptionsToInternal, globDirentOptionsDefault, globDirentOptionsToInternal, globFilePathOptionsDefault, globFilePathOptionsToInternal, mkdirOptionsDefault, mkdirOptionsToInternal, opendirOptionsDefault, opendirOptionsToInternal, readFileBufferOptionsDefault, readFileBufferOptionsToInternal, readFileStringOptionsDefault, readFileStringOptionsToInternal, readdirBufferOptionsDefault, readdirBufferOptionsToInternal, readdirDirentBufferOptionsDefault, readdirDirentBufferOptionsToInternal, readdirDirentOptionsDefault, readdirDirentOptionsToInternal, readdirFilePathOptionsDefault, readdirFilePathOptionsToInternal, realpathOptionsDefault, realpathOptionsToInternal, rmOptionsDefault, rmdirOptionsDefault, writeFileBufferOptionsDefault, writeFileBufferOptionsToInternal, writeFileStringOptionsDefault, writeFileStringOptionsToInternal) import Node.FS.Perms (Perms, permsToString) import Node.FS.Stats (Stats) import Node.FS.Types (BufferLength, BufferOffset, ByteCount, FileDescriptor, FileMode, FilePosition, SymlinkType, EncodingString, symlinkTypeToNode) @@ -537,13 +539,23 @@ fdAppend fd buff = do fdClose :: FileDescriptor -> Effect Unit fdClose fd = runEffectFn1 closeSyncImpl fd --- | Copy a file synchronously. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fspromises_copyfile_src_dest_mode) +-- | Copy a file synchronously using a `cp` command. +-- | See the [Node Documentation](https://nodejs.org/api/fs.html#fscpsyncsrc-dest-options) -- | for details. -cp :: FilePath -> FilePath -> Effect Unit -cp src dest = cp' src dest cpOptionsDefault +cpFile :: FilePath -> FilePath -> Effect Unit +cpFile src dest = cpFile' src dest cpFileOptionsDefault -cp' :: FilePath -> FilePath -> CpOptions -> Effect Unit -cp' src dest opts = runEffectFn3 cpSyncImpl src dest (cpOptionsToCpOptionsInternal opts) +cpFile' :: FilePath -> FilePath -> CpFileOptions -> Effect Unit +cpFile' src dest opts = runEffectFn3 cpSyncImpl src dest (cpFileOptionsToCpOptionsInternal opts) + +-- | Copy a directory synchronously using a `cp` command with option `recursive = true`. +-- | See the [Node Documentation](https://nodejs.org/api/fs.html#fscpsyncsrc-dest-options) +-- | for details. +cpDir :: FilePath -> FilePath -> Effect Unit +cpDir src dest = cpDir' src dest cpDirOptionsDefault + +cpDir' :: FilePath -> FilePath -> CpDirOptions -> Effect Unit +cpDir' src dest opts = runEffectFn3 cpSyncImpl src dest (cpDirOptionsToCpOptionsInternal opts) -- | Change permissions on a file descriptor. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_fchmod_fd_mode_callback) -- | for details. diff --git a/test/Test/Node/FS/Sync.purs b/test/Test/Node/FS/Sync.purs index ab27c19..c53f8a6 100644 --- a/test/Test/Node/FS/Sync.purs +++ b/test/Test/Node/FS/Sync.purs @@ -8,18 +8,20 @@ import Data.Traversable (for_, traverse) import Effect (Effect) import Effect.Console (log) import Effect.Exception (Error, catchException, error, message, throw, throwException, try) +import Effect.Exception as Error import Node.Buffer as Buffer import Node.Encoding (Encoding(..)) import Node.FS (FileFlags(..), SymlinkType(..)) import Node.FS.Async as A import Node.FS.Constants (copyFile_EXCL, r_OK, w_OK) +import Node.FS.Options (rmOptionsDefault) import Node.FS.Perms (mkPerms, permsAll) import Node.FS.Perms as Perms import Node.FS.Stats (statusChangedTime, accessedTime, modifiedTime, isSymbolicLink, isSocket, isFIFO, isCharacterDevice, isBlockDevice, isDirectory, isFile) -import Node.FS.Options (rmOptionsDefault) import Node.FS.Sync (chmod) import Node.FS.Sync as S import Node.Path as Path +import Test.Assert (assertEqual') import Unsafe.Coerce (unsafeCoerce) -- Cheat to allow `main` to type check. See also issue #5 in @@ -192,12 +194,30 @@ main = do S.copyFile readableFixturePath destReadPath unlessM (S.exists destReadPath) do throw $ destReadPath <> " does not exist after copy" - let destReadPath2 = Path.concat [ tempDir, "readable2.txt" ] - S.cp readableFixturePath destReadPath2 - unlessM (S.exists destReadPath2) do - throw $ destReadPath2 <> " does not exist after copy" - copyErr <- try $ S.copyFile' readableFixturePath destReadPath copyFile_EXCL case copyErr of Left _ -> pure unit Right _ -> throw $ destReadPath <> " already exists, but copying a file to there did not throw an error with COPYFILE_EXCL option" + + log "copy file using cp: ok" + let destReadPath2 = Path.concat [ tempDir, "readable2.txt" ] + S.cpFile readableFixturePath destReadPath2 + unlessM (S.exists destReadPath2) do + throw $ destReadPath2 <> " does not exist after copy" + + log "copy dir using cp: if copy using cpDir - ok" + S.cpDir (tempDir <> "/") (tempDir <> "2") + + log "copy dir using cp: if copy using cpDir - error - ERR_FS_EISDIR \"Recursive option not enabled\"" + let + cpFileShouldThrow_from = tempDir <> "/" + cpFileShouldThrow_to = tempDir <> "3" + cpDirError <- try $ S.cpFile cpFileShouldThrow_from cpFileShouldThrow_to + case cpDirError of + Left cpDirError' -> do + let + cpDirError'_message = Error.message cpDirError' + cpDirError'_code = (unsafeCoerce cpDirError' :: { code :: String }).code + assertEqual' "cpDirError'_message" { actual: cpDirError'_message, expected: "Recursive option not enabled, cannot copy a directory: " <> cpFileShouldThrow_from } + assertEqual' "cpDirError'_code" { actual: cpDirError'_code, expected: "ERR_FS_EISDIR" } + Right _ -> throw $ "cpFileShouldThrow: should have failed " <> show { cpFileShouldThrow_from, cpFileShouldThrow_to } From 3e2e675400aba7377e39782bf88d9b50f1ec647f Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Sun, 13 Oct 2024 12:16:44 +0700 Subject: [PATCH 23/32] feat: DirentType and getType -> add --- src/Node/FS/Dirent.js | 2 ++ src/Node/FS/Dirent.purs | 25 +++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/Node/FS/Dirent.js b/src/Node/FS/Dirent.js index d8799eb..1314aa9 100644 --- a/src/Node/FS/Dirent.js +++ b/src/Node/FS/Dirent.js @@ -1,5 +1,7 @@ export { inspect as showDirentObj } from "util"; +// Implemented here +// https://github.com/nodejs/node/blob/d881fcba86f72ff506eea53a5eca9a0ab2e4a02f/lib/internal/fs/utils.js#L160 export const isBlockDevice = dirent => dirent.isBlockDevice(); export const isCharacterDevice = dirent => dirent.isCharacterDevice(); export const isDirectory = dirent => dirent.isDirectory(); diff --git a/src/Node/FS/Dirent.purs b/src/Node/FS/Dirent.purs index c544f17..db8acaa 100644 --- a/src/Node/FS/Dirent.purs +++ b/src/Node/FS/Dirent.purs @@ -4,6 +4,7 @@ import Prelude import Node.Buffer (Buffer) import Node.Path (FilePath) +import Partial.Unsafe (unsafeCrashWith) import Unsafe.Coerce (unsafeCoerce) data DirentNameType @@ -34,6 +35,26 @@ foreign import isSocket :: forall direntnametype. Dirent direntnametype -> Boole -- | Check if the Dirent object describes a symbolic link. foreign import isSymbolicLink :: forall direntnametype. Dirent direntnametype -> Boolean +data DirentType + = DirentType_BlockDevice + | DirentType_CharacterDevice + | DirentType_Directory + | DirentType_FIFO + | DirentType_File + | DirentType_Socket + | DirentType_SymbolicLink + +getType :: forall direntnametype. Dirent direntnametype -> DirentType +getType dirent = + if isBlockDevice dirent then DirentType_BlockDevice + else if isCharacterDevice dirent then DirentType_CharacterDevice + else if isDirectory dirent then DirentType_Directory + else if isFIFO dirent then DirentType_FIFO + else if isFile dirent then DirentType_File + else if isSocket dirent then DirentType_Socket + else if isSymbolicLink dirent then DirentType_SymbolicLink + else unsafeCrashWith "Impossible: unknown Dirent type" + foreign import nameImpl :: forall direntnametype nametype. Dirent direntnametype -> nametype class IsDirentNameForDirent direntnametype stringOrBuffer | direntnametype -> stringOrBuffer where @@ -42,10 +63,10 @@ class IsDirentNameForDirent direntnametype stringOrBuffer | direntnametype -> st instance IsDirentNameForDirent DirentNameTypeString String where name :: Dirent DirentNameTypeString -> String - name = unsafeCoerce nameImpl + name = nameImpl else instance IsDirentNameForDirent DirentNameTypeBuffer Buffer where name :: Dirent DirentNameTypeBuffer -> Buffer - name = unsafeCoerce nameImpl + name = nameImpl -- | Get the parent directory path of the file this Dirent object refers to. -- | Added in: v21.4.0, v20.12.0, v18.20.0 From fcfddf95e463b2d39c7c297c80016098d933419a Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Sun, 13 Oct 2024 12:17:27 +0700 Subject: [PATCH 24/32] feat: rename using sd -F 'DirentNameType' 'DirentName' $(fd --type file) --- src/Node/FS/Aff.purs | 18 +++++++++--------- src/Node/FS/Aff/Dir.purs | 10 +++++----- src/Node/FS/Async.purs | 14 +++++++------- src/Node/FS/Dir.purs | 10 +++++----- src/Node/FS/Dirent.purs | 16 ++++++++-------- src/Node/FS/Options.purs | 6 +++--- src/Node/FS/Sync.purs | 14 +++++++------- test/Test/Node/FS/OpendirAndDir.purs | 6 +++--- 8 files changed, 47 insertions(+), 47 deletions(-) diff --git a/src/Node/FS/Aff.purs b/src/Node/FS/Aff.purs index 3f355d8..d853128 100644 --- a/src/Node/FS/Aff.purs +++ b/src/Node/FS/Aff.purs @@ -97,7 +97,7 @@ import Node.FS.Options (AppendFileBufferOptions, CpDirOptions, CpFileOptions, Fd import Node.FS.Constants (AccessMode, CopyMode, FileFlags) import Node.FS.Async as A import Node.FS.Dir (Dir) -import Node.FS.Dirent (Dirent, DirentNameTypeBuffer, DirentNameTypeString) +import Node.FS.Dirent (Dirent, DirentNameBuffer, DirentNameString) import Node.FS.Perms (Perms) import Node.FS.Stats (Stats) import Node.Path (FilePath) @@ -258,25 +258,25 @@ readdirBuffer = toAff1 A.readdirBuffer readdirBuffer' :: FilePath -> ReaddirBufferOptions -> Aff (Array Buffer) readdirBuffer' = toAff2 A.readdirBuffer' --- | Reads the contents of a directory and returns an Aff (Array (Dirent DirentNameTypeString)). -readdirDirent :: FilePath -> Aff (Array (Dirent DirentNameTypeString)) +-- | Reads the contents of a directory and returns an Aff (Array (Dirent DirentNameString)). +readdirDirent :: FilePath -> Aff (Array (Dirent DirentNameString)) readdirDirent = toAff1 A.readdirDirent --- | Reads the contents of a directory with options and returns Aff (Array (Dirent DirentNameTypeString)). -readdirDirent' :: FilePath -> ReaddirDirentOptions -> Aff (Array (Dirent DirentNameTypeString)) +-- | Reads the contents of a directory with options and returns Aff (Array (Dirent DirentNameString)). +readdirDirent' :: FilePath -> ReaddirDirentOptions -> Aff (Array (Dirent DirentNameString)) readdirDirent' = toAff2 A.readdirDirent' -- | Reads the contents of a directory. readdirDirentBuffer :: FilePath - -> Aff (Array (Dirent DirentNameTypeBuffer)) + -> Aff (Array (Dirent DirentNameBuffer)) readdirDirentBuffer = toAff1 A.readdirDirentBuffer -- | Reads the contents of a directory. readdirDirentBuffer' :: FilePath -> ReaddirDirentBufferOptions - -> Aff (Array (Dirent DirentNameTypeBuffer)) + -> Aff (Array (Dirent DirentNameBuffer)) readdirDirentBuffer' = toAff2 A.readdirDirentBuffer' -- | @@ -469,10 +469,10 @@ glob = toAff1 A.glob glob' :: Array FilePath -> GlobFilePathOptions -> Aff (Array FilePath) glob' = toAff2 A.glob' -globDirent :: Array FilePath -> Aff (Array (Dirent DirentNameTypeString)) +globDirent :: Array FilePath -> Aff (Array (Dirent DirentNameString)) globDirent = toAff1 A.globDirent -globDirent' :: Array FilePath -> GlobDirentOptions -> Aff (Array (Dirent DirentNameTypeString)) +globDirent' :: Array FilePath -> GlobDirentOptions -> Aff (Array (Dirent DirentNameString)) globDirent' = toAff2 A.globDirent' -- | Change permissions on a symbolic link. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_lchmod_path_mode_callback) diff --git a/src/Node/FS/Aff/Dir.purs b/src/Node/FS/Aff/Dir.purs index c3abcc7..ff5f78e 100644 --- a/src/Node/FS/Aff/Dir.purs +++ b/src/Node/FS/Aff/Dir.purs @@ -18,10 +18,10 @@ import Effect.Ref (Ref) import Effect.Ref as Ref import Node.FS.Dir (Dir) import Node.FS.Dir as Dir -import Node.FS.Dirent (Dirent, DirentNameTypeString) +import Node.FS.Dirent (Dirent, DirentNameString) import Node.FS.Internal.AffUtils (toAff1) -read :: Dir -> Aff (Maybe (Dirent DirentNameTypeString)) +read :: Dir -> Aff (Maybe (Dirent DirentNameString)) read = toAff1 Dir.read close :: Dir -> Aff Unit @@ -29,11 +29,11 @@ close dir = makeAff \k -> do Dir.close dir k pure nonCanceler -entries :: Dir -> Aff (Array (Dirent DirentNameTypeString)) +entries :: Dir -> Aff (Array (Dirent DirentNameString)) entries dir = do direntArrayRef <- liftEffect $ Ref.new [] let - handleDirent :: Dirent DirentNameTypeString -> Effect Unit + handleDirent :: Dirent DirentNameString -> Effect Unit handleDirent dirent = Ref.modify_ (flip Array.snoc dirent) direntArrayRef entriesIterate dir handleDirent liftEffect $ Ref.read direntArrayRef @@ -47,7 +47,7 @@ entries dir = do -- | -- | Possible errors: -- | - if dir is closed already - `read` and `close` will throw "Directory handle was closed" -entriesIterate :: Dir -> ((Dirent DirentNameTypeString) -> Effect Unit) -> Aff Unit +entriesIterate :: Dir -> ((Dirent DirentNameString) -> Effect Unit) -> Aff Unit entriesIterate dir handleDirent = finally (close dir) $ makeAff \(k :: Either Error Unit -> Effect Unit) -> do stopRef <- Ref.new false go k stopRef diff --git a/src/Node/FS/Async.purs b/src/Node/FS/Async.purs index bbb4ba9..5cd2838 100644 --- a/src/Node/FS/Async.purs +++ b/src/Node/FS/Async.purs @@ -96,7 +96,7 @@ import Node.Encoding (Encoding(..), encodingToNode) import Node.FS (FileDescriptor, ByteCount, FilePosition, BufferLength, BufferOffset, FileMode, SymlinkType, symlinkTypeToNode) import Node.FS.Constants (AccessMode, CopyMode, FileFlags, defaultAccessMode, defaultCopyMode, fileFlagsToNode) import Node.FS.Dir (Dir) -import Node.FS.Dirent (Dirent, DirentNameTypeBuffer, DirentNameTypeString) +import Node.FS.Dirent (Dirent, DirentNameBuffer, DirentNameString) import Node.FS.Internal.Utils (Callback0, Callback1, JSCallback0, JSCallback1, JSCallback2, datetimeToUnixEpochTimeInSeconds, handleCallback0, handleCallback1, handleCallback1Tuple) import Node.FS.Options (AppendFileBufferOptions, AppendFileOptionsInternal, AppendFileStringOptions, CpDirOptions, CpFileOptions, CpOptionsInternal, FdReadOptions, FdReadOptionsInternal, FdWriteOptions, FdWriteOptionsInternal, GlobDirentOptions, GlobFilePathOptions, GlobOptionsInternal, MkdirOptions, MkdirOptionsInternal, OpendirOptions, OpendirOptionsInternal, ReadFileBufferOptions, ReadFileOptionsInternal, ReadFileStringOptions, ReaddirBufferOptions, ReaddirDirentBufferOptions, ReaddirDirentOptions, ReaddirFilePathOptions, ReaddirOptionsInternal, RealpathOptions, RealpathOptionsInternal, RmOptions, RmdirOptions, WriteFileBufferOptions, WriteFileOptionsInternal, WriteFileStringOptions, appendFileBufferOptionsDefault, appendFileBufferOptionsToInternal, appendFileStringOptionsDefault, appendFileStringOptionsToInternal, cpDirOptionsDefault, cpDirOptionsToCpOptionsInternal, cpFileOptionsDefault, cpFileOptionsToCpOptionsInternal, fdReadOptionsToInternal, fdWriteOptionsToInternal, globDirentOptionsDefault, globDirentOptionsToInternal, globFilePathOptionsDefault, globFilePathOptionsToInternal, mkdirOptionsDefault, mkdirOptionsToInternal, opendirOptionsDefault, opendirOptionsToInternal, readFileBufferOptionsDefault, readFileBufferOptionsToInternal, readFileStringOptionsDefault, readFileStringOptionsToInternal, readdirBufferOptionsDefault, readdirBufferOptionsToInternal, readdirDirentBufferOptionsDefault, readdirDirentBufferOptionsToInternal, readdirDirentOptionsDefault, readdirDirentOptionsToInternal, readdirFilePathOptionsDefault, readdirFilePathOptionsToInternal, realpathOptionsDefault, realpathOptionsToInternal, rmOptionsDefault, rmdirOptionsDefault, writeFileBufferOptionsDefault, writeFileBufferOptionsToInternal, writeFileStringOptionsDefault, writeFileStringOptionsToInternal) import Node.FS.Perms (Perms, permsToString) @@ -369,7 +369,7 @@ readdirBuffer' file options cb = runEffectFn3 readdirImpl file (readdirBufferOpt -- | Reads the contents of a directory. readdirDirent :: FilePath - -> Callback1 (Array (Dirent DirentNameTypeString)) + -> Callback1 (Array (Dirent DirentNameString)) -> Effect Unit readdirDirent file = readdirDirent' file readdirDirentOptionsDefault @@ -377,14 +377,14 @@ readdirDirent file = readdirDirent' file readdirDirentOptionsDefault readdirDirent' :: FilePath -> ReaddirDirentOptions - -> Callback1 (Array (Dirent DirentNameTypeString)) + -> Callback1 (Array (Dirent DirentNameString)) -> Effect Unit readdirDirent' file options cb = runEffectFn3 readdirImpl file (readdirDirentOptionsToInternal options) (handleCallback1 cb) -- | Reads the contents of a directory. readdirDirentBuffer :: FilePath - -> Callback1 (Array (Dirent DirentNameTypeBuffer)) + -> Callback1 (Array (Dirent DirentNameBuffer)) -> Effect Unit readdirDirentBuffer file = readdirDirentBuffer' file readdirDirentBufferOptionsDefault @@ -392,7 +392,7 @@ readdirDirentBuffer file = readdirDirentBuffer' file readdirDirentBufferOptionsD readdirDirentBuffer' :: FilePath -> ReaddirDirentBufferOptions - -> Callback1 (Array (Dirent DirentNameTypeBuffer)) + -> Callback1 (Array (Dirent DirentNameBuffer)) -> Effect Unit readdirDirentBuffer' file options cb = runEffectFn3 readdirImpl file (readdirDirentBufferOptionsToInternal options) (handleCallback1 cb) @@ -654,10 +654,10 @@ glob pattern = glob' pattern globFilePathOptionsDefault glob' :: Array FilePath -> GlobFilePathOptions -> Callback1 (Array FilePath) -> Effect Unit glob' pattern options cb = runEffectFn3 globImpl pattern (globFilePathOptionsToInternal options) (handleCallback1 cb) -globDirent :: Array FilePath -> Callback1 (Array (Dirent DirentNameTypeString)) -> Effect Unit +globDirent :: Array FilePath -> Callback1 (Array (Dirent DirentNameString)) -> Effect Unit globDirent pattern = globDirent' pattern globDirentOptionsDefault -globDirent' :: Array FilePath -> GlobDirentOptions -> Callback1 (Array (Dirent DirentNameTypeString)) -> Effect Unit +globDirent' :: Array FilePath -> GlobDirentOptions -> Callback1 (Array (Dirent DirentNameString)) -> Effect Unit globDirent' pattern options cb = runEffectFn3 globImpl pattern (globDirentOptionsToInternal options) (handleCallback1 cb) -- | Change permissions on a symbolic link. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_lchmod_path_mode_callback) diff --git a/src/Node/FS/Dir.purs b/src/Node/FS/Dir.purs index c9e7a07..a1c3d69 100644 --- a/src/Node/FS/Dir.purs +++ b/src/Node/FS/Dir.purs @@ -6,7 +6,7 @@ import Data.Maybe (Maybe) import Data.Nullable (Nullable, toMaybe) import Effect (Effect) import Effect.Uncurried (EffectFn1, EffectFn2, runEffectFn1, runEffectFn2) -import Node.FS.Dirent (Dirent, DirentNameTypeString) +import Node.FS.Dirent (Dirent, DirentNameString) import Node.FS.Internal.Utils (Callback0, JSCallback0, JSCallback1, Callback1, handleCallback0, handleCallback1) import Node.Path (FilePath) @@ -20,8 +20,8 @@ instance Show Dir where foreign import closeImpl :: EffectFn2 Dir JSCallback0 Unit foreign import closeSyncImpl :: EffectFn1 Dir Unit -foreign import readImpl :: EffectFn2 Dir (JSCallback1 (Nullable (Dirent DirentNameTypeString))) Unit -foreign import readSyncImpl :: EffectFn1 Dir (Nullable (Dirent DirentNameTypeString)) +foreign import readImpl :: EffectFn2 Dir (JSCallback1 (Nullable (Dirent DirentNameString))) Unit +foreign import readSyncImpl :: EffectFn1 Dir (Nullable (Dirent DirentNameString)) -- | Get the path of this directory as was provided to fs.opendir(), fs.opendirSync(), or fsPromises.opendir(). foreign import path :: Dir -> FilePath @@ -35,9 +35,9 @@ closeSync :: Dir -> Effect Unit closeSync = runEffectFn1 closeSyncImpl -- | Asynchronously read the next directory entry. -read :: Dir -> (Callback1 (Maybe (Dirent DirentNameTypeString))) -> Effect Unit +read :: Dir -> (Callback1 (Maybe (Dirent DirentNameString))) -> Effect Unit read dir cb = runEffectFn2 readImpl dir (handleCallback1 (cb <<< map toMaybe)) -- | Synchronously read the next directory entry. -readSync :: Dir -> Effect (Maybe (Dirent DirentNameTypeString)) +readSync :: Dir -> Effect (Maybe (Dirent DirentNameString)) readSync dir = toMaybe <$> runEffectFn1 readSyncImpl dir diff --git a/src/Node/FS/Dirent.purs b/src/Node/FS/Dirent.purs index db8acaa..fb63a56 100644 --- a/src/Node/FS/Dirent.purs +++ b/src/Node/FS/Dirent.purs @@ -7,12 +7,12 @@ import Node.Path (FilePath) import Partial.Unsafe (unsafeCrashWith) import Unsafe.Coerce (unsafeCoerce) -data DirentNameType +data DirentName -foreign import data DirentNameTypeString :: DirentNameType -foreign import data DirentNameTypeBuffer :: DirentNameType +foreign import data DirentNameString :: DirentName +foreign import data DirentNameBuffer :: DirentName -foreign import data Dirent :: DirentNameType -> Type +foreign import data Dirent :: DirentName -> Type -- | Check if the Dirent object describes a block device. foreign import isBlockDevice :: forall direntnametype. Dirent direntnametype -> Boolean @@ -61,11 +61,11 @@ class IsDirentNameForDirent direntnametype stringOrBuffer | direntnametype -> st -- | The file name that this object refers to. The type of this value is determined by the options.encoding passed to fs.readdir() or fs.readdirSync(). name :: Dirent direntnametype -> stringOrBuffer -instance IsDirentNameForDirent DirentNameTypeString String where - name :: Dirent DirentNameTypeString -> String +instance IsDirentNameForDirent DirentNameString String where + name :: Dirent DirentNameString -> String name = nameImpl -else instance IsDirentNameForDirent DirentNameTypeBuffer Buffer where - name :: Dirent DirentNameTypeBuffer -> Buffer +else instance IsDirentNameForDirent DirentNameBuffer Buffer where + name :: Dirent DirentNameBuffer -> Buffer name = nameImpl -- | Get the parent directory path of the file this Dirent object refers to. diff --git a/src/Node/FS/Options.purs b/src/Node/FS/Options.purs index 8b6864f..7ae95ed 100644 --- a/src/Node/FS/Options.purs +++ b/src/Node/FS/Options.purs @@ -11,7 +11,7 @@ import Foreign as Foreign import Node.Buffer (Buffer) import Node.Encoding (Encoding(..), encodingToNode) import Node.FS.Constants (CopyMode, FileFlags(..), copyFile_NO_FLAGS, fileFlagsToNode) -import Node.FS.Dirent (Dirent, DirentNameTypeString) +import Node.FS.Dirent (Dirent, DirentNameString) import Node.FS.Internal.Undefinable (Undefinable) import Node.FS.Internal.Undefinable as Undefinable import Node.FS.Perms (Perms, all, mkPerms, permsToString, read, write) @@ -342,12 +342,12 @@ globFilePathOptionsDefault = { cwd: Nothing, exclude: Nothing } globFilePathOptionsToInternal :: GlobFilePathOptions -> GlobOptionsInternal FilePath globFilePathOptionsToInternal { cwd, exclude } = { cwd: toNullable cwd, exclude: toNullable exclude, withFileTypes: false } -type GlobDirentOptions = { cwd :: Maybe FilePath, exclude :: Maybe (Dirent DirentNameTypeString -> Boolean) } +type GlobDirentOptions = { cwd :: Maybe FilePath, exclude :: Maybe (Dirent DirentNameString -> Boolean) } globDirentOptionsDefault :: GlobDirentOptions globDirentOptionsDefault = { cwd: Nothing, exclude: Nothing } -globDirentOptionsToInternal :: GlobDirentOptions -> GlobOptionsInternal (Dirent DirentNameTypeString) +globDirentOptionsToInternal :: GlobDirentOptions -> GlobOptionsInternal (Dirent DirentNameString) globDirentOptionsToInternal { cwd, exclude } = { cwd: toNullable cwd, exclude: toNullable exclude, withFileTypes: true } ------------------ diff --git a/src/Node/FS/Sync.purs b/src/Node/FS/Sync.purs index 442e3e3..57be331 100644 --- a/src/Node/FS/Sync.purs +++ b/src/Node/FS/Sync.purs @@ -96,7 +96,7 @@ import Node.Buffer (Buffer, size) import Node.Encoding (Encoding(..), encodingToNode) import Node.FS.Constants (AccessMode, CopyMode, FileFlags, defaultAccessMode, defaultCopyMode, fileFlagsToNode) import Node.FS.Dir (Dir) -import Node.FS.Dirent (Dirent, DirentNameTypeBuffer, DirentNameTypeString) +import Node.FS.Dirent (Dirent, DirentNameBuffer, DirentNameString) import Node.FS.Internal.Utils (datetimeToUnixEpochTimeInSeconds) import Node.FS.Options (AppendFileBufferOptions, AppendFileOptionsInternal, AppendFileStringOptions, CpDirOptions, CpFileOptions, CpOptionsInternal, FdReadOptions, FdReadOptionsInternal, FdWriteOptions, FdWriteOptionsInternal, GlobDirentOptions, GlobFilePathOptions, GlobOptionsInternal, MkdirOptions, MkdirOptionsInternal, OpendirOptions, OpendirOptionsInternal, ReadFileBufferOptions, ReadFileOptionsInternal, ReadFileStringOptions, ReaddirBufferOptions, ReaddirDirentBufferOptions, ReaddirDirentOptions, ReaddirFilePathOptions, ReaddirOptionsInternal, RealpathOptions, RealpathOptionsInternal, RmOptions, RmdirOptions, WriteFileBufferOptions, WriteFileOptionsInternal, WriteFileStringOptions, appendFileBufferOptionsDefault, appendFileBufferOptionsToInternal, appendFileStringOptionsDefault, appendFileStringOptionsToInternal, cpDirOptionsDefault, cpDirOptionsToCpOptionsInternal, cpFileOptionsDefault, cpFileOptionsToCpOptionsInternal, fdReadOptionsToInternal, fdWriteOptionsToInternal, globDirentOptionsDefault, globDirentOptionsToInternal, globFilePathOptionsDefault, globFilePathOptionsToInternal, mkdirOptionsDefault, mkdirOptionsToInternal, opendirOptionsDefault, opendirOptionsToInternal, readFileBufferOptionsDefault, readFileBufferOptionsToInternal, readFileStringOptionsDefault, readFileStringOptionsToInternal, readdirBufferOptionsDefault, readdirBufferOptionsToInternal, readdirDirentBufferOptionsDefault, readdirDirentBufferOptionsToInternal, readdirDirentOptionsDefault, readdirDirentOptionsToInternal, readdirFilePathOptionsDefault, readdirFilePathOptionsToInternal, realpathOptionsDefault, realpathOptionsToInternal, rmOptionsDefault, rmdirOptionsDefault, writeFileBufferOptionsDefault, writeFileBufferOptionsToInternal, writeFileStringOptionsDefault, writeFileStringOptionsToInternal) import Node.FS.Perms (Perms, permsToString) @@ -337,27 +337,27 @@ readdirBuffer' file options = runEffectFn2 readdirSyncImpl file (readdirBufferOp -- | Reads the contents of a directory. readdirDirent :: FilePath - -> Effect (Array (Dirent DirentNameTypeString)) + -> Effect (Array (Dirent DirentNameString)) readdirDirent file = readdirDirent' file readdirDirentOptionsDefault -- | Reads the contents of a directory. readdirDirent' :: FilePath -> ReaddirDirentOptions - -> Effect (Array (Dirent DirentNameTypeString)) + -> Effect (Array (Dirent DirentNameString)) readdirDirent' file options = runEffectFn2 readdirSyncImpl file (readdirDirentOptionsToInternal options) -- | Reads the contents of a directory. readdirDirentBuffer :: FilePath - -> Effect (Array (Dirent DirentNameTypeBuffer)) + -> Effect (Array (Dirent DirentNameBuffer)) readdirDirentBuffer file = readdirDirentBuffer' file readdirDirentBufferOptionsDefault -- | Reads the contents of a directory. readdirDirentBuffer' :: FilePath -> ReaddirDirentBufferOptions - -> Effect (Array (Dirent DirentNameTypeBuffer)) + -> Effect (Array (Dirent DirentNameBuffer)) readdirDirentBuffer' file options = runEffectFn2 readdirSyncImpl file (readdirDirentBufferOptionsToInternal options) -- | Sets the accessed and modified times for the specified file. @@ -600,10 +600,10 @@ glob pattern = glob' pattern globFilePathOptionsDefault glob' :: Array FilePath -> GlobFilePathOptions -> Effect (Array FilePath) glob' pattern options = runEffectFn2 globSyncImpl pattern (globFilePathOptionsToInternal options) -globDirent :: Array FilePath -> Effect (Array (Dirent DirentNameTypeString)) +globDirent :: Array FilePath -> Effect (Array (Dirent DirentNameString)) globDirent pattern = globDirent' pattern globDirentOptionsDefault -globDirent' :: Array FilePath -> GlobDirentOptions -> Effect (Array (Dirent DirentNameTypeString)) +globDirent' :: Array FilePath -> GlobDirentOptions -> Effect (Array (Dirent DirentNameString)) globDirent' pattern options = runEffectFn2 globSyncImpl pattern (globDirentOptionsToInternal options) -- | Change permissions on a symbolic link. See the [Node Documentation](https://nodejs.org/api/fs.html#fs_fs_lchmod_path_mode_callback) diff --git a/test/Test/Node/FS/OpendirAndDir.purs b/test/Test/Node/FS/OpendirAndDir.purs index e43350d..7654009 100644 --- a/test/Test/Node/FS/OpendirAndDir.purs +++ b/test/Test/Node/FS/OpendirAndDir.purs @@ -14,7 +14,7 @@ import Node.Encoding (Encoding(..)) import Node.FS.Options (opendirOptionsDefault, rmOptionsDefault) import Node.FS.Aff as A import Node.FS.Aff.Dir (close, entries, read) -import Node.FS.Dirent (Dirent, DirentNameTypeString) +import Node.FS.Dirent (Dirent, DirentNameString) import Node.FS.Perms (permsAll) import Node.Path (FilePath) import Node.Path as Path @@ -74,7 +74,7 @@ test1 = do }]""" } liftEffect $ log $ show files' - try (entries dir) >>= \(eitherFile :: Either Error (Array (Dirent DirentNameTypeString))) -> liftEffect $ assertEqual + try (entries dir) >>= \(eitherFile :: Either Error (Array (Dirent DirentNameString))) -> liftEffect $ assertEqual { actual: String.take 74 $ show eitherFile , expected: "(Left Error [ERR_DIR_CLOSED]: Directory handle was closed\n at #readImpl" } @@ -106,7 +106,7 @@ test2 = do { actual: String.take 74 $ show error , expected: "(Left Error [ERR_DIR_CLOSED]: Directory handle was closed\n at Dir.close" } - try (read dir) >>= \(eitherFile :: Either Error (Maybe (Dirent DirentNameTypeString))) -> liftEffect $ assertEqual + try (read dir) >>= \(eitherFile :: Either Error (Maybe (Dirent DirentNameString))) -> liftEffect $ assertEqual { actual: String.take 74 $ show eitherFile , expected: "(Left Error [ERR_DIR_CLOSED]: Directory handle was closed\n at #readImpl" } From bc7c327d3fc6989efd09a1c65083ecd8bfad47eb Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Sun, 13 Oct 2024 12:23:57 +0700 Subject: [PATCH 25/32] feat: Dirent -> dont export isXXX --- src/Node/FS/Dirent.purs | 42 +++++++++++++++------------------ src/Node/FS/Internal/Utils.purs | 2 +- 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/src/Node/FS/Dirent.purs b/src/Node/FS/Dirent.purs index fb63a56..d90821c 100644 --- a/src/Node/FS/Dirent.purs +++ b/src/Node/FS/Dirent.purs @@ -1,11 +1,20 @@ -module Node.FS.Dirent where +module Node.FS.Dirent + ( Dirent + , DirentName + , DirentNameString + , DirentNameBuffer + , DirentType(..) + , getType + , class IsDirentNameForDirent + , name + , parentPath + ) where import Prelude import Node.Buffer (Buffer) import Node.Path (FilePath) import Partial.Unsafe (unsafeCrashWith) -import Unsafe.Coerce (unsafeCoerce) data DirentName @@ -14,35 +23,22 @@ foreign import data DirentNameBuffer :: DirentName foreign import data Dirent :: DirentName -> Type --- | Check if the Dirent object describes a block device. foreign import isBlockDevice :: forall direntnametype. Dirent direntnametype -> Boolean - --- | Check if the Dirent object describes a character device. foreign import isCharacterDevice :: forall direntnametype. Dirent direntnametype -> Boolean - --- | Check if the Dirent object describes a directory. foreign import isDirectory :: forall direntnametype. Dirent direntnametype -> Boolean - --- | Check if the Dirent object describes a FIFO pipe. foreign import isFIFO :: forall direntnametype. Dirent direntnametype -> Boolean - --- | Check if the Dirent object describes a regular file. foreign import isFile :: forall direntnametype. Dirent direntnametype -> Boolean - --- | Check if the Dirent object describes a socket. foreign import isSocket :: forall direntnametype. Dirent direntnametype -> Boolean - --- | Check if the Dirent object describes a symbolic link. foreign import isSymbolicLink :: forall direntnametype. Dirent direntnametype -> Boolean data DirentType - = DirentType_BlockDevice - | DirentType_CharacterDevice - | DirentType_Directory - | DirentType_FIFO - | DirentType_File - | DirentType_Socket - | DirentType_SymbolicLink + = DirentType_BlockDevice -- Dirent object describes a block device. + | DirentType_CharacterDevice -- Dirent object describes a character device. + | DirentType_Directory -- Dirent object describes a directory. + | DirentType_FIFO -- Dirent object describes a FIFO pipe. + | DirentType_File -- Dirent object describes a regular file. + | DirentType_Socket -- Dirent object describes a socket. + | DirentType_SymbolicLink -- Dirent object describes a symbolic link. getType :: forall direntnametype. Dirent direntnametype -> DirentType getType dirent = @@ -53,7 +49,7 @@ getType dirent = else if isFile dirent then DirentType_File else if isSocket dirent then DirentType_Socket else if isSymbolicLink dirent then DirentType_SymbolicLink - else unsafeCrashWith "Impossible: unknown Dirent type" + else unsafeCrashWith ("Impossible: unknown Dirent type for " <> show dirent) foreign import nameImpl :: forall direntnametype nametype. Dirent direntnametype -> nametype diff --git a/src/Node/FS/Internal/Utils.purs b/src/Node/FS/Internal/Utils.purs index fcf8896..75ec4c3 100644 --- a/src/Node/FS/Internal/Utils.purs +++ b/src/Node/FS/Internal/Utils.purs @@ -19,7 +19,7 @@ type JSCallback1 a = EffectFn2 (Nullable Error) a Unit type JSCallback2 a b = EffectFn3 (Nullable Error) a b Unit -- | Type synonym for callback functions. -type Callback0 = Either Error Unit -> Effect Unit -- TODO: better Maybe Error -> Unit? +type Callback0 = Either Error Unit -> Effect Unit -- TODO: maybe better Maybe Error -> Unit? type Callback1 a = Either Error a -> Effect Unit handleCallback0 :: Callback0 -> JSCallback0 From 4710e21feb4063e2b1e01d8075278a5b7ea2a51a Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Sun, 13 Oct 2024 12:34:11 +0700 Subject: [PATCH 26/32] feat: move Callbacks --- src/Node/FS/Async.purs | 3 ++- src/Node/FS/Dir.purs | 2 +- src/Node/FS/Internal/AffUtils.purs | 2 +- src/Node/FS/Internal/Callbacks.purs | 38 +++++++++++++++++++++++++++++ src/Node/FS/Internal/Utils.purs | 26 -------------------- 5 files changed, 42 insertions(+), 29 deletions(-) create mode 100644 src/Node/FS/Internal/Callbacks.purs diff --git a/src/Node/FS/Async.purs b/src/Node/FS/Async.purs index 5cd2838..2abb436 100644 --- a/src/Node/FS/Async.purs +++ b/src/Node/FS/Async.purs @@ -97,7 +97,8 @@ import Node.FS (FileDescriptor, ByteCount, FilePosition, BufferLength, BufferOff import Node.FS.Constants (AccessMode, CopyMode, FileFlags, defaultAccessMode, defaultCopyMode, fileFlagsToNode) import Node.FS.Dir (Dir) import Node.FS.Dirent (Dirent, DirentNameBuffer, DirentNameString) -import Node.FS.Internal.Utils (Callback0, Callback1, JSCallback0, JSCallback1, JSCallback2, datetimeToUnixEpochTimeInSeconds, handleCallback0, handleCallback1, handleCallback1Tuple) +import Node.FS.Internal.Utils (datetimeToUnixEpochTimeInSeconds) +import Node.FS.Internal.Callbacks (Callback0, Callback1, JSCallback0, JSCallback1, JSCallback2, handleCallback0, handleCallback1, handleCallback1Tuple) import Node.FS.Options (AppendFileBufferOptions, AppendFileOptionsInternal, AppendFileStringOptions, CpDirOptions, CpFileOptions, CpOptionsInternal, FdReadOptions, FdReadOptionsInternal, FdWriteOptions, FdWriteOptionsInternal, GlobDirentOptions, GlobFilePathOptions, GlobOptionsInternal, MkdirOptions, MkdirOptionsInternal, OpendirOptions, OpendirOptionsInternal, ReadFileBufferOptions, ReadFileOptionsInternal, ReadFileStringOptions, ReaddirBufferOptions, ReaddirDirentBufferOptions, ReaddirDirentOptions, ReaddirFilePathOptions, ReaddirOptionsInternal, RealpathOptions, RealpathOptionsInternal, RmOptions, RmdirOptions, WriteFileBufferOptions, WriteFileOptionsInternal, WriteFileStringOptions, appendFileBufferOptionsDefault, appendFileBufferOptionsToInternal, appendFileStringOptionsDefault, appendFileStringOptionsToInternal, cpDirOptionsDefault, cpDirOptionsToCpOptionsInternal, cpFileOptionsDefault, cpFileOptionsToCpOptionsInternal, fdReadOptionsToInternal, fdWriteOptionsToInternal, globDirentOptionsDefault, globDirentOptionsToInternal, globFilePathOptionsDefault, globFilePathOptionsToInternal, mkdirOptionsDefault, mkdirOptionsToInternal, opendirOptionsDefault, opendirOptionsToInternal, readFileBufferOptionsDefault, readFileBufferOptionsToInternal, readFileStringOptionsDefault, readFileStringOptionsToInternal, readdirBufferOptionsDefault, readdirBufferOptionsToInternal, readdirDirentBufferOptionsDefault, readdirDirentBufferOptionsToInternal, readdirDirentOptionsDefault, readdirDirentOptionsToInternal, readdirFilePathOptionsDefault, readdirFilePathOptionsToInternal, realpathOptionsDefault, realpathOptionsToInternal, rmOptionsDefault, rmdirOptionsDefault, writeFileBufferOptionsDefault, writeFileBufferOptionsToInternal, writeFileStringOptionsDefault, writeFileStringOptionsToInternal) import Node.FS.Perms (Perms, permsToString) import Node.FS.Stats (Stats) diff --git a/src/Node/FS/Dir.purs b/src/Node/FS/Dir.purs index a1c3d69..2298d6a 100644 --- a/src/Node/FS/Dir.purs +++ b/src/Node/FS/Dir.purs @@ -7,7 +7,7 @@ import Data.Nullable (Nullable, toMaybe) import Effect (Effect) import Effect.Uncurried (EffectFn1, EffectFn2, runEffectFn1, runEffectFn2) import Node.FS.Dirent (Dirent, DirentNameString) -import Node.FS.Internal.Utils (Callback0, JSCallback0, JSCallback1, Callback1, handleCallback0, handleCallback1) +import Node.FS.Internal.Callbacks (Callback0, JSCallback0, JSCallback1, Callback1, handleCallback0, handleCallback1) import Node.Path (FilePath) -- Foreign imports for the Dir class diff --git a/src/Node/FS/Internal/AffUtils.purs b/src/Node/FS/Internal/AffUtils.purs index 53d7957..f2d1623 100644 --- a/src/Node/FS/Internal/AffUtils.purs +++ b/src/Node/FS/Internal/AffUtils.purs @@ -4,7 +4,7 @@ import Prelude import Effect (Effect) import Effect.Aff (Aff, makeAff, nonCanceler) -import Node.FS.Internal.Utils (Callback1) +import Node.FS.Internal.Callbacks (Callback1) toAff :: forall a diff --git a/src/Node/FS/Internal/Callbacks.purs b/src/Node/FS/Internal/Callbacks.purs new file mode 100644 index 0000000..5336e0a --- /dev/null +++ b/src/Node/FS/Internal/Callbacks.purs @@ -0,0 +1,38 @@ +module Node.FS.Internal.Callbacks where + +import Prelude + +import Data.DateTime (DateTime) +import Data.DateTime.Instant (fromDateTime, unInstant) +import Data.Either (Either(..)) +import Data.Int (round) +import Data.Maybe (Maybe(..)) +import Data.Nullable (Nullable, toMaybe) +import Data.Time.Duration (Milliseconds(..)) +import Data.Tuple (Tuple(..)) +import Effect (Effect) +import Effect.Exception (Error) +import Effect.Uncurried (EffectFn1, EffectFn2, EffectFn3, mkEffectFn1, mkEffectFn2, mkEffectFn3) + +type JSCallback0 = EffectFn1 (Nullable Error) Unit +type JSCallback1 a = EffectFn2 (Nullable Error) a Unit +type JSCallback2 a b = EffectFn3 (Nullable Error) a b Unit + +-- | Type synonym for callback functions. +type Callback0 = Either Error Unit -> Effect Unit -- TODO: maybe better Maybe Error -> Unit? +type Callback1 a = Either Error a -> Effect Unit + +handleCallback0 :: Callback0 -> JSCallback0 +handleCallback0 cb = mkEffectFn1 \err -> case toMaybe err of + Nothing -> cb (Right unit) + Just err' -> cb (Left err') + +handleCallback1 :: forall a. Callback1 a -> JSCallback1 a +handleCallback1 cb = mkEffectFn2 \err a -> case toMaybe err of + Nothing -> cb (Right a) + Just err' -> cb (Left err') + +handleCallback1Tuple :: forall a b. Callback1 (Tuple a b) -> JSCallback2 a b +handleCallback1Tuple cb = mkEffectFn3 \err a b -> case toMaybe err of + Nothing -> cb (Right (Tuple a b)) + Just err' -> cb (Left err') diff --git a/src/Node/FS/Internal/Utils.purs b/src/Node/FS/Internal/Utils.purs index 75ec4c3..a04ad78 100644 --- a/src/Node/FS/Internal/Utils.purs +++ b/src/Node/FS/Internal/Utils.purs @@ -12,32 +12,6 @@ import Data.Time.Duration (Milliseconds(..)) import Data.Tuple (Tuple(..)) import Effect (Effect) import Effect.Exception (Error) -import Effect.Uncurried (EffectFn1, EffectFn2, EffectFn3, mkEffectFn1, mkEffectFn2, mkEffectFn3) - -type JSCallback0 = EffectFn1 (Nullable Error) Unit -type JSCallback1 a = EffectFn2 (Nullable Error) a Unit -type JSCallback2 a b = EffectFn3 (Nullable Error) a b Unit - --- | Type synonym for callback functions. -type Callback0 = Either Error Unit -> Effect Unit -- TODO: maybe better Maybe Error -> Unit? -type Callback1 a = Either Error a -> Effect Unit - -handleCallback0 :: Callback0 -> JSCallback0 -handleCallback0 cb = mkEffectFn1 \err -> case toMaybe err of - Nothing -> cb (Right unit) - Just err' -> cb (Left err') - -handleCallback1 :: forall a. Callback1 a -> JSCallback1 a -handleCallback1 cb = mkEffectFn2 \err a -> case toMaybe err of - Nothing -> cb (Right a) - Just err' -> cb (Left err') - -handleCallback1Tuple :: forall a b. Callback1 (Tuple a b) -> JSCallback2 a b -handleCallback1Tuple cb = mkEffectFn3 \err a b -> case toMaybe err of - Nothing -> cb (Right (Tuple a b)) - Just err' -> cb (Left err') - ----------------------- datetimeToUnixEpochTimeInSeconds :: DateTime -> Int datetimeToUnixEpochTimeInSeconds date = ms (toEpochMilliseconds date) / 1000 From 111d26e6fc324822a00bc7161df979b1a0345b0d Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Sun, 13 Oct 2024 12:44:54 +0700 Subject: [PATCH 27/32] feat: Dir -> split --- spago.lock | 88 ++++++++++++++++------ spago.yaml | 44 +++++------ src/Node/FS/Dir.js | 4 - src/Node/FS/Dir.purs | 27 ------- src/Node/FS/{Aff/Dir.purs => Dir/Aff.purs} | 15 ++-- src/Node/FS/Dir/Async.js | 2 + src/Node/FS/Dir/Async.purs | 22 ++++++ src/Node/FS/Dir/Sync.js | 2 + src/Node/FS/Dir/Sync.purs | 21 ++++++ src/Node/FS/Internal/Callbacks.purs | 4 - src/Node/FS/Internal/Utils.purs | 7 -- test/Test/Node/FS/OpendirAndDir.purs | 4 +- 12 files changed, 141 insertions(+), 99 deletions(-) rename src/Node/FS/{Aff/Dir.purs => Dir/Aff.purs} (92%) create mode 100644 src/Node/FS/Dir/Async.js create mode 100644 src/Node/FS/Dir/Async.purs create mode 100644 src/Node/FS/Dir/Sync.js create mode 100644 src/Node/FS/Dir/Sync.purs diff --git a/spago.lock b/spago.lock index 2c01805..1efc16e 100644 --- a/spago.lock +++ b/spago.lock @@ -5,28 +5,72 @@ "path": "./", "core": { "dependencies": [ - "aff", - "arrays", - "datetime", - "effect", - "either", - "enums", - "exceptions", - "foreign", - "functions", - "integers", - "js-date", - "maybe", - "node-buffer", - "node-path", - "node-streams", - "nullable", - "partial", - "prelude", - "refs", - "strings", - "tuples", - "unsafe-coerce" + { + "aff": ">=8.0.0 <9.0.0" + }, + { + "arrays": ">=7.3.0 <8.0.0" + }, + { + "datetime": ">=6.1.0 <7.0.0" + }, + { + "effect": ">=4.0.0 <5.0.0" + }, + { + "either": ">=6.1.0 <7.0.0" + }, + { + "enums": ">=6.0.1 <7.0.0" + }, + { + "exceptions": ">=6.1.0 <7.0.0" + }, + { + "foreign": ">=7.0.0 <8.0.0" + }, + { + "functions": ">=6.0.0 <7.0.0" + }, + { + "integers": ">=6.0.0 <7.0.0" + }, + { + "js-date": ">=8.0.0 <9.0.0" + }, + { + "maybe": ">=6.0.0 <7.0.0" + }, + { + "node-buffer": ">=9.0.0 <10.0.0" + }, + { + "node-path": ">=5.0.0 <6.0.0" + }, + { + "node-streams": ">=9.0.0 <10.0.0" + }, + { + "nullable": ">=6.0.0 <7.0.0" + }, + { + "partial": ">=4.0.0 <5.0.0" + }, + { + "prelude": ">=6.0.1 <7.0.0" + }, + { + "refs": ">=6.0.0 <7.0.0" + }, + { + "strings": ">=6.0.1 <7.0.0" + }, + { + "tuples": ">=7.0.0 <8.0.0" + }, + { + "unsafe-coerce": ">=6.0.0 <7.0.0" + } ], "build_plan": [ "aff", diff --git a/spago.yaml b/spago.yaml index f9c54c8..526fb6d 100644 --- a/spago.yaml +++ b/spago.yaml @@ -7,28 +7,28 @@ package: githubOwner: purescript-node githubRepo: purescript-node-fs dependencies: - - aff - - arrays - - datetime - - effect - - either - - enums - - exceptions - - foreign - - functions - - integers - - js-date - - maybe - - node-buffer - - node-path - - node-streams - - nullable - - partial - - prelude - - refs - - strings - - tuples - - unsafe-coerce + - aff: ">=8.0.0 <9.0.0" + - arrays: ">=7.3.0 <8.0.0" + - datetime: ">=6.1.0 <7.0.0" + - effect: ">=4.0.0 <5.0.0" + - either: ">=6.1.0 <7.0.0" + - enums: ">=6.0.1 <7.0.0" + - exceptions: ">=6.1.0 <7.0.0" + - foreign: ">=7.0.0 <8.0.0" + - functions: ">=6.0.0 <7.0.0" + - integers: ">=6.0.0 <7.0.0" + - js-date: ">=8.0.0 <9.0.0" + - maybe: ">=6.0.0 <7.0.0" + - node-buffer: ">=9.0.0 <10.0.0" + - node-path: ">=5.0.0 <6.0.0" + - node-streams: ">=9.0.0 <10.0.0" + - nullable: ">=6.0.0 <7.0.0" + - partial: ">=4.0.0 <5.0.0" + - prelude: ">=6.0.1 <7.0.0" + - refs: ">=6.0.0 <7.0.0" + - strings: ">=6.0.1 <7.0.0" + - tuples: ">=7.0.0 <8.0.0" + - unsafe-coerce: ">=6.0.0 <7.0.0" test: main: Test.Main dependencies: diff --git a/src/Node/FS/Dir.js b/src/Node/FS/Dir.js index 17abb12..ce73b07 100644 --- a/src/Node/FS/Dir.js +++ b/src/Node/FS/Dir.js @@ -1,7 +1,3 @@ export { inspect as showDirObj } from "util"; -export const closeImpl = (dir, callback) => dir.close(callback); -export const closeSyncImpl = (dir) => dir.close(); export const path = (dir) => dir.path; -export const readImpl = (dir, callback) => dir.read(callback); -export const readSyncImpl = (dir) => dir.read(); diff --git a/src/Node/FS/Dir.purs b/src/Node/FS/Dir.purs index 2298d6a..bc2ca38 100644 --- a/src/Node/FS/Dir.purs +++ b/src/Node/FS/Dir.purs @@ -2,12 +2,6 @@ module Node.FS.Dir where import Prelude -import Data.Maybe (Maybe) -import Data.Nullable (Nullable, toMaybe) -import Effect (Effect) -import Effect.Uncurried (EffectFn1, EffectFn2, runEffectFn1, runEffectFn2) -import Node.FS.Dirent (Dirent, DirentNameString) -import Node.FS.Internal.Callbacks (Callback0, JSCallback0, JSCallback1, Callback1, handleCallback0, handleCallback1) import Node.Path (FilePath) -- Foreign imports for the Dir class @@ -18,26 +12,5 @@ foreign import showDirObj :: Dir -> String instance Show Dir where show s = showDirObj s -foreign import closeImpl :: EffectFn2 Dir JSCallback0 Unit -foreign import closeSyncImpl :: EffectFn1 Dir Unit -foreign import readImpl :: EffectFn2 Dir (JSCallback1 (Nullable (Dirent DirentNameString))) Unit -foreign import readSyncImpl :: EffectFn1 Dir (Nullable (Dirent DirentNameString)) - -- | Get the path of this directory as was provided to fs.opendir(), fs.opendirSync(), or fsPromises.opendir(). foreign import path :: Dir -> FilePath - --- | Asynchronously close the directory's underlying resource handle. -close :: Dir -> Callback0 -> Effect Unit -close dir cb = runEffectFn2 closeImpl dir (handleCallback0 cb) - --- | Synchronously close the directory's underlying resource handle. -closeSync :: Dir -> Effect Unit -closeSync = runEffectFn1 closeSyncImpl - --- | Asynchronously read the next directory entry. -read :: Dir -> (Callback1 (Maybe (Dirent DirentNameString))) -> Effect Unit -read dir cb = runEffectFn2 readImpl dir (handleCallback1 (cb <<< map toMaybe)) - --- | Synchronously read the next directory entry. -readSync :: Dir -> Effect (Maybe (Dirent DirentNameString)) -readSync dir = toMaybe <$> runEffectFn1 readSyncImpl dir diff --git a/src/Node/FS/Aff/Dir.purs b/src/Node/FS/Dir/Aff.purs similarity index 92% rename from src/Node/FS/Aff/Dir.purs rename to src/Node/FS/Dir/Aff.purs index ff5f78e..88dc43c 100644 --- a/src/Node/FS/Aff/Dir.purs +++ b/src/Node/FS/Dir/Aff.purs @@ -1,9 +1,4 @@ -module Node.FS.Aff.Dir - ( read - , close - , entries - , entriesIterate - ) where +module Node.FS.Dir.Aff where import Prelude @@ -17,16 +12,16 @@ import Effect.Exception (Error) import Effect.Ref (Ref) import Effect.Ref as Ref import Node.FS.Dir (Dir) -import Node.FS.Dir as Dir +import Node.FS.Dir.Async as A import Node.FS.Dirent (Dirent, DirentNameString) import Node.FS.Internal.AffUtils (toAff1) read :: Dir -> Aff (Maybe (Dirent DirentNameString)) -read = toAff1 Dir.read +read = toAff1 A.read close :: Dir -> Aff Unit close dir = makeAff \k -> do - Dir.close dir k + A.close dir k pure nonCanceler entries :: Dir -> Aff (Array (Dirent DirentNameString)) @@ -58,7 +53,7 @@ entriesIterate dir handleDirent = finally (close dir) $ makeAff \(k :: Either Er stopped <- Ref.read stopRef if stopped then do callback $ Right unit - else Dir.read dir case _ of + else A.read dir case _ of Left error -> callback $ Left error Right maybeDirent -> case maybeDirent of diff --git a/src/Node/FS/Dir/Async.js b/src/Node/FS/Dir/Async.js new file mode 100644 index 0000000..668c881 --- /dev/null +++ b/src/Node/FS/Dir/Async.js @@ -0,0 +1,2 @@ +export const closeImpl = (dir, callback) => dir.close(callback); +export const readImpl = (dir, callback) => dir.read(callback); diff --git a/src/Node/FS/Dir/Async.purs b/src/Node/FS/Dir/Async.purs new file mode 100644 index 0000000..8928149 --- /dev/null +++ b/src/Node/FS/Dir/Async.purs @@ -0,0 +1,22 @@ +module Node.FS.Dir.Async where + +import Prelude + +import Data.Maybe (Maybe) +import Data.Nullable (Nullable, toMaybe) +import Effect (Effect) +import Effect.Uncurried (EffectFn2, runEffectFn2) +import Node.FS.Dir (Dir) +import Node.FS.Dirent (Dirent, DirentNameString) +import Node.FS.Internal.Callbacks (Callback0, JSCallback0, JSCallback1, Callback1, handleCallback0, handleCallback1) + +foreign import closeImpl :: EffectFn2 Dir JSCallback0 Unit +foreign import readImpl :: EffectFn2 Dir (JSCallback1 (Nullable (Dirent DirentNameString))) Unit + +-- | Asynchronously close the directory's underlying resource handle. +close :: Dir -> Callback0 -> Effect Unit +close dir cb = runEffectFn2 closeImpl dir (handleCallback0 cb) + +-- | Asynchronously read the next directory entry. +read :: Dir -> (Callback1 (Maybe (Dirent DirentNameString))) -> Effect Unit +read dir cb = runEffectFn2 readImpl dir (handleCallback1 (cb <<< map toMaybe)) diff --git a/src/Node/FS/Dir/Sync.js b/src/Node/FS/Dir/Sync.js new file mode 100644 index 0000000..bba43b1 --- /dev/null +++ b/src/Node/FS/Dir/Sync.js @@ -0,0 +1,2 @@ +export const closeSyncImpl = (dir) => dir.closeSync(); +export const readSyncImpl = (dir) => dir.readSync(); diff --git a/src/Node/FS/Dir/Sync.purs b/src/Node/FS/Dir/Sync.purs new file mode 100644 index 0000000..a662f9d --- /dev/null +++ b/src/Node/FS/Dir/Sync.purs @@ -0,0 +1,21 @@ +module Node.FS.Dir.Sync where + +import Prelude + +import Data.Maybe (Maybe) +import Data.Nullable (Nullable, toMaybe) +import Effect (Effect) +import Effect.Uncurried (EffectFn1, runEffectFn1) +import Node.FS.Dir (Dir) +import Node.FS.Dirent (Dirent, DirentNameString) + +foreign import closeSyncImpl :: EffectFn1 Dir Unit +foreign import readSyncImpl :: EffectFn1 Dir (Nullable (Dirent DirentNameString)) + +-- | Synchronously close the directory's underlying resource handle. +closeSync :: Dir -> Effect Unit +closeSync = runEffectFn1 closeSyncImpl + +-- | Synchronously read the next directory entry. +readSync :: Dir -> Effect (Maybe (Dirent DirentNameString)) +readSync dir = toMaybe <$> runEffectFn1 readSyncImpl dir diff --git a/src/Node/FS/Internal/Callbacks.purs b/src/Node/FS/Internal/Callbacks.purs index 5336e0a..e578007 100644 --- a/src/Node/FS/Internal/Callbacks.purs +++ b/src/Node/FS/Internal/Callbacks.purs @@ -2,13 +2,9 @@ module Node.FS.Internal.Callbacks where import Prelude -import Data.DateTime (DateTime) -import Data.DateTime.Instant (fromDateTime, unInstant) import Data.Either (Either(..)) -import Data.Int (round) import Data.Maybe (Maybe(..)) import Data.Nullable (Nullable, toMaybe) -import Data.Time.Duration (Milliseconds(..)) import Data.Tuple (Tuple(..)) import Effect (Effect) import Effect.Exception (Error) diff --git a/src/Node/FS/Internal/Utils.purs b/src/Node/FS/Internal/Utils.purs index a04ad78..9bf7e50 100644 --- a/src/Node/FS/Internal/Utils.purs +++ b/src/Node/FS/Internal/Utils.purs @@ -4,18 +4,11 @@ import Prelude import Data.DateTime (DateTime) import Data.DateTime.Instant (fromDateTime, unInstant) -import Data.Either (Either(..)) import Data.Int (round) -import Data.Maybe (Maybe(..)) -import Data.Nullable (Nullable, toMaybe) import Data.Time.Duration (Milliseconds(..)) -import Data.Tuple (Tuple(..)) -import Effect (Effect) -import Effect.Exception (Error) datetimeToUnixEpochTimeInSeconds :: DateTime -> Int datetimeToUnixEpochTimeInSeconds date = ms (toEpochMilliseconds date) / 1000 where ms (Milliseconds n) = round n toEpochMilliseconds = unInstant <<< fromDateTime - diff --git a/test/Test/Node/FS/OpendirAndDir.purs b/test/Test/Node/FS/OpendirAndDir.purs index 7654009..1d7a865 100644 --- a/test/Test/Node/FS/OpendirAndDir.purs +++ b/test/Test/Node/FS/OpendirAndDir.purs @@ -13,7 +13,7 @@ import Effect.Exception (Error) import Node.Encoding (Encoding(..)) import Node.FS.Options (opendirOptionsDefault, rmOptionsDefault) import Node.FS.Aff as A -import Node.FS.Aff.Dir (close, entries, read) +import Node.FS.Dir.Aff (close, entries, read) import Node.FS.Dirent (Dirent, DirentNameString) import Node.FS.Perms (permsAll) import Node.Path (FilePath) @@ -23,8 +23,6 @@ import Test.Assert (assertEqual) outerTmpDir :: FilePath outerTmpDir = Path.concat [ "tmp", "dir-entries-test" ] --- outerTmpDir = Path.concat [".", "tmp", "dir-entries-test"] - prepare :: Aff Unit prepare = do A.rm' outerTmpDir (rmOptionsDefault { recursive = true, force = true }) From 3a1dc6fc7aa44e2509f5bf8600552f0f08d67e30 Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Sun, 13 Oct 2024 12:49:08 +0700 Subject: [PATCH 28/32] refactor: tests -> wrong names --- test/Test/Node/FS/Sync.purs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/Test/Node/FS/Sync.purs b/test/Test/Node/FS/Sync.purs index c53f8a6..7877b7f 100644 --- a/test/Test/Node/FS/Sync.purs +++ b/test/Test/Node/FS/Sync.purs @@ -199,25 +199,25 @@ main = do Left _ -> pure unit Right _ -> throw $ destReadPath <> " already exists, but copying a file to there did not throw an error with COPYFILE_EXCL option" - log "copy file using cp: ok" + log "copy file using cpFile: ok" let destReadPath2 = Path.concat [ tempDir, "readable2.txt" ] S.cpFile readableFixturePath destReadPath2 unlessM (S.exists destReadPath2) do throw $ destReadPath2 <> " does not exist after copy" - log "copy dir using cp: if copy using cpDir - ok" + log "copy dir using cpDir: ok" S.cpDir (tempDir <> "/") (tempDir <> "2") - log "copy dir using cp: if copy using cpDir - error - ERR_FS_EISDIR \"Recursive option not enabled\"" + log "copy dir using cpFile: error - ERR_FS_EISDIR \"Recursive option not enabled\"" let cpFileShouldThrow_from = tempDir <> "/" cpFileShouldThrow_to = tempDir <> "3" - cpDirError <- try $ S.cpFile cpFileShouldThrow_from cpFileShouldThrow_to - case cpDirError of - Left cpDirError' -> do + cpFileError <- try $ S.cpFile cpFileShouldThrow_from cpFileShouldThrow_to + case cpFileError of + Left cpFileError' -> do let - cpDirError'_message = Error.message cpDirError' - cpDirError'_code = (unsafeCoerce cpDirError' :: { code :: String }).code - assertEqual' "cpDirError'_message" { actual: cpDirError'_message, expected: "Recursive option not enabled, cannot copy a directory: " <> cpFileShouldThrow_from } - assertEqual' "cpDirError'_code" { actual: cpDirError'_code, expected: "ERR_FS_EISDIR" } + cpFileError'_message = Error.message cpFileError' + cpFileError'_code = (unsafeCoerce cpFileError' :: { code :: String }).code + assertEqual' "cpDirError'_message" { actual: cpFileError'_message, expected: "Recursive option not enabled, cannot copy a directory: " <> cpFileShouldThrow_from } + assertEqual' "cpDirError'_code" { actual: cpFileError'_code, expected: "ERR_FS_EISDIR" } Right _ -> throw $ "cpFileShouldThrow: should have failed " <> show { cpFileShouldThrow_from, cpFileShouldThrow_to } From 4732d1b1ec0573013dede6188c405359eab98e87 Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Sun, 13 Oct 2024 12:50:47 +0700 Subject: [PATCH 29/32] refactor: Dir.Sync -> wrong names --- src/Node/FS/Dir/Sync.purs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Node/FS/Dir/Sync.purs b/src/Node/FS/Dir/Sync.purs index a662f9d..ba4fd6d 100644 --- a/src/Node/FS/Dir/Sync.purs +++ b/src/Node/FS/Dir/Sync.purs @@ -13,9 +13,9 @@ foreign import closeSyncImpl :: EffectFn1 Dir Unit foreign import readSyncImpl :: EffectFn1 Dir (Nullable (Dirent DirentNameString)) -- | Synchronously close the directory's underlying resource handle. -closeSync :: Dir -> Effect Unit -closeSync = runEffectFn1 closeSyncImpl +close :: Dir -> Effect Unit +close = runEffectFn1 closeSyncImpl -- | Synchronously read the next directory entry. -readSync :: Dir -> Effect (Maybe (Dirent DirentNameString)) -readSync dir = toMaybe <$> runEffectFn1 readSyncImpl dir +read :: Dir -> Effect (Maybe (Dirent DirentNameString)) +read dir = toMaybe <$> runEffectFn1 readSyncImpl dir From b9195f52fb00e6d48276426a6439b3b6165c88aa Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Sun, 13 Oct 2024 12:51:22 +0700 Subject: [PATCH 30/32] refactor: Dir -> explicit export --- src/Node/FS/Dir/Async.purs | 2 +- src/Node/FS/Dir/Sync.purs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Node/FS/Dir/Async.purs b/src/Node/FS/Dir/Async.purs index 8928149..95fb856 100644 --- a/src/Node/FS/Dir/Async.purs +++ b/src/Node/FS/Dir/Async.purs @@ -1,4 +1,4 @@ -module Node.FS.Dir.Async where +module Node.FS.Dir.Async (close, read) where import Prelude diff --git a/src/Node/FS/Dir/Sync.purs b/src/Node/FS/Dir/Sync.purs index ba4fd6d..dfe49e9 100644 --- a/src/Node/FS/Dir/Sync.purs +++ b/src/Node/FS/Dir/Sync.purs @@ -1,4 +1,4 @@ -module Node.FS.Dir.Sync where +module Node.FS.Dir.Sync (close, read) where import Prelude From 622d56bf3fa2803712f84295d3f124ad07fc347b Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Sun, 13 Oct 2024 12:52:42 +0700 Subject: [PATCH 31/32] refactor: rename module --- src/Node/FS/Aff.purs | 2 +- src/Node/FS/Dir/Aff.purs | 2 +- src/Node/FS/Internal/{AffUtils.purs => ToAff.purs} | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename src/Node/FS/Internal/{AffUtils.purs => ToAff.purs} (96%) diff --git a/src/Node/FS/Aff.purs b/src/Node/FS/Aff.purs index d853128..854d0ce 100644 --- a/src/Node/FS/Aff.purs +++ b/src/Node/FS/Aff.purs @@ -92,7 +92,7 @@ import Effect.Aff (Aff, Error, makeAff, nonCanceler) import Node.Buffer (Buffer) import Node.Encoding (Encoding) import Node.FS.Types (BufferLength, BufferOffset, ByteCount, FileDescriptor, FileMode, FilePosition, SymlinkType) -import Node.FS.Internal.AffUtils (toAff1, toAff2, toAff3, toAff4, toAff5) +import Node.FS.Internal.ToAff (toAff1, toAff2, toAff3, toAff4, toAff5) import Node.FS.Options (AppendFileBufferOptions, CpDirOptions, CpFileOptions, FdReadOptions, FdWriteOptions, GlobDirentOptions, GlobFilePathOptions, MkdirOptions, OpendirOptions, ReadFileBufferOptions, ReadFileStringOptions, ReaddirBufferOptions, ReaddirDirentBufferOptions, ReaddirDirentOptions, ReaddirFilePathOptions, RealpathOptions, RmOptions, RmdirOptions, WriteFileBufferOptions, WriteFileStringOptions) import Node.FS.Constants (AccessMode, CopyMode, FileFlags) import Node.FS.Async as A diff --git a/src/Node/FS/Dir/Aff.purs b/src/Node/FS/Dir/Aff.purs index 88dc43c..bd42a85 100644 --- a/src/Node/FS/Dir/Aff.purs +++ b/src/Node/FS/Dir/Aff.purs @@ -14,7 +14,7 @@ import Effect.Ref as Ref import Node.FS.Dir (Dir) import Node.FS.Dir.Async as A import Node.FS.Dirent (Dirent, DirentNameString) -import Node.FS.Internal.AffUtils (toAff1) +import Node.FS.Internal.ToAff (toAff1) read :: Dir -> Aff (Maybe (Dirent DirentNameString)) read = toAff1 A.read diff --git a/src/Node/FS/Internal/AffUtils.purs b/src/Node/FS/Internal/ToAff.purs similarity index 96% rename from src/Node/FS/Internal/AffUtils.purs rename to src/Node/FS/Internal/ToAff.purs index f2d1623..41d390c 100644 --- a/src/Node/FS/Internal/AffUtils.purs +++ b/src/Node/FS/Internal/ToAff.purs @@ -1,4 +1,4 @@ -module Node.FS.Internal.AffUtils where +module Node.FS.Internal.ToAff where import Prelude From 0a1796ac1c18a122b067a195dab9803f8789a438 Mon Sep 17 00:00:00 2001 From: Serhii Khoma Date: Sun, 13 Oct 2024 13:17:22 +0700 Subject: [PATCH 32/32] feat: DirentType -> add derive --- src/Node/FS/Dirent.purs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Node/FS/Dirent.purs b/src/Node/FS/Dirent.purs index d90821c..3e21f15 100644 --- a/src/Node/FS/Dirent.purs +++ b/src/Node/FS/Dirent.purs @@ -15,6 +15,8 @@ import Prelude import Node.Buffer (Buffer) import Node.Path (FilePath) import Partial.Unsafe (unsafeCrashWith) +import Data.Generic.Rep (class Generic) +import Data.Show.Generic (genericShow) data DirentName @@ -40,6 +42,12 @@ data DirentType | DirentType_Socket -- Dirent object describes a socket. | DirentType_SymbolicLink -- Dirent object describes a symbolic link. +derive instance Eq DirentType +derive instance Ord DirentType +derive instance Generic DirentType _ +instance Show DirentType where + show = genericShow + getType :: forall direntnametype. Dirent direntnametype -> DirentType getType dirent = if isBlockDevice dirent then DirentType_BlockDevice