diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7c1c4828a8..a9196eb0f1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,6 +20,32 @@ env: OCAMLRUNPARAM: b jobs: + test-rewatch-integration: + needs: + - pkg-pr-new + runs-on: ubuntu-latest + env: + RUST_BACKTRACE: "1" + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Use Node.js + uses: actions/setup-node@v4 + with: + node-version-file: .nvmrc + - name: Install ReScript package + run: | + COMMIT_SHA="${{ github.event.pull_request.head.sha || github.sha }}" + yarn add "rescript@https://pkg.pr.new/rescript-lang/rescript@${COMMIT_SHA::7}" + shell: bash + working-directory: rewatch/testrepo + + - name: Run rewatch integration tests + run: | + make test-rewatch-ci + build-rewatch: strategy: fail-fast: false @@ -78,6 +104,11 @@ jobs: run: | cargo build --manifest-path rewatch/Cargo.toml --target ${{ matrix.rust-target }} --release + - name: Run rewatch unit tests + if: steps.build-cache.outputs.cache-hit != 'true' + run: | + cargo test --manifest-path rewatch/Cargo.toml + - name: Copy rewatch binary run: | cp rewatch/target/${{ matrix.rust-target }}/release/rewatch${{ runner.os == 'Windows' && '.exe' || '' }} rewatch.exe @@ -440,7 +471,7 @@ jobs: path: lib/ocaml pkg-pr-new: - needs: + needs: - build-rewatch - build-compiler runs-on: ubuntu-24.04-arm diff --git a/Makefile b/Makefile index 3f37c782e0..e7b5c0459a 100644 --- a/Makefile +++ b/Makefile @@ -16,8 +16,8 @@ dce: reanalyze.exe -dce-cmt _build/default/compiler rewatch: - cargo build --manifest-path rewatch/Cargo.toml - cp rewatch/target/debug/rewatch rewatch + cargo build --manifest-path rewatch/Cargo.toml --release + cp rewatch/target/release/rewatch rewatch ./scripts/copyExes.js --rewatch ninja/ninja: @@ -46,15 +46,25 @@ test-syntax-roundtrip: test-gentype: make -C tests/gentype_tests/typescript-react-example clean test -test-all: test test-gentype test-analysis test-tools +test-rewatch: + bash ./rewatch/tests/suite-ci.sh + +test-rewatch-ci: + bash ./rewatch/tests/suite-ci.sh node_modules/.bin/rewatch + +test-all: test test-gentype test-analysis test-tools test-rewatch reanalyze: reanalyze.exe -set-exit-code -all-cmt _build/default/compiler _build/default/tests -exclude-paths compiler/outcome_printer,compiler/ml,compiler/frontend,compiler/ext,compiler/depends,compiler/core,compiler/common,compiler/cmij,compiler/bsb_helper,compiler/bsb -lib: +lib-bsb: ./scripts/buildRuntime.sh ./scripts/prebuilt.js +lib: + ./scripts/buildRuntimeRewatch.sh + ./scripts/prebuilt.js + artifacts: lib ./scripts/npmPack.js --updateArtifactList diff --git a/cli/rewatch.js b/cli/rewatch.js index 41377a387f..6df646ed4b 100755 --- a/cli/rewatch.js +++ b/cli/rewatch.js @@ -3,8 +3,10 @@ // @ts-check import * as child_process from "node:child_process"; -import { rewatch_exe } from "./common/bins.js"; +import { rewatch_exe, bsc_exe } from "./common/bins.js"; const args = process.argv.slice(2); -child_process.spawnSync(rewatch_exe, args, { stdio: "inherit" }); +child_process.spawnSync(rewatch_exe, [...args, "--bsc-path", bsc_exe], { + stdio: "inherit", +}); diff --git a/rewatch/.cargo/config.toml b/rewatch/.cargo/config.toml new file mode 100644 index 0000000000..a10cae5f48 --- /dev/null +++ b/rewatch/.cargo/config.toml @@ -0,0 +1,4 @@ +[alias] +build-m1-release = "RUSTFLAGS=\"-C target-cpu=apple-m1\" cargo build --release" +build-docs = "cargo doc --no-deps --document-private-items --target-dir ./docs" + diff --git a/rewatch/.gitignore b/rewatch/.gitignore new file mode 100644 index 0000000000..e68f4e2f60 --- /dev/null +++ b/rewatch/.gitignore @@ -0,0 +1,3 @@ +/target +.DS_Store +/docs diff --git a/rewatch/Cargo.lock b/rewatch/Cargo.lock index 6c09783cd8..4b313f505c 100644 --- a/rewatch/Cargo.lock +++ b/rewatch/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "ahash" @@ -26,75 +26,77 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.13" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "once_cell", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.93" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" +checksum = "6b964d184e89d9b6b67dd2715bc8e74cf3107fb2b529990c90cf517326150bf4" [[package]] name = "arrayref" -version = "0.3.7" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "autocfg" -version = "1.2.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "bitflags" @@ -104,28 +106,38 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" [[package]] name = "blake3" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52" +checksum = "1230237285e3e10cde447185e8975408ae24deaa67205ce684805c25bc0c7937" dependencies = [ "arrayref", "arrayvec", "cc", "cfg-if", "constant_time_eq", + "memmap2", ] +[[package]] +name = "bumpalo" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" + [[package]] name = "cc" -version = "1.0.92" +version = "1.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41" +checksum = "c736e259eea577f443d5c86c304f9f4ae0295c43f3ba05c21f1d66b5f06001af" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -135,15 +147,15 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cfg_aliases" -version = "0.1.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "clap" -version = "4.5.4" +version = "4.5.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767" dependencies = [ "clap_builder", "clap_derive", @@ -151,9 +163,9 @@ dependencies = [ [[package]] name = "clap-verbosity-flag" -version = "2.2.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e099138e1807662ff75e2cebe4ae2287add879245574489f9b1588eb5e5564ed" +checksum = "34c77f67047557f62582784fd7482884697731b2932c7d37ced54bce2312e1e2" dependencies = [ "clap", "log", @@ -161,9 +173,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863" dependencies = [ "anstream", "anstyle", @@ -173,9 +185,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" dependencies = [ "heck", "proc-macro2", @@ -185,34 +197,34 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "console" -version = "0.15.8" +version = "0.15.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" dependencies = [ "encode_unicode", - "lazy_static", "libc", + "once_cell", "unicode-width", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "constant_time_eq" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" [[package]] name = "convert_case" @@ -225,24 +237,24 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "crossbeam-channel" -version = "0.5.12" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -259,31 +271,31 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "ctrlc" -version = "3.4.4" +version = "3.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "672465ae37dc1bc6380a6547a8883d5dd397b0f1faaad4f265726cc7042a5345" +checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" dependencies = [ "nix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "either" -version = "1.10.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "b7914353092ddf589ad78f25c5c1c21b7f80b0ff8621e7c814c3485b5306da9d" [[package]] name = "encode_unicode" -version = "0.3.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "env_logger" @@ -300,14 +312,14 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.23" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ "cfg-if", "libc", - "redox_syscall", - "windows-sys 0.52.0", + "libredox", + "windows-sys 0.59.0", ] [[package]] @@ -321,9 +333,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -336,9 +348,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -346,15 +358,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -363,15 +375,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", @@ -380,15 +392,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-timer" @@ -398,9 +410,9 @@ checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -416,9 +428,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -433,9 +445,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.3.9" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" [[package]] name = "humantime" @@ -445,15 +457,15 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "indicatif" -version = "0.17.8" +version = "0.17.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" dependencies = [ "console", - "instant", "number_prefix", "portable-atomic", "unicode-width", + "web-time", ] [[package]] @@ -476,31 +488,38 @@ dependencies = [ "libc", ] -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - [[package]] name = "is-terminal" -version = "0.4.12" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +checksum = "e19b23d53f35ce9f56aebc7d1bb4e6ac1e9c0db7ac85c8d1760c04379edced37" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] [[package]] name = "kqueue" @@ -523,28 +542,42 @@ dependencies = [ ] [[package]] -name = "lazy_static" -version = "1.4.0" +name = "libc" +version = "0.2.170" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" [[package]] -name = "libc" -version = "0.2.153" +name = "libredox" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.8.0", + "libc", + "redox_syscall", +] [[package]] name = "log" -version = "0.4.21" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memmap2" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" +dependencies = [ + "libc", +] [[package]] name = "mio" @@ -560,11 +593,11 @@ dependencies = [ [[package]] name = "nix" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.8.0", "cfg-if", "cfg_aliases", "libc", @@ -616,15 +649,15 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -634,24 +667,24 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "portable-atomic" -version = "1.6.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -678,18 +711,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "82b568323e98e49e2a0899dcee453dd679fae22d69adf9b11dd508d1549b7e2f" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.8.0", ] [[package]] name = "regex" -version = "1.10.4" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -699,9 +732,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -710,13 +743,13 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rewatch" -version = "1.0.10" +version = "1.2.0" dependencies = [ "ahash", "anyhow", @@ -743,9 +776,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" [[package]] name = "same-file" @@ -758,18 +791,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.197" +version = "1.0.218" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.218" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b" dependencies = [ "proc-macro2", "quote", @@ -778,15 +811,22 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.115" +version = "1.0.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +checksum = "44f86c3acccc9c65b153fe1b85a3be07fe5515274ec9f0653b4a0875731c72a6" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "slab" version = "0.4.9" @@ -804,9 +844,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.58" +version = "2.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" dependencies = [ "proc-macro2", "quote", @@ -839,33 +879,33 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe" [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "walkdir" @@ -883,6 +923,73 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" @@ -901,11 +1008,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "winapi", + "windows-sys 0.59.0", ] [[package]] @@ -934,11 +1041,11 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.52.0" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.6", ] [[package]] @@ -973,17 +1080,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -1000,9 +1108,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -1018,9 +1126,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -1036,9 +1144,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -1054,9 +1168,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -1072,9 +1186,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -1090,9 +1204,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -1108,24 +1222,24 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", diff --git a/rewatch/Cargo.toml b/rewatch/Cargo.toml index 79e5166038..5a5d192d0d 100644 --- a/rewatch/Cargo.toml +++ b/rewatch/Cargo.toml @@ -1,30 +1,30 @@ [package] name = "rewatch" -version = "1.0.10" +version = "1.2.0" edition = "2021" [dependencies] -notify = { version = "5.1.0", features = ["serde"] } -serde = { version = "1.0.152", features = ["derive"] } -serde_derive = "1.0.152" -serde_json = { version = "1.0.93" } ahash = "0.8.3" +anyhow = "1.0.93" +blake3 = "1.3.3" +clap = { version = "4.3", features = ["derive"] } +clap-verbosity-flag = "2.2" +console = "0.15.5" convert_case = "0.6.0" -rayon = "1.6.1" -log = { version = "0.4.17" } -env_logger = "0.10.0" +ctrlc = "3.4.4" +env_logger = "0.10" +futures = "0.3.25" +futures-timer = "3.0.2" indicatif = "0.17.3" -console = "0.15.5" -blake3 = "1.3.3" +log = { version = "0.4.17" } +notify = { version = "5.1.0", features = ["serde"] } notify-debouncer-mini = { version = "0.2.0" } +rayon = "1.6.1" regex = "1.7.1" -futures = "0.3.25" -futures-timer = "3.0.2" -clap = { version = "4.3.17", features = ["derive"] } +serde = { version = "1.0.152", features = ["derive"] } +serde_derive = "1.0.152" +serde_json = { version = "1.0.93" } sysinfo = "0.29.10" -ctrlc = "3.4.4" -clap-verbosity-flag = "2.2.2" -anyhow = "1.0.93" [profile.release] diff --git a/rewatch/CompilerConfigurationSpec.md b/rewatch/CompilerConfigurationSpec.md new file mode 100644 index 0000000000..ddfbdcfc54 --- /dev/null +++ b/rewatch/CompilerConfigurationSpec.md @@ -0,0 +1,173 @@ +## ReScript build configuration + +This document contains a list of all bsconfig parameters with remarks, and whether they are already implemented in rewatch. It is based on https://rescript-lang.org/docs/manual/latest/build-configuration-schema. + +| Parameter | JSON type | Remark | Implemented? | +| -------------------- | ----------------------- | ------ | :----------: | +| version | string | | [_] | +| name | string | | [x] | +| namespace | boolean | | [x] | +| namespace | string | | [x] | +| sources | string | | [x] | +| sources | array of string | | [x] | +| sources | Source | | [x] | +| sources | array of Source | | [x] | +| ignored-dirs | array of string | | [_] | +| bs-dependencies | array of string | | [x] | +| bs-dev-dependencies | array of string | | [x] | +| pinned-dependencies | array of string | | [x] | +| generators | array of Rule-Generator | | [_] | +| cut-generators | boolean | | [_] | +| jsx | JSX | | [x] | +| uncurried | boolean | | [x] | +| reason | Reason | | [x] | +| gentypeconfig | Gentype | | [_] | +| bsc-flags | array of string | | [x] | +| warnings | Warnings | | [x] | +| ppx-flags | array of string | | [x] | +| pp-flags | array of string | | [_] | +| js-post-build | Js-Post-Build | | [_] | +| package-specs | array of Module-Format | | [_] | +| package-specs | array of Package-Spec | | [x] | +| entries | array of Target-Item | | [_] | +| use-stdlib | boolean | | [_] | +| external-stdlib | string | | [_] | +| bs-external-includes | array of string | | [_] | +| suffix | Suffix | | [x] | +| reanalyze | Reanalyze | | [_] | + +### Source + +| Parameter | JSON type | Remark | Implemented? | +| ---------------- | ------------------------ | ------ | :----------: | +| dir | string | | [x] | +| type | "dev" | | [x] | +| files | array of string | | [_] | +| files | File-Object | | [_] | +| generators | array of Build-Generator | | [_] | +| public | "all" | | [_] | +| public | array of string | | [_] | +| resources | array of string | | [_] | +| subdirs | boolean | | [x] | +| subdirs | string | | [_] | +| subdirs | array of string | | [x] | +| subdirs | Source | | [_] | +| subdirs | array of Source | | [x] | +| group | string | | [_] | +| group | Group | | [_] | +| internal-depends | array of string | | [_] | + +### File-Object + +| Parameter | JSON type | Remark | Implemented? | +| --------- | --------------- | ------ | :----------: | +| slow-re | string | | [_] | +| excludes | array of string | | [_] | + +### Build-Generator + +| Parameter | JSON type | Remark | Implemented? | +| --------- | --------------- | ------ | :----------: | +| name | string | | [_] | +| edge | array of string | | [_] | + +### Rule-Generator + +| Parameter | JSON type | Remark | Implemented? | +| --------- | --------- | ------ | :----------: | +| name | string | | [_] | +| command | string | | [_] | + +### JSX + +| Parameter | JSON type | Remark | Implemented? | +| --------------- | --------------- | ------ | :----------: | +| version | JSX-Version | | [x] | +| module | "react" | | [x] | +| mode | JSX-Mode | | [x] | +| v3-dependencies | array of string | | [x] | + +### JSX-Version + +enum: 3 | 4 + +### JSX-Mode + +enum: "classic" | "automatic" + +### Gentype + +| Parameter | JSON type | Remark | Implemented? | +| --------- | --------- | ------ | :----------: | +| path | string | | [_] | + +### Reanalyze + +| Parameter | JSON type | Remark | Implemented? | +| ---------- | --------------------------- | ------ | :----------: | +| analysis | array of Reanalyze-Analysis | | [_] | +| suppress | array of string | | [_] | +| unsuppress | array of string | | [_] | +| transitive | boolean | | [_] | + +### Reanalyze-Analysis + +enum: | "dce" | "exception" | "termination" + +### Warnings + +| Parameter | JSON type | Remark | Implemented? | +| --------- | --------- | ------ | :----------: | +| number | string | | [x] | +| error | boolean | | [x] | +| error | string | | [x] | + +### Js-Post-Build + +| Parameter | JSON type | Remark | Implemented? | +| --------- | --------- | ------ | :----------: | +| cmd | string | | [_] | + +### Package-Spec + +| Parameter | JSON type | Remark | Implemented? | +| --------- | ------------- | ------ | :----------: | +| module | Module-Format | | [_] | +| in-source | boolean | | [x] | +| suffix | Suffix | | [_] | + +### Module-Format + +enum: "commonjs" | "es6" | "es6-global" + +### Suffix + +enum: ".js" | ".mjs" | ".cjs" | ".bs.js" | ".bs.mjs" | ".bs.cjs" + +### Reason + +| Parameter | JSON type | Remark | Implemented? | +| --------- | --------- | ------ | :----------: | +| react-jsx | number | | [x] | + +### Target-Item + +Not really usable by ReScript, likely to be removed. + +| Parameter | JSON type | Remark | Implemented? | +| --------- | ---------------- | ------ | :----------: | +| kind | Target-Item-Kind | | [_] | +| main | string | | [_] | + +### Target-Item-Kind + +enum: "native" | "bytecode" | "js" + +### Group + +What is this even for? The spec says it is not even implemented in ReScript. Likely to be removed. + +| Parameter | JSON type | Remark | Implemented? | +| --------- | --------- | ------ | :----------: | +| name | string | | [_] | +| hierarchy | boolean | | [_] | diff --git a/rewatch/README.md b/rewatch/README.md new file mode 100644 index 0000000000..522c811feb --- /dev/null +++ b/rewatch/README.md @@ -0,0 +1,118 @@ +# Rewatch + +## [![Release](https://github.com/rolandpeelen/rewatch/actions/workflows/build.yml/badge.svg?branch=master&event=release)](https://github.com/rolandpeelen/rewatch/actions/workflows/build.yml) + +# Info + +Rewatch is an alternative build system for the [Rescript Compiler](https://rescript-lang.org/) (which uses a combination of Ninja, OCaml and a Node.js script). It strives to deliver consistent and faster builds in monorepo setups. Bsb doesn't support a watch-mode in a monorepo setup, and when setting up a watcher that runs a global incremental compile it's consistent but very inefficient and thus slow. + +We couldn't find a way to improve this without re-architecting the whole build system. The benefit of having a specialized build system is that it's possible to completely tailor it to ReScript and not being dependent of the constraints of a generic build system like Ninja. This allowed us to have significant performance improvements even in non-monorepo setups (30% to 3x improvements reported). + +# Project Status + +This project should be considered in beta status. We run it in production at [Walnut](https://github.com/teamwalnut/). We're open to PR's and other contributions to make it 100% stable in the ReScript toolchain. + +# Usage + + 1. Install the package + + ``` + yarn add @rolandpeelen/rewatch + ``` + + 2. Build / Clean / Watch + + ``` + yarn rewatch build + ``` + + ``` + yarn rewatch clean + ``` + + ``` + yarn rewatch watch + ``` + + You can pass in the folder as the second argument where the 'root' `bsconfig.json` lives. If you encounter a 'stale build error', either directly, or after a while, a `clean` may be needed to clean up some old compiler assets. + +## Full Options + +Find this output by running `yarn rewatch --help`. + +``` +Rewatch is an alternative build system for the Rescript Compiler bsb (which uses Ninja internally). It strives to deliver consistent and faster builds in monorepo setups with multiple packages, where the default build system fails to pick up changed interfaces across multiple packages + +Usage: rewatch [OPTIONS] [COMMAND] [FOLDER] + +Arguments: + [COMMAND] + Possible values: + - build: Build using Rewatch + - watch: Build, then start a watcher + - clean: Clean the build artifacts + + [FOLDER] + The relative path to where the main rescript.json resides. IE - the root of your project + +Options: + -f, --filter + Filter allows for a regex to be supplied which will filter the files to be compiled. For instance, to filter out test files for compilation while doing feature work + + -a, --after-build + This allows one to pass an additional command to the watcher, which allows it to run when finished. For instance, to play a sound when done compiling, or to run a test suite. NOTE - You may need to add '--color=always' to your subcommand in case you want to output colour as well + + -n, --no-timing [] + [default: false] + [possible values: true, false] + + -v, --verbose... + Increase logging verbosity + + -q, --quiet... + Decrease logging verbosity + + -c, --create-sourcedirs [] + This creates a source_dirs.json file at the root of the monorepo, which is needed when you want to use Reanalyze + + [default: false] + [possible values: true, false] + + --compiler-args + This prints the compiler arguments. It expects the path to a rescript.json file. This also requires --bsc-path and --rescript-version to be present + + --dev [] + This is the flag to also compile development dependencies It's important to know that we currently do not discern between project src, and dependencies. So enabling this flag will enable building _all_ development dependencies of _all_ packages + + [default: false] + [possible values: true, false] + + --rescript-version + To be used in conjunction with compiler_args + + --bsc-path + A custom path to bsc + + -h, --help + Print help (see a summary with '-h') + + -V, --version + Print version + +``` + +# Contributing + + Pre-requisites: + + - [Rust](https://rustup.rs/) + - [NodeJS](https://nodejs.org/en/) - For running testscripts only + - [Yarn](https://yarnpkg.com/) or [Npm](https://www.npmjs.com/) - Npm probably comes with your node installation + + 1. `cd testrepo && yarn` (install dependencies for submodule) + 2. `cargo run` + + Running tests: + + 1. `cargo build --release` + 2. `./tests/suite.sh` diff --git a/rewatch/postinstall.js b/rewatch/postinstall.js new file mode 100644 index 0000000000..5b15cd4da3 --- /dev/null +++ b/rewatch/postinstall.js @@ -0,0 +1,55 @@ +const path = require("path"); +const fs = require("fs"); + +const installMacLinuxBinary = (binary) => { + const source = path.join(__dirname, binary); + if (fs.existsSync(source)) { + // mac and linux support extension-less executables + // so just overwrite the shell script + const target = path.join(__dirname, "rewatch"); + fs.renameSync(source, target); + + // The binary should be executable in the bundle, but just in case + fs.chmodSync(target, 0777); + } else { + // assume we're in dev mode - nothing will break if the script + // isn't overwritten, it will just be slower + } +}; + +const installWindowsBinary = () => { + const source = path.join(__dirname, "rewatch-windows.exe"); + if (fs.existsSync(source)) { + const target = path.join(__dirname, "rewatch.exe"); + fs.renameSync(source, target); + + // windows scripts use a different file extension to executables + // so we delete the script to make sure windows uses the exe now + const windowsScript = path.join(__dirname, "rewatch.cmd"); + fs.unlinkSync(windowsScript); + } else { + // assume we're in dev mode - nothing will break if the script + // isn't overwritten, it will just be slower + } +}; + +switch (process.platform) { + case "linux": + if (process.arch === "arm64") { + installMacLinuxBinary("rewatch-linux-arm64"); + } else { + installMacLinuxBinary("rewatch-linux"); + } + break; + case "darwin": + installMacLinuxBinary("rewatch-macos"); + break; + case "win32": + installWindowsBinary(); + break; + default: + // This won't break the installation because the shell script remains + // but that script will throw an error in this case anyway + console.warn(`No release available for "${process.platform}"`); + process.exit(1); +} diff --git a/rewatch/rewatch.cmd b/rewatch/rewatch.cmd new file mode 100644 index 0000000000..eac089856c --- /dev/null +++ b/rewatch/rewatch.cmd @@ -0,0 +1,3 @@ +@echo off +REM no need to branch on OS here, it will only be used on windows +%~dp0\rewatch-windows.exe %* diff --git a/rewatch/src/build.rs b/rewatch/src/build.rs index 92fb31c668..15f02de8b9 100644 --- a/rewatch/src/build.rs +++ b/rewatch/src/build.rs @@ -12,7 +12,6 @@ use crate::build::compile::{mark_modules_with_deleted_deps_dirty, mark_modules_w use crate::helpers::emojis::*; use crate::helpers::{self, get_workspace_root}; use crate::sourcedirs; -use ahash::AHashSet; use anyhow::{anyhow, Result}; use build_types::*; use console::style; @@ -59,6 +58,7 @@ pub fn get_compiler_args( path: &str, rescript_version: Option, bsc_path: Option, + build_dev_deps: bool, ) -> Result { let filename = &helpers::get_abs_path(path); let package_root = helpers::get_abs_path( @@ -72,14 +72,15 @@ pub fn get_compiler_args( rescript_version } else { let bsc_path = match bsc_path { - Some(bsc_path) => bsc_path, + Some(bsc_path) => helpers::get_abs_path(&bsc_path), None => helpers::get_bsc(&package_root, workspace_root.to_owned()), }; helpers::get_rescript_version(&bsc_path) }; + // make PathBuf from package root and get the relative path for filename let relative_filename = PathBuf::from(&filename) - .strip_prefix(PathBuf::from(&package_root).parent().unwrap()) + .strip_prefix(PathBuf::from(&package_root)) .unwrap() .to_string_lossy() .to_string(); @@ -107,7 +108,7 @@ pub fn get_compiler_args( let compiler_args = compiler_args( &rescript_config, &root_rescript_config, - &ast_path, + &ast_path.to_string_lossy(), &rescript_version, &relative_filename, is_interface, @@ -115,6 +116,7 @@ pub fn get_compiler_args( &package_root, &workspace_root, &None, + build_dev_deps, ); let result = serde_json::to_string_pretty(&CompilerArgs { @@ -131,23 +133,30 @@ pub fn initialize_build( show_progress: bool, path: &str, bsc_path: Option, + build_dev_deps: bool, ) -> Result { let project_root = helpers::get_abs_path(path); let workspace_root = helpers::get_workspace_root(&project_root); let bsc_path = match bsc_path { - Some(bsc_path) => bsc_path, + Some(bsc_path) => helpers::get_abs_path(&bsc_path), None => helpers::get_bsc(&project_root, workspace_root.to_owned()), }; - let root_config_name = packages::get_package_name(&project_root)?; + let root_config_name = packages::read_package_name(&project_root)?; let rescript_version = helpers::get_rescript_version(&bsc_path); if show_progress { - println!("{} {}Building package tree...", style("[1/7]").bold().dim(), TREE); + print!("{} {}Building package tree...", style("[1/7]").bold().dim(), TREE); let _ = stdout().flush(); } let timing_package_tree = Instant::now(); - let packages = packages::make(filter, &project_root, &workspace_root, show_progress)?; + let packages = packages::make( + filter, + &project_root, + &workspace_root, + show_progress, + build_dev_deps, + )?; let timing_package_tree_elapsed = timing_package_tree.elapsed(); if show_progress { @@ -169,7 +178,7 @@ pub fn initialize_build( let timing_source_files = Instant::now(); if show_progress { - println!( + print!( "{} {}Finding source files...", style("[2/7]").bold().dim(), LOOKING_GLASS @@ -199,7 +208,7 @@ pub fn initialize_build( .as_secs_f64() ); - println!( + print!( "{} {}Reading compile state...", style("[3/7]").bold().dim(), COMPILE_STATE @@ -221,7 +230,7 @@ pub fn initialize_build( .as_secs_f64() ); - println!( + print!( "{} {}Cleaning up previous build...", style("[4/7]").bold().dim(), SWEEP @@ -273,10 +282,11 @@ impl fmt::Display for IncrementalBuildError { pub fn incremental_build( build_state: &mut BuildState, default_timing: Option, - initial_build: bool, + _initial_build: bool, show_progress: bool, only_incremental: bool, create_sourcedirs: bool, + build_dev_deps: bool, ) -> Result<(), IncrementalBuildError> { logs::initialize(&build_state.packages); let num_dirty_modules = build_state.modules.values().filter(|m| is_dirty(m)).count() as u64; @@ -311,6 +321,7 @@ pub fn incremental_build( num_dirty_modules, default_timing.unwrap_or(timing_ast_elapsed).as_secs_f64() ); + pb.finish(); } } Err(err) => { @@ -323,9 +334,10 @@ pub fn incremental_build( CROSS, default_timing.unwrap_or(timing_ast_elapsed).as_secs_f64() ); + pb.finish(); } - log::error!("Could not parse source files: {}", &err); + println!("Could not parse source files: {}", &err); return Err(IncrementalBuildError::SourceFileParseError); } } @@ -344,17 +356,7 @@ pub fn incremental_build( ); } - // track the compile dirty state, we reset it when the compile fails - let mut tracked_dirty_modules = AHashSet::new(); - for (module_name, module) in build_state.modules.iter() { - if module.compile_dirty { - tracked_dirty_modules.insert(module_name.to_owned()); - } - } - if initial_build { - // repair broken state - mark_modules_with_expired_deps_dirty(build_state); - } + mark_modules_with_expired_deps_dirty(build_state); mark_modules_with_deleted_deps_dirty(build_state); current_step += 1; @@ -373,10 +375,23 @@ pub fn incremental_build( } else { ProgressBar::hidden() }; + pb.set_style( + ProgressStyle::with_template(&format!( + "{} {}Compiling... {{spinner}} {{pos}}/{{len}} {{msg}}", + format_step(current_step, total_steps), + SWORDS + )) + .unwrap(), + ); - let (compile_errors, compile_warnings, num_compiled_modules) = - compile::compile(build_state, || pb.inc(1), |size| pb.set_length(size)) - .map_err(|e| IncrementalBuildError::CompileError(Some(e.to_string())))?; + let (compile_errors, compile_warnings, num_compiled_modules) = compile::compile( + build_state, + show_progress, + || pb.inc(1), + |size| pb.set_length(size), + build_dev_deps, + ) + .map_err(|e| IncrementalBuildError::CompileError(Some(e.to_string())))?; let compile_duration = start_compiling.elapsed(); @@ -386,9 +401,6 @@ pub fn incremental_build( } pb.finish(); if !compile_errors.is_empty() { - if helpers::contains_ascii_characters(&compile_warnings) { - log::error!("{}", &compile_warnings); - } if show_progress { println!( "{}{} {}Compiled {} modules in {:.2}s", @@ -399,12 +411,11 @@ pub fn incremental_build( default_timing.unwrap_or(compile_duration).as_secs_f64() ); } - log::error!("{}", &compile_errors); - // mark the original files as dirty again, because we didn't complete a full build - for (module_name, module) in build_state.modules.iter_mut() { - if tracked_dirty_modules.contains(module_name) { - module.compile_dirty = true; - } + if helpers::contains_ascii_characters(&compile_warnings) { + println!("{}", &compile_warnings); + } + if helpers::contains_ascii_characters(&compile_errors) { + println!("{}", &compile_errors); } Err(IncrementalBuildError::CompileError(None)) } else { @@ -418,8 +429,9 @@ pub fn incremental_build( default_timing.unwrap_or(compile_duration).as_secs_f64() ); } + if helpers::contains_ascii_characters(&compile_warnings) { - log::warn!("{}", &compile_warnings); + println!("{}", &compile_warnings); } Ok(()) } @@ -433,7 +445,7 @@ pub fn incremental_build( pub fn write_build_ninja(build_state: &BuildState) { for package in build_state.packages.values() { // write empty file: - let mut f = File::create(std::path::Path::new(&package.get_bs_build_path()).join("build.ninja")) + let mut f = File::create(std::path::Path::new(&package.get_build_path()).join("build.ninja")) .expect("Unable to write file"); f.write_all(b"").expect("unable to write to ninja file"); } @@ -446,6 +458,7 @@ pub fn build( no_timing: bool, create_sourcedirs: bool, bsc_path: Option, + build_dev_deps: bool, ) -> Result { let default_timing: Option = if no_timing { Some(std::time::Duration::new(0.0 as u64, 0.0 as u32)) @@ -453,8 +466,15 @@ pub fn build( None }; let timing_total = Instant::now(); - let mut build_state = initialize_build(default_timing, filter, show_progress, path, bsc_path) - .map_err(|e| anyhow!("Could not initialize build. Error: {e}"))?; + let mut build_state = initialize_build( + default_timing, + filter, + show_progress, + path, + bsc_path, + build_dev_deps, + ) + .map_err(|e| anyhow!("Could not initialize build. Error: {e}"))?; match incremental_build( &mut build_state, @@ -463,6 +483,7 @@ pub fn build( show_progress, false, create_sourcedirs, + build_dev_deps, ) { Ok(_) => { if show_progress { diff --git a/rewatch/src/build/build_types.rs b/rewatch/src/build/build_types.rs index 95e9039673..51700e7d7c 100644 --- a/rewatch/src/build/build_types.rs +++ b/rewatch/src/build/build_types.rs @@ -70,6 +70,7 @@ pub struct Module { pub compile_dirty: bool, pub last_compiled_cmi: Option, pub last_compiled_cmt: Option, + pub deps_dirty: bool, } impl Module { diff --git a/rewatch/src/build/clean.rs b/rewatch/src/build/clean.rs index 8101c58498..ba53e4ff5e 100644 --- a/rewatch/src/build/clean.rs +++ b/rewatch/src/build/clean.rs @@ -70,16 +70,31 @@ pub fn clean_mjs_files(build_state: &BuildState) { .packages .get(&build_state.root_config_name) .expect("Could not find root package"); - Some(( - std::path::PathBuf::from(package.path.to_string()) - .join(&source_file.implementation.path) - .to_string_lossy() - .to_string(), - root_package.config.get_suffix(), - )) + + Some( + root_package + .config + .get_package_specs() + .iter() + .filter_map(|spec| { + if spec.in_source { + Some(( + std::path::PathBuf::from(package.path.to_string()) + .join(&source_file.implementation.path) + .to_string_lossy() + .to_string(), + root_package.config.get_suffix(spec), + )) + } else { + None + } + }) + .collect::>(), + ) } _ => None, }) + .flatten() .collect::>(); rescript_file_locations @@ -158,7 +173,11 @@ pub fn cleanup_previous_build( .get_mut(module_name) .expect("Could not find module for ast file"); - let compile_dirty = compile_assets_state.cmi_modules.get(module_name); + let compile_dirty = compile_assets_state.cmt_modules.get(module_name); + // if there is a new AST but it has not been compiled yet, we mark the module as compile dirty + // we do this by checking if the cmt file is newer than the AST file. We always compile the + // interface AND implementation. For some reason the CMI file is not always rewritten if it + // doesn't have any changes, that's why we just look at the CMT file. if let Some(compile_dirty) = compile_dirty { let last_modified = Some(ast_last_modified); @@ -319,13 +338,20 @@ pub fn cleanup_after_build(build_state: &BuildState) { }); } -pub fn clean(path: &str, show_progress: bool, bsc_path: Option) -> Result<()> { +pub fn clean(path: &str, show_progress: bool, bsc_path: Option, build_dev_deps: bool) -> Result<()> { let project_root = helpers::get_abs_path(path); let workspace_root = helpers::get_workspace_root(&project_root); - let packages = packages::make(&None, &project_root, &workspace_root, show_progress)?; - let root_config_name = packages::get_package_name(&project_root)?; + let packages = packages::make( + &None, + &project_root, + &workspace_root, + show_progress, + // Always clean dev dependencies + build_dev_deps, + )?; + let root_config_name = packages::read_package_name(&project_root)?; let bsc_path = match bsc_path { - Some(bsc_path) => bsc_path, + Some(bsc_path) => helpers::get_abs_path(&bsc_path), None => helpers::get_bsc(&project_root, workspace_root.to_owned()), }; @@ -333,7 +359,7 @@ pub fn clean(path: &str, show_progress: bool, bsc_path: Option) -> Resul let timing_clean_compiler_assets = Instant::now(); if show_progress { - println!( + print!( "{} {}Cleaning compiler assets...", style("[1/2]").bold().dim(), SWEEP @@ -342,7 +368,7 @@ pub fn clean(path: &str, show_progress: bool, bsc_path: Option) -> Resul }; packages.iter().for_each(|(_, package)| { if show_progress { - println!( + print!( "{}{} {}Cleaning {}...", LINE_CLEAR, style("[1/2]").bold().dim(), @@ -356,7 +382,7 @@ pub fn clean(path: &str, show_progress: bool, bsc_path: Option) -> Resul let path = std::path::Path::new(&path_str); let _ = std::fs::remove_dir_all(path); - let path_str = package.get_bs_build_path(); + let path_str = package.get_ocaml_build_path(); let path = std::path::Path::new(&path_str); let _ = std::fs::remove_dir_all(path); }); diff --git a/rewatch/src/build/compile.rs b/rewatch/src/build/compile.rs index e4cb17809e..73260ec6a9 100644 --- a/rewatch/src/build/compile.rs +++ b/rewatch/src/build/compile.rs @@ -8,9 +8,9 @@ use super::packages; use crate::config; use crate::helpers; use ahash::{AHashMap, AHashSet}; -use anyhow::{anyhow, Result}; +use anyhow::anyhow; use console::style; -use log::{debug, log_enabled, trace, Level::Info}; +use log::{debug, trace}; use rayon::prelude::*; use std::path::Path; use std::process::Command; @@ -18,9 +18,11 @@ use std::time::SystemTime; pub fn compile( build_state: &mut BuildState, + show_progress: bool, inc: impl Fn() + std::marker::Sync, set_length: impl Fn(u64), -) -> Result<(String, String, usize)> { + build_dev_deps: bool, +) -> anyhow::Result<(String, String, usize)> { let mut compiled_modules = AHashSet::::new(); let dirty_modules = build_state .modules @@ -146,7 +148,7 @@ pub fn compile( "cmi", ); - let cmi_digest = helpers::compute_file_hash(&cmi_path); + let cmi_digest = helpers::compute_file_hash(Path::new(&cmi_path)); let package = build_state .get_package(&module.package_name) @@ -160,7 +162,7 @@ pub fn compile( let result = compile_file( package, root_package, - &package.get_iast_path(&path), + &helpers::get_ast_path(&path).to_string_lossy(), module, &build_state.rescript_version, true, @@ -168,6 +170,7 @@ pub fn compile( &build_state.packages, &build_state.project_root, &build_state.workspace_root, + build_dev_deps, ); Some(result) } @@ -176,7 +179,7 @@ pub fn compile( let result = compile_file( package, root_package, - &package.get_ast_path(&source_file.implementation.path), + &helpers::get_ast_path(&source_file.implementation.path).to_string_lossy(), module, &build_state.rescript_version, false, @@ -184,8 +187,9 @@ pub fn compile( &build_state.packages, &build_state.project_root, &build_state.workspace_root, + build_dev_deps, ); - let cmi_digest_after = helpers::compute_file_hash(&cmi_path); + let cmi_digest_after = helpers::compute_file_hash(Path::new(&cmi_path)); // we want to compare both the hash of interface and the implementation // compile assets to verify that nothing changed. We also need to checke the interface @@ -212,7 +216,7 @@ pub fn compile( None } .inspect(|_res| { - if !(log_enabled!(Info)) { + if show_progress { inc(); } }) @@ -322,7 +326,7 @@ pub fn compile( if files_total_count == compile_universe_count { break; } - if in_progress_modules.len() == 0 || in_progress_modules.eq(¤t_in_progres_modules) { + if in_progress_modules.is_empty() || in_progress_modules.eq(¤t_in_progres_modules) { // find the dependency cycle let cycle = dependency_cycle::find( &compile_universe @@ -358,36 +362,12 @@ pub fn compiler_args( // if packages are known, we pass a reference here // this saves us a scan to find their paths packages: &Option<&AHashMap>, + build_dev_deps: bool, ) -> Vec { - let normal_deps = config.bs_dependencies.as_ref().unwrap_or(&vec![]).to_owned(); - let bsc_flags = config::flatten_flags(&config.bsc_flags); - // don't compile dev-deps yet - // let dev_deps = source - // .package - // .config - // .bs_dev_dependencies - // .as_ref() - // .unwrap_or(&vec![]) - // .to_owned(); - - let deps = [normal_deps] - .concat() - .par_iter() - .map(|package_name| { - let canonicalized_path = if let Some(packages) = packages { - packages - .get(package_name) - .expect("expect package") - .path - .to_string() - } else { - packages::read_dependency(package_name, project_root, project_root, workspace_root) - .expect("cannot find dep") - }; - vec!["-I".to_string(), packages::get_build_path(&canonicalized_path)] - }) - .collect::>>(); + + let dependency_paths = + get_dependency_paths(config, project_root, workspace_root, packages, build_dev_deps); let module_name = helpers::file_path_to_module_name(file_path, &config.get_namespace()); @@ -412,11 +392,8 @@ pub fn compiler_args( packages::Namespace::NoNamespace => vec![], }; - let jsx_args = root_config.get_jsx_args(); - let jsx_module_args = root_config.get_jsx_module_args(); - let jsx_mode_args = root_config.get_jsx_mode_args(); let uncurried_args = root_config.get_uncurried_args(version); - let gentype_arg = root_config.get_gentype_arg(); + let gentype_arg = config.get_gentype_arg(); let warning_args: Vec = match config.warnings.to_owned() { None => vec![], @@ -453,52 +430,152 @@ pub fn compiler_args( false => vec![], }; + let package_name_arg = vec!["-bs-package-name".to_string(), config.name.to_owned()]; + let implementation_args = if is_interface { debug!("Compiling interface file: {}", &module_name); vec![] } else { debug!("Compiling file: {}", &module_name); - - vec![ - "-bs-package-name".to_string(), - config.name.to_owned(), - "-bs-package-output".to_string(), - format!( - "{}:{}:{}", - root_config.get_module(), - Path::new(file_path).parent().unwrap().to_str().unwrap(), - root_config.get_suffix() - ), - ] + let specs = root_config.get_package_specs(); + + specs + .iter() + .map(|spec| { + return vec![ + "-bs-package-output".to_string(), + format!( + "{}:{}:{}", + spec.module, + if spec.in_source { + Path::new(file_path) + .parent() + .unwrap() + .to_str() + .unwrap() + .to_string() + } else { + format!( + "lib/{}", + Path::join( + Path::new(&spec.get_out_of_source_dir()), + Path::new(file_path).parent().unwrap() + ) + .to_str() + .unwrap() + ) + }, + root_config.get_suffix(spec), + ), + ]; + }) + .flatten() + .collect() }; vec![ namespace_args, read_cmi_args, - vec!["-I".to_string(), ".".to_string()], - deps.concat(), - gentype_arg, - jsx_args, - jsx_module_args, - jsx_mode_args, + vec!["-I".to_string(), "../ocaml".to_string()], + dependency_paths.concat(), uncurried_args, bsc_flags.to_owned(), warning_args, + gentype_arg, // vec!["-warn-error".to_string(), "A".to_string()], // ^^ this one fails for bisect-ppx // this is the default // we should probably parse the right ones from the package config // vec!["-w".to_string(), "a".to_string()], + package_name_arg, implementation_args, // vec![ // "-I".to_string(), // abs_node_modules_path.to_string() + "/rescript/ocaml", // ], + vec!["-bs-v".to_string(), format!("{}", version)], vec![ast_path.to_string()], ] .concat() } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +enum DependentPackage { + Normal(String), + Dev(String), +} + +impl DependentPackage { + fn name(&self) -> &str { + match self { + Self::Normal(name) => name, + Self::Dev(name) => name, + } + } + + fn is_dev(&self) -> bool { + match self { + Self::Normal(_) => false, + Self::Dev(_) => true, + } + } +} + +fn get_dependency_paths( + config: &config::Config, + project_root: &str, + workspace_root: &Option, + packages: &Option<&AHashMap>, + build_dev_deps: bool, +) -> Vec> { + let normal_deps = config + .bs_dependencies + .clone() + .unwrap_or_default() + .into_iter() + .map(DependentPackage::Normal) + .collect(); + let dev_deps = if build_dev_deps { + config + .bs_dev_dependencies + .clone() + .unwrap_or_default() + .into_iter() + .map(DependentPackage::Dev) + .collect() + } else { + vec![] + }; + + [dev_deps, normal_deps] + .concat() + .par_iter() + .filter_map(|dependent_package| { + let package_name = dependent_package.name(); + let dependency_path = if let Some(packages) = packages { + packages.get(package_name).map(|package| package.path.to_string()) + } else { + packages::read_dependency(package_name, project_root, project_root, workspace_root).ok() + } + .map(|canonicalized_path| { + vec![ + "-I".to_string(), + packages::get_ocaml_build_path(&canonicalized_path), + ] + }); + + if !dependent_package.is_dev() && dependency_path.is_none() { + panic!( + "Expected to find dependent package {} of {}", + package_name, config.name + ); + } + + dependency_path + }) + .collect::>>() +} + fn compile_file( package: &packages::Package, root_package: &packages::Package, @@ -510,14 +587,15 @@ fn compile_file( packages: &AHashMap, project_root: &str, workspace_root: &Option, -) -> Result> { + build_dev_deps: bool, +) -> Result, String> { + let ocaml_build_path_abs = package.get_ocaml_build_path(); let build_path_abs = package.get_build_path(); let implementation_file_path = match &module.source_type { SourceType::SourceFile(ref source_file) => Ok(&source_file.implementation.path), - sourcetype => Err(anyhow!( + sourcetype => Err(format!( "Tried to compile a file that is not a source file ({}). Path to AST: {}. ", - sourcetype, - ast_path + sourcetype, ast_path )), }?; let module_name = helpers::file_path_to_module_name(implementation_file_path, &package.namespace); @@ -533,6 +611,7 @@ fn compile_file( project_root, workspace_root, &Some(packages), + build_dev_deps, ); let to_mjs = Command::new(bsc_path) @@ -544,12 +623,11 @@ fn compile_file( Ok(x) if !x.status.success() => { let stderr = String::from_utf8_lossy(&x.stderr); let stdout = String::from_utf8_lossy(&x.stdout); - Err(anyhow!(stderr.to_string() + &stdout)) + Err(stderr.to_string() + &stdout) } - Err(e) => Err(anyhow!( + Err(e) => Err(format!( "Could not compile file. Error: {}. Path to AST: {:?}", - e, - ast_path + e, ast_path )), Ok(x) => { let err = std::str::from_utf8(&x.stderr) @@ -561,43 +639,69 @@ fn compile_file( // perhaps we can do this copying somewhere else if !is_interface { let _ = std::fs::copy( - build_path_abs.to_string() + "/" + &module_name + ".cmi", - std::path::Path::new(&package.get_bs_build_path()) + std::path::Path::new(&package.get_build_path()) .join(dir) // because editor tooling doesn't support namespace entries yet // we just remove the @ for now. This makes sure the editor support // doesn't break .join(module_name.to_owned() + ".cmi"), + ocaml_build_path_abs.to_string() + "/" + &module_name + ".cmi", ); let _ = std::fs::copy( - build_path_abs.to_string() + "/" + &module_name + ".cmj", - std::path::Path::new(&package.get_bs_build_path()) + std::path::Path::new(&package.get_build_path()) .join(dir) .join(module_name.to_owned() + ".cmj"), + ocaml_build_path_abs.to_string() + "/" + &module_name + ".cmj", ); let _ = std::fs::copy( - build_path_abs.to_string() + "/" + &module_name + ".cmt", - std::path::Path::new(&package.get_bs_build_path()) + std::path::Path::new(&package.get_build_path()) .join(dir) // because editor tooling doesn't support namespace entries yet // we just remove the @ for now. This makes sure the editor support // doesn't break .join(module_name.to_owned() + ".cmt"), + ocaml_build_path_abs.to_string() + "/" + &module_name + ".cmt", ); } else { let _ = std::fs::copy( - build_path_abs.to_string() + "/" + &module_name + ".cmti", - std::path::Path::new(&package.get_bs_build_path()) + std::path::Path::new(&package.get_build_path()) .join(dir) .join(module_name.to_owned() + ".cmti"), + ocaml_build_path_abs.to_string() + "/" + &module_name + ".cmti", + ); + let _ = std::fs::copy( + std::path::Path::new(&package.get_build_path()) + .join(dir) + .join(module_name.to_owned() + ".cmi"), + ocaml_build_path_abs.to_string() + "/" + &module_name + ".cmi", ); } + match &module.source_type { SourceType::SourceFile(SourceFile { interface: Some(Interface { path, .. }), .. - }) - | SourceType::SourceFile(SourceFile { + }) => { + // we need to copy the source file to the build directory. + // editor tools expects the source file in lib/bs for finding the current package + // and in lib/ocaml when referencing modules in other packages + let _ = std::fs::copy( + std::path::Path::new(&package.path).join(path), + std::path::Path::new(&package.get_build_path()).join(path), + ) + .expect("copying source file failed"); + + let _ = std::fs::copy( + std::path::Path::new(&package.path).join(path), + std::path::Path::new(&package.get_ocaml_build_path()) + .join(std::path::Path::new(path).file_name().unwrap()), + ) + .expect("copying source file failed"); + } + _ => (), + } + match &module.source_type { + SourceType::SourceFile(SourceFile { implementation: Implementation { path, .. }, .. }) => { @@ -606,13 +710,13 @@ fn compile_file( // and in lib/ocaml when referencing modules in other packages let _ = std::fs::copy( std::path::Path::new(&package.path).join(path), - std::path::Path::new(&package.get_bs_build_path()).join(path), + std::path::Path::new(&package.get_build_path()).join(path), ) .expect("copying source file failed"); let _ = std::fs::copy( std::path::Path::new(&package.path).join(path), - std::path::Path::new(&package.get_build_path()) + std::path::Path::new(&package.get_ocaml_build_path()) .join(std::path::Path::new(path).file_name().unwrap()), ) .expect("copying source file failed"); @@ -620,8 +724,35 @@ fn compile_file( _ => (), } + // copy js file + root_package.config.get_package_specs().iter().for_each(|spec| { + if spec.in_source { + match &module.source_type { + SourceType::SourceFile(SourceFile { + implementation: Implementation { path, .. }, + .. + }) => { + let source = helpers::get_source_file_from_rescript_file( + &std::path::Path::new(&package.path).join(path), + &root_package.config.get_suffix(spec), + ); + let destination = helpers::get_source_file_from_rescript_file( + &std::path::Path::new(&package.get_build_path()).join(path), + &root_package.config.get_suffix(spec), + ); + + if source.exists() { + let _ = + std::fs::copy(&source, &destination).expect("copying source file failed"); + } + } + _ => (), + } + } + }); + if helpers::contains_ascii_characters(&err) { - if package.is_pinned_dep { + if package.is_pinned_dep || package.is_local_dep { // supress warnings of external deps Ok(Some(err)) } else { @@ -667,7 +798,7 @@ pub fn mark_modules_with_expired_deps_dirty(build_state: &mut BuildState) { let dependent_module = build_state.modules.get(dependent).unwrap(); match dependent_module.source_type { SourceType::SourceFile(_) => { - match (module.last_compiled_cmt, module.last_compiled_cmi) { + match (module.last_compiled_cmt, module.last_compiled_cmt) { (None, None) | (Some(_), None) | (None, Some(_)) => { // println!( // "๐Ÿ›‘ {} is a dependent of {} but has no cmt/cmi", @@ -681,7 +812,7 @@ pub fn mark_modules_with_expired_deps_dirty(build_state: &mut BuildState) { // we compare the last compiled time of the dependent module with the last // compile of the interface of the module it depends on, if the interface // didn't change it doesn't matter - match (dependent_module.last_compiled_cmt, module.last_compiled_cmi) { + match (dependent_module.last_compiled_cmt, module.last_compiled_cmt) { (Some(last_compiled_dependent), Some(last_compiled)) => { if last_compiled_dependent < last_compiled { // println!( @@ -714,7 +845,7 @@ pub fn mark_modules_with_expired_deps_dirty(build_state: &mut BuildState) { let dependent_module = build_state.modules.get(dependent_of_namespace).unwrap(); if let (Some(last_compiled_dependent), Some(last_compiled)) = - (dependent_module.last_compiled_cmt, module.last_compiled_cmi) + (dependent_module.last_compiled_cmt, module.last_compiled_cmt) { if last_compiled_dependent < last_compiled { modules_with_expired_deps.insert(dependent.to_string()); diff --git a/rewatch/src/build/compile/dependency_cycle.rs b/rewatch/src/build/compile/dependency_cycle.rs index 072ca06743..b96ea8eb8d 100644 --- a/rewatch/src/build/compile/dependency_cycle.rs +++ b/rewatch/src/build/compile/dependency_cycle.rs @@ -1,71 +1,153 @@ use super::super::build_types::*; use crate::helpers; use ahash::AHashSet; +use std::collections::{HashMap, HashSet, VecDeque}; pub fn find(modules: &Vec<(&String, &Module)>) -> Vec { - let mut visited: AHashSet = AHashSet::new(); - let mut stack: Vec = vec![]; + find_shortest_cycle(modules) +} - // we want to sort the module names so that we always return the same - // dependency cycle (there can be more than one) - let mut module_names = modules - .iter() - .map(|(name, _)| name.to_string()) - .collect::>(); +fn find_shortest_cycle(modules: &Vec<(&String, &Module)>) -> Vec { + let mut shortest_cycle: Vec = Vec::new(); + + // Build a graph representation for easier traversal - module_names.sort(); - for module_name in module_names { - if find_dependency_cycle_helper(&module_name, modules, &mut visited, &mut stack) { - return stack; + let mut graph: HashMap<&String, &AHashSet> = HashMap::new(); + let mut in_degrees: HashMap<&String, usize> = HashMap::new(); + + let empty = AHashSet::new(); + // First pass: collect all nodes and initialize in-degrees + for (name, _) in modules { + graph.insert(name, &empty); + in_degrees.insert(name, 0); + } + + // Second pass: build the graph and count in-degrees + for (name, module) in modules { + // Update in-degrees + for dep in module.deps.iter() { + if let Some(count) = in_degrees.get_mut(dep) { + *count += 1; + } } - visited.clear(); - stack.clear(); + + // Update the graph + *graph.get_mut(*name).unwrap() = &module.deps; } - stack -} + // Remove all nodes in the graph that have no incoming edges + graph.retain(|_, deps| !deps.is_empty()); -fn find_dependency_cycle_helper( - module_name: &String, - modules: &Vec<(&String, &Module)>, - visited: &mut AHashSet, - stack: &mut Vec, -) -> bool { - if let Some(module) = modules - .iter() - .find(|(name, _)| *name == module_name) - .map(|(_, module)| module) - { - visited.insert(module_name.to_string()); - // if the module is a mlmap (namespace), we don't want to show this in the path - // because the namespace is not a module the user created, so only add source files - // to the stack - if let SourceType::SourceFile(_) = module.source_type { - stack.push(module_name.to_string()) + // OPTIMIZATION 1: Start with nodes that are more likely to be in cycles + // Sort nodes by their connectivity (in-degree + out-degree) + let mut start_nodes: Vec<&String> = graph.keys().cloned().collect(); + start_nodes.sort_by(|a, b| { + let a_connectivity = in_degrees.get(a).unwrap_or(&0) + graph.get(a).map_or(0, |v| v.len()); + let b_connectivity = in_degrees.get(b).unwrap_or(&0) + graph.get(b).map_or(0, |v| v.len()); + b_connectivity.cmp(&a_connectivity) // Sort in descending order + }); + + // OPTIMIZATION 2: Keep track of the current shortest cycle length for early termination + let mut current_shortest_length = usize::MAX; + + // OPTIMIZATION 3: Cache nodes that have been checked and don't have cycles + let mut no_cycle_cache: HashSet = HashSet::new(); + + // Try BFS from each node to find the shortest cycle + for start_node in start_nodes { + // Skip nodes that we know don't have cycles + if no_cycle_cache.contains(start_node) { + continue; } - for dep in &module.deps { - if !visited.contains(dep) { - if find_dependency_cycle_helper(dep, modules, visited, stack) { - return true; + + // Skip nodes with no incoming edges + if in_degrees.get(&start_node).map_or(true, |&d| d == 0) { + no_cycle_cache.insert(start_node.clone()); + continue; + } + + if let Some(cycle) = find_cycle_bfs(&start_node, &graph, current_shortest_length) { + if shortest_cycle.is_empty() || cycle.len() < shortest_cycle.len() { + shortest_cycle = cycle.clone(); + current_shortest_length = cycle.len(); + + // OPTIMIZATION 4: If we find a very short cycle (length <= 3), we can stop early + // as it's unlikely to find a shorter one + if cycle.len() <= 3 { + break; } - } else if stack.contains(dep) { - stack.push(dep.to_string()); - return true; } + } else { + // Cache this node as not having a cycle + no_cycle_cache.insert(start_node.to_string()); } - // because we only pushed source files to the stack, we also only need to - // pop these from the stack if we don't find a dependency cycle - if let SourceType::SourceFile(_) = module.source_type { - let _ = stack.pop(); + } + + shortest_cycle +} + +fn find_cycle_bfs( + start: &String, + graph: &HashMap<&String, &AHashSet>, + max_length: usize, +) -> Option> { + // Use a BFS to find the shortest cycle + let mut queue = VecDeque::new(); + // Store node -> (distance, parent) + let mut visited: HashMap)> = HashMap::new(); + + // Initialize with start node + visited.insert(start.clone(), (0, None)); + queue.push_back(start.clone()); + + while let Some(current) = queue.pop_front() { + let (dist, _) = *visited.get(¤t).unwrap(); + + // OPTIMIZATION: Early termination if we've gone too far + // If we're already at max_length, we won't find a shorter cycle from here + if dist >= max_length - 1 { + continue; + } + + // Check all neighbors + if let Some(neighbors) = graph.get(¤t) { + for neighbor in neighbors.iter() { + // If we found the start node again, we have a cycle + if neighbor == start { + // Reconstruct the cycle + let mut path = Vec::new(); + path.push(start.clone()); + + // Backtrack from current to start using parent pointers + let mut curr = current.clone(); + while curr != *start { + path.push(curr.clone()); + curr = visited.get(&curr).unwrap().1.clone().unwrap(); + } + + return Some(path); + } + + // If not visited, add to queue + if !visited.contains_key(neighbor) { + visited.insert(neighbor.clone(), (dist + 1, Some(current.clone()))); + queue.push_back(neighbor.clone()); + } + } } - return false; } - false + + None } pub fn format(cycle: &[String]) -> String { + let mut cycle = cycle.to_vec(); + cycle.reverse(); + // add the first module to the end of the cycle + cycle.push(cycle[0].clone()); + cycle .iter() .map(|s| helpers::format_namespaced_module_name(s)) .collect::>() - .join(" -> ") + .join("\n โ†’ ") } diff --git a/rewatch/src/build/deps.rs b/rewatch/src/build/deps.rs index 2ce82b39ca..59ddd3c2a7 100644 --- a/rewatch/src/build/deps.rs +++ b/rewatch/src/build/deps.rs @@ -1,5 +1,4 @@ use super::build_types::*; -use super::is_dirty; use super::packages; use crate::helpers; use ahash::AHashSet; @@ -10,8 +9,10 @@ fn get_dep_modules( namespace: Option, package_modules: &AHashSet, valid_modules: &AHashSet, + package: &packages::Package, ) -> AHashSet { let mut deps = AHashSet::new(); + let ast_file = package.get_build_path() + "/" + ast_file; if let Ok(lines) = helpers::read_lines(ast_file.to_string()) { // we skip the first line with is some null characters // the following lines in the AST are the dependency modules @@ -75,23 +76,25 @@ pub fn get_deps(build_state: &mut BuildState, deleted_modules: &AHashSet let package = build_state .get_package(&module.package_name) .expect("Package not found"); - let ast_path = package.get_ast_path(&source_file.implementation.path); - if is_dirty(module) || !build_state.deps_initialized { + let ast_path = helpers::get_ast_path(&source_file.implementation.path); + if module.deps_dirty || !build_state.deps_initialized { let mut deps = get_dep_modules( - &ast_path, + &ast_path.to_string_lossy(), package.namespace.to_suffix(), package.modules.as_ref().unwrap(), all_mod, + &package, ); if let Some(interface) = &source_file.interface { - let iast_path = package.get_iast_path(&interface.path); + let iast_path = helpers::get_ast_path(&interface.path); deps.extend(get_dep_modules( - &iast_path, + &iast_path.to_string_lossy(), package.namespace.to_suffix(), package.modules.as_ref().unwrap(), all_mod, + &package, )) } match &package.namespace { @@ -114,6 +117,7 @@ pub fn get_deps(build_state: &mut BuildState, deleted_modules: &AHashSet .for_each(|(module_name, deps)| { if let Some(module) = build_state.modules.get_mut(&module_name) { module.deps = deps.clone(); + module.deps_dirty = false; } deps.iter().for_each(|dep_name| { if let Some(module) = build_state.modules.get_mut(dep_name) { diff --git a/rewatch/src/build/logs.rs b/rewatch/src/build/logs.rs index 8f79afd802..5f3b8b4026 100644 --- a/rewatch/src/build/logs.rs +++ b/rewatch/src/build/logs.rs @@ -16,8 +16,8 @@ enum Location { fn get_log_file_path(package: &packages::Package, subfolder: Location) -> String { let build_folder = match subfolder { - Location::Bs => package.get_bs_build_path(), - Location::Ocaml => package.get_build_path(), + Location::Bs => package.get_build_path(), + Location::Ocaml => package.get_ocaml_build_path(), }; build_folder.to_owned() + "/.compiler.log" diff --git a/rewatch/src/build/packages.rs b/rewatch/src/build/packages.rs index c77334cf7c..d85f93f754 100644 --- a/rewatch/src/build/packages.rs +++ b/rewatch/src/build/packages.rs @@ -5,7 +5,7 @@ use crate::config; use crate::helpers; use crate::helpers::emojis::*; use ahash::{AHashMap, AHashSet}; -use anyhow::Result; +use anyhow::{anyhow, Result}; use console::style; use log::{debug, error}; use rayon::prelude::*; @@ -59,22 +59,43 @@ pub struct Package { pub path: String, pub dirs: Option>, pub is_pinned_dep: bool, + pub is_local_dep: bool, pub is_root: bool, } pub fn get_build_path(canonical_path: &str) -> String { + format!("{}/lib/bs", canonical_path) +} + +pub fn get_js_path(canonical_path: &str) -> String { + format!("{}/lib/js", canonical_path) +} + +pub fn get_es6_path(canonical_path: &str) -> String { + format!("{}/lib/es6", canonical_path) +} + +pub fn get_ocaml_build_path(canonical_path: &str) -> String { format!("{}/lib/ocaml", canonical_path) } impl Package { - pub fn get_bs_build_path(&self) -> String { - format!("{}/lib/bs", self.path) + pub fn get_ocaml_build_path(&self) -> String { + get_ocaml_build_path(&self.path) } pub fn get_build_path(&self) -> String { get_build_path(&self.path) } + pub fn get_js_path(&self) -> String { + get_js_path(&self.path) + } + + pub fn get_es6_path(&self) -> String { + get_es6_path(&self.path) + } + pub fn get_mlmap_path(&self) -> String { self.get_build_path() + "/" @@ -94,14 +115,6 @@ impl Package { .expect("namespace should be set for mlmap module") + ".cmi" } - - pub fn get_ast_path(&self, source_file: &str) -> String { - helpers::get_compiler_asset(self, &packages::Namespace::NoNamespace, source_file, "ast") - } - - pub fn get_iast_path(&self, source_file: &str) -> String { - helpers::get_compiler_asset(self, &packages::Namespace::NoNamespace, source_file, "iast") - } } impl PartialEq for Package { @@ -377,6 +390,25 @@ fn flatten_dependencies(dependencies: Vec) -> Vec { flattened } +pub fn read_package_name(package_dir: &str) -> Result { + let package_json_path = if package_dir.is_empty() { + "package.json".to_string() + } else { + format!("{}/package.json", package_dir) + }; + + let package_json_contents = + fs::read_to_string(&package_json_path).map_err(|e| anyhow!("Could not read package.json: {}", e))?; + + let package_json: serde_json::Value = serde_json::from_str(&package_json_contents) + .map_err(|e| anyhow!("Could not parse package.json: {}", e))?; + + package_json["name"] + .as_str() + .map(|s| s.to_string()) + .ok_or_else(|| anyhow!("No name field found in package.json")) +} + fn make_package(config: config::Config, package_path: &str, is_pinned_dep: bool, is_root: bool) -> Package { let source_folders = match config.sources.to_owned() { Some(config::OneOrMore::Single(source)) => get_source_dirs(source, None), @@ -399,8 +431,9 @@ fn make_package(config: config::Config, package_path: &str, is_pinned_dep: bool, } }; + let package_name = read_package_name(package_path).expect("Could not read package name"); Package { - name: config.name.to_owned(), + name: package_name, config: config.to_owned(), source_folders, source_files: None, @@ -414,6 +447,7 @@ fn make_package(config: config::Config, package_path: &str, is_pinned_dep: bool, .to_string(), dirs: None, is_pinned_dep, + is_local_dep: !package_path.contains("node_modules"), is_root, } } @@ -427,10 +461,8 @@ fn read_packages( // Store all packages and completely deduplicate them let mut map: AHashMap = AHashMap::new(); - map.insert( - root_config.name.to_owned(), - make_package(root_config.to_owned(), project_root, false, true), - ); + let root_package = make_package(root_config.to_owned(), project_root, false, true); + map.insert(root_package.name.to_string(), root_package); let mut registered_dependencies_set: AHashSet = AHashSet::new(); let dependencies = flatten_dependencies(read_dependencies( @@ -443,10 +475,8 @@ fn read_packages( )); dependencies.iter().for_each(|d| { if !map.contains_key(&d.name) { - map.insert( - d.name.to_owned(), - make_package(d.config.to_owned(), &d.path, d.is_pinned, false), - ); + let package = make_package(d.config.to_owned(), &d.path, d.is_pinned, false); + map.insert(package.name.to_string(), package); } }); @@ -466,6 +496,7 @@ pub fn get_source_files( package_dir: &Path, filter: &Option, source: &config::PackageSource, + build_dev_deps: bool, ) -> AHashMap { let mut map: AHashMap = AHashMap::new(); @@ -479,24 +510,19 @@ pub fn get_source_files( }; let path_dir = Path::new(&source.dir); - // don't include dev sources for now - if type_ != &Some("dev".to_string()) { - match read_folders(filter, package_dir, path_dir, recurse) { + match (build_dev_deps, type_) { + (false, Some(type_)) if type_ == "dev" => (), + _ => match read_folders(filter, package_dir, path_dir, recurse) { Ok(files) => map.extend(files), - // Err(_e) if type_ == &Some("dev".to_string()) => { - // log::warn!( - // "Could not read folder: {}... Probably ok as type is dev", - // path_dir.to_string_lossy() - // ) - // } + Err(_e) => log::error!( "Could not read folder: {:?}. Specified in dependency: {}, located {:?}...", path_dir.to_path_buf().into_os_string(), package_name, package_dir ), - } - } + }, + }; map } @@ -506,13 +532,22 @@ pub fn get_source_files( fn extend_with_children( filter: &Option, mut build: AHashMap, + build_dev_deps: bool, ) -> AHashMap { for (_key, package) in build.iter_mut() { let mut map: AHashMap = AHashMap::new(); package .source_folders .par_iter() - .map(|source| get_source_files(&package.name, Path::new(&package.path), filter, source)) + .map(|source| { + get_source_files( + &package.name, + Path::new(&package.path), + filter, + source, + build_dev_deps, + ) + }) .collect::>>() .into_iter() .for_each(|source| map.extend(source)); @@ -554,30 +589,17 @@ pub fn make( root_folder: &str, workspace_root: &Option, show_progress: bool, + build_dev_deps: bool, ) -> Result> { let map = read_packages(root_folder, workspace_root.to_owned(), show_progress)?; /* Once we have the deduplicated packages, we can add the source files for each - to minimize * the IO */ - let result = extend_with_children(filter, map); - - result.values().for_each(|package| { - if let Some(dirs) = &package.dirs { - dirs.iter().for_each(|dir| { - let _ = std::fs::create_dir_all(std::path::Path::new(&package.get_bs_build_path()).join(dir)); - }) - } - }); + let result = extend_with_children(filter, map, build_dev_deps); Ok(result) } -pub fn get_package_name(path: &str) -> Result { - let config = read_config(path)?; - - Ok(config.name) -} - pub fn parse_packages(build_state: &mut BuildState) { build_state .packages @@ -589,9 +611,49 @@ pub fn parse_packages(build_state: &mut BuildState) { build_state.module_names.extend(package_modules) } let build_path_abs = package.get_build_path(); - let bs_build_path = package.get_bs_build_path(); - helpers::create_build_path(&build_path_abs); - helpers::create_build_path(&bs_build_path); + let bs_build_path = package.get_ocaml_build_path(); + helpers::create_path(&build_path_abs); + helpers::create_path(&bs_build_path); + let root_config = build_state + .get_package(&build_state.root_config_name) + .expect("cannot find root config"); + + root_config.config.get_package_specs().iter().for_each(|spec| { + if !spec.in_source { + // we don't want to calculate this if we don't have out of source specs + // we do this twice, but we almost never have multiple package specs + // so this optimization is less important + let relative_dirs: AHashSet = match &package.source_files { + Some(source_files) => source_files + .keys() + .map(|source_file| { + Path::new(source_file) + .parent() + .expect("parent dir not found") + .to_owned() + }) + .collect(), + _ => AHashSet::new(), + }; + if spec.is_common_js() { + helpers::create_path(&package.get_js_path()); + relative_dirs.iter().for_each(|path_buf| { + helpers::create_path_for_path(&Path::join( + &PathBuf::from(package.get_js_path()), + path_buf, + )) + }) + } else { + helpers::create_path(&package.get_es6_path()); + relative_dirs.iter().for_each(|path_buf| { + helpers::create_path_for_path(&Path::join( + &PathBuf::from(package.get_es6_path()), + path_buf, + )) + }) + } + } + }); package.namespace.to_suffix().iter().for_each(|namespace| { // generate the mlmap "AST" file for modules that have a namespace configured @@ -645,6 +707,7 @@ pub fn parse_packages(build_state: &mut BuildState) { build_state.insert_module( &helpers::file_path_to_module_name(&mlmap.to_owned(), &packages::Namespace::NoNamespace), Module { + deps_dirty: false, source_type: SourceType::MlMap(MlMap { parse_dirty: false }), deps, dependents: AHashSet::new(), @@ -685,6 +748,7 @@ pub fn parse_packages(build_state: &mut BuildState) { } }) .or_insert(Module { + deps_dirty: true, source_type: SourceType::SourceFile(SourceFile { implementation: Implementation { path: file.to_owned(), @@ -732,6 +796,7 @@ pub fn parse_packages(build_state: &mut BuildState) { } }) .or_insert(Module { + deps_dirty: true, source_type: SourceType::SourceFile(SourceFile { // this will be overwritten later implementation: Implementation { @@ -803,7 +868,7 @@ fn get_unallowed_dependents( struct UnallowedDependency { bs_deps: Vec, pinned_deps: Vec, - bs_dev_deps: Vec, + bs_build_dev_deps: Vec, } pub fn validate_packages_dependencies(packages: &AHashMap) -> bool { @@ -827,7 +892,7 @@ pub fn validate_packages_dependencies(packages: &AHashMap) -> b let empty_unallowed_deps = UnallowedDependency { bs_deps: vec![], pinned_deps: vec![], - bs_dev_deps: vec![], + bs_build_dev_deps: vec![], }; let unallowed_dependency = detected_unallowed_dependencies.entry(String::from(package_name)); @@ -835,7 +900,7 @@ pub fn validate_packages_dependencies(packages: &AHashMap) -> b match *dependency_type { "bs-dependencies" => value.bs_deps.push(unallowed_dependency_name), "pinned-dependencies" => value.pinned_deps.push(unallowed_dependency_name), - "bs-dev-dependencies" => value.bs_dev_deps.push(unallowed_dependency_name), + "bs-dev-dependencies" => value.bs_build_dev_deps.push(unallowed_dependency_name), _ => (), } } @@ -851,7 +916,7 @@ pub fn validate_packages_dependencies(packages: &AHashMap) -> b [ ("bs-dependencies", unallowed_deps.bs_deps.to_owned()), ("pinned-dependencies", unallowed_deps.pinned_deps.to_owned()), - ("bs-dev-dependencies", unallowed_deps.bs_dev_deps.to_owned()), + ("bs-dev-dependencies", unallowed_deps.bs_build_dev_deps.to_owned()), ] .iter() .for_each(|(deps_type, map)| { @@ -887,7 +952,7 @@ mod test { name: String, bs_deps: Vec, pinned_deps: Vec, - dev_deps: Vec, + build_dev_deps: Vec, allowed_dependents: Option>, ) -> Package { Package { @@ -902,7 +967,7 @@ mod test { suffix: None, pinned_dependencies: Some(pinned_deps), bs_dependencies: Some(bs_deps), - bs_dev_dependencies: Some(dev_deps), + bs_dev_dependencies: Some(build_dev_deps), ppx_flags: None, bsc_flags: None, reason: None, @@ -921,6 +986,7 @@ mod test { dirs: None, is_pinned_dep: false, is_root: false, + is_local_dep: false, } } #[test] diff --git a/rewatch/src/build/parse.rs b/rewatch/src/build/parse.rs index b8a344941a..b4fddd72f2 100644 --- a/rewatch/src/build/parse.rs +++ b/rewatch/src/build/parse.rs @@ -29,7 +29,12 @@ pub fn generate_asts( match &module.source_type { SourceType::MlMap(_mlmap) => { let path = package.get_mlmap_path(); - (module_name.to_owned(), Ok((path, None)), Ok(None), false) + ( + module_name.to_owned(), + Ok((Path::new(&path).to_path_buf(), None)), + Ok(None), + false, + ) } SourceType::SourceFile(source_file) => { @@ -69,13 +74,20 @@ pub fn generate_asts( } else { ( Ok(( - helpers::get_basename(&source_file.implementation.path).to_string() + ".ast", + Path::new( + &(helpers::get_basename(&source_file.implementation.path).to_string() + + ".ast"), + ) + .to_path_buf(), None, )), - Ok(source_file - .interface - .as_ref() - .map(|i| (helpers::get_basename(&i.path).to_string() + ".iast", None))), + Ok(source_file.interface.as_ref().map(|i| { + ( + Path::new(&(helpers::get_basename(&i.path).to_string() + ".iast")) + .to_path_buf(), + None, + ) + })), false, ) }; @@ -86,8 +98,8 @@ pub fn generate_asts( }) .collect::), String>, - Result)>, String>, + Result<(PathBuf, Option), String>, + Result)>, String>, bool, )>>() .into_iter() @@ -98,6 +110,7 @@ pub fn generate_asts( // the compile_dirty flag if it was set before if is_dirty { module.compile_dirty = true; + module.deps_dirty = true; } let package = build_state .packages @@ -113,9 +126,6 @@ pub fn generate_asts( Ok((_path, Some(stderr_warnings))) if package.is_pinned_dep => { source_file.implementation.parse_state = ParseState::Warning; source_file.implementation.parse_dirty = true; - if let Some(interface) = source_file.interface.as_mut() { - interface.parse_dirty = false; - } logs::append(package, &stderr_warnings); stderr.push_str(&stderr_warnings); } @@ -124,9 +134,6 @@ pub fn generate_asts( // dependency (so some external dep). We can ignore those source_file.implementation.parse_state = ParseState::Success; source_file.implementation.parse_dirty = false; - if let Some(interface) = source_file.interface.as_mut() { - interface.parse_dirty = false; - } } Err(err) => { // Some compilation error @@ -198,32 +205,31 @@ pub fn generate_asts( // probably better to do this in a different function // specific to compiling mlmaps let compile_path = package.get_mlmap_compile_path(); - let mlmap_hash = helpers::compute_file_hash(&compile_path); + let mlmap_hash = helpers::compute_file_hash(&Path::new(&compile_path)); namespaces::compile_mlmap(package, module_name, &build_state.bsc_path); - let mlmap_hash_after = helpers::compute_file_hash(&compile_path); + let mlmap_hash_after = helpers::compute_file_hash(&Path::new(&compile_path)); let suffix = package .namespace .to_suffix() .expect("namespace should be set for mlmap module"); - // copy the mlmap to the bs build path for editor tooling let base_build_path = package.get_build_path() + "/" + &suffix; - let base_bs_build_path = package.get_bs_build_path() + "/" + &suffix; + let base_ocaml_build_path = package.get_ocaml_build_path() + "/" + &suffix; let _ = std::fs::copy( base_build_path.to_string() + ".cmi", - base_bs_build_path.to_string() + ".cmi", + base_ocaml_build_path.to_string() + ".cmi", ); let _ = std::fs::copy( base_build_path.to_string() + ".cmt", - base_bs_build_path.to_string() + ".cmt", + base_ocaml_build_path.to_string() + ".cmt", ); let _ = std::fs::copy( base_build_path.to_string() + ".cmj", - base_bs_build_path.to_string() + ".cmj", + base_ocaml_build_path.to_string() + ".cmj", ); let _ = std::fs::copy( base_build_path.to_string() + ".mlmap", - base_bs_build_path.to_string() + ".mlmap", + base_ocaml_build_path.to_string() + ".mlmap", ); match (mlmap_hash, mlmap_hash_after) { (Some(digest), Some(digest_after)) => !digest.eq(&digest_after), @@ -255,11 +261,9 @@ pub fn parser_args( workspace_root: &Option, root_path: &str, contents: &str, -) -> (String, Vec) { +) -> (PathBuf, Vec) { let file = &filename.to_string(); - let path = PathBuf::from(filename); - let ast_extension = path_to_ast_extension(&path); - let ast_path = (helpers::get_basename(&file.to_string()).to_owned()) + ast_extension; + let ast_path = helpers::get_ast_path(file); let ppx_flags = config::flatten_ppx_flags( &if let Some(workspace_root) = workspace_root { format!("{}/node_modules", &workspace_root) @@ -277,7 +281,7 @@ pub fn parser_args( let file = "../../".to_string() + file; ( - ast_path.to_string(), + ast_path.to_owned(), [ vec!["-bs-v".to_string(), format!("{}", version)], ppx_flags, @@ -290,7 +294,7 @@ pub fn parser_args( "-absname".to_string(), "-bs-ast".to_string(), "-o".to_string(), - ast_path.to_string(), + ast_path.to_string_lossy().to_string(), file, ], ] @@ -305,7 +309,7 @@ fn generate_ast( version: &str, bsc_path: &str, workspace_root: &Option, -) -> Result<(String, Option), String> { +) -> Result<(PathBuf, Option), String> { let file_path = PathBuf::from(&package.path).join(filename); let contents = helpers::read_file(&file_path).expect("Error reading file"); @@ -320,6 +324,9 @@ fn generate_ast( &contents, ); + // generate the dir of the ast_path (it mirrors the source file dir) + helpers::create_path(&(package.get_build_path() + "/" + &ast_path.parent().unwrap().to_string_lossy())); + /* Create .ast */ let result = if let Some(res_to_ast) = Some( Command::new(bsc_path) @@ -347,26 +354,14 @@ fn generate_ast( )) }; if let Ok((ast_path, _)) = &result { - let dir = std::path::Path::new(filename).parent().unwrap(); let _ = std::fs::copy( - build_path_abs.to_string() + "/" + ast_path, - std::path::Path::new(&package.get_bs_build_path()) - .join(dir) - .join(ast_path), + Path::new(&build_path_abs).join(&ast_path), + std::path::Path::new(&package.get_ocaml_build_path()).join(ast_path.file_name().unwrap()), ); } result } -fn path_to_ast_extension(path: &Path) -> &str { - let extension = path.extension().unwrap().to_str().unwrap(); - if helpers::is_interface_ast_file(extension) { - ".iast" - } else { - ".ast" - } -} - fn include_ppx(flag: &str, contents: &str) -> bool { if flag.contains("bisect") { return std::env::var("BISECT_ENABLE").is_ok(); diff --git a/rewatch/src/build/read_compile_state.rs b/rewatch/src/build/read_compile_state.rs index b6cbc9a3aa..4bfc3e29fc 100644 --- a/rewatch/src/build/read_compile_state.rs +++ b/rewatch/src/build/read_compile_state.rs @@ -52,7 +52,7 @@ pub fn read(build_state: &mut BuildState) -> CompileAssetsState { .packages .par_iter() .map(|(_, package)| { - let read_dir = fs::read_dir(std::path::Path::new(&package.get_build_path())).unwrap(); + let read_dir = fs::read_dir(std::path::Path::new(&package.get_ocaml_build_path())).unwrap(); read_dir .filter_map(|entry| match entry { Ok(entry) => { @@ -103,7 +103,9 @@ pub fn read(build_state: &mut BuildState) -> CompileAssetsState { last_modified: last_modified.to_owned(), ast_file_path, is_root: *package_is_root, - suffix: root_package.config.get_suffix(), + suffix: root_package + .config + .get_suffix(root_package.config.get_package_specs().first().unwrap()), }, ); let _ = ast_rescript_file_locations.insert(res_file_path); diff --git a/rewatch/src/config.rs b/rewatch/src/config.rs index c575b90e25..7bcbda2e51 100644 --- a/rewatch/src/config.rs +++ b/rewatch/src/config.rs @@ -111,6 +111,27 @@ pub struct PackageSpec { pub suffix: Option, } +impl PackageSpec { + pub fn get_out_of_source_dir(&self) -> String { + match self.module.as_str() { + "commonjs" => "js", + _ => "es6", + } + .to_string() + } + + pub fn is_common_js(&self) -> bool { + match self.module.as_str() { + "commonjs" => true, + _ => false, + } + } + + pub fn get_suffix(&self) -> Option { + self.suffix.to_owned() + } +} + #[derive(Deserialize, Debug, Clone)] #[serde(untagged)] pub enum Error { @@ -182,13 +203,13 @@ pub struct Config { pub suffix: Option, #[serde(rename = "pinned-dependencies")] pub pinned_dependencies: Option>, - #[serde(rename = "bs-dependencies")] + #[serde(rename = "dependencies", alias = "bs-dependencies")] pub bs_dependencies: Option>, - #[serde(rename = "bs-dev-dependencies")] + #[serde(rename = "bs-dev-dependencies", alias = "dev-dependencies")] pub bs_dev_dependencies: Option>, #[serde(rename = "ppx-flags")] pub ppx_flags: Option>>, - #[serde(rename = "bsc-flags")] + #[serde(rename = "bsc-flags", alias = "compiler-flags")] pub bsc_flags: Option>>, pub reason: Option, pub namespace: Option, @@ -287,11 +308,32 @@ fn check_if_rescript11_or_higher(version: &str) -> Result { } fn namespace_from_package_name(package_name: &str) -> String { - package_name - .to_owned() - .replace('@', "") - .replace('/', "_") - .to_case(Case::Pascal) + let len = package_name.len(); + let mut buf = String::with_capacity(len); + + fn aux(s: &str, capital: bool, buf: &mut String, off: usize) { + if off >= s.len() { + return; + } + + let ch = s.as_bytes()[off] as char; + match ch { + 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => { + let new_capital = false; + buf.push(if capital { ch.to_ascii_uppercase() } else { ch }); + aux(s, new_capital, buf, off + 1); + } + '/' | '-' => { + aux(s, true, buf, off + 1); + } + _ => { + aux(s, capital, buf, off + 1); + } + } + } + + aux(package_name, true, &mut buf, 0); + buf } impl Config { @@ -312,7 +354,7 @@ impl Config { namespace if namespace.is_case(Case::UpperFlat) => { packages::Namespace::Namespace(namespace.to_string()) } - namespace => packages::Namespace::Namespace(namespace.to_string().to_case(Case::Pascal)), + namespace => packages::Namespace::Namespace(namespace_from_package_name(namespace)), }, (Some(self::NamespaceConfig::String(str)), Some(entry)) => match str.as_str() { "true" => packages::Namespace::NamespaceWithEntry { @@ -396,36 +438,29 @@ impl Config { } } - pub fn get_module(&self) -> String { - match &self.package_specs { - Some(OneOrMore::Single(PackageSpec { module, .. })) => module.to_string(), - Some(OneOrMore::Multiple(vec)) => match vec.first() { - Some(PackageSpec { module, .. }) => module.to_string(), - None => "commonjs".to_string(), - }, - _ => "commonjs".to_string(), + pub fn get_gentype_arg(&self) -> Vec { + match &self.gentype_config { + Some(_) => vec!["-bs-gentype".to_string()], + None => vec![], } } - pub fn get_suffix(&self) -> String { - match &self.package_specs { - Some(OneOrMore::Single(PackageSpec { suffix, .. })) => suffix.to_owned(), - Some(OneOrMore::Multiple(vec)) => match vec.first() { - Some(PackageSpec { suffix, .. }) => suffix.to_owned(), - None => None, - }, - - _ => None, + pub fn get_package_specs(&self) -> Vec { + match self.package_specs.clone() { + None => vec![PackageSpec { + module: "commonjs".to_string(), + in_source: true, + suffix: Some(".js".to_string()), + }], + Some(OneOrMore::Single(spec)) => vec![spec], + Some(OneOrMore::Multiple(vec)) => vec, } - .or(self.suffix.to_owned()) - .unwrap_or(".js".to_string()) } - pub fn get_gentype_arg(&self) -> Vec { - match &self.gentype_config { - Some(_) => vec!["-bs-gentype".to_string()], - None => vec![], - } + pub fn get_suffix(&self, spec: &PackageSpec) -> String { + spec.get_suffix() + .or(self.suffix.clone()) + .unwrap_or(".js".to_string()) } } @@ -447,8 +482,11 @@ mod tests { "#; let config = serde_json::from_str::(json).unwrap(); - assert_eq!(config.get_suffix(), ".mjs"); - assert_eq!(config.get_module(), "es6"); + let specs = config.get_package_specs(); + assert_eq!(specs.len(), 1); + let spec = specs.first().unwrap(); + assert_eq!(spec.module, "es6"); + assert_eq!(config.get_suffix(spec), ".mjs"); } #[test] @@ -484,6 +522,40 @@ mod tests { } } + #[test] + fn test_dev_sources_multiple() { + let json = r#" + { + "name": "@rescript/core", + "version": "0.5.0", + "sources": [ + { "dir": "src" }, + { "dir": "test", "type": "dev" } + ], + "package-specs": { + "module": "esmodule", + "in-source": true + }, + "bs-dev-dependencies": ["@rescript/tools"], + "suffix": ".mjs", + "warnings": { + "error": "+101" + } + } + "#; + + let config = serde_json::from_str::(json).unwrap(); + if let Some(OneOrMore::Multiple(sources)) = config.sources { + assert_eq!(sources.len(), 2); + let test_dir = sources[1].to_qualified_without_children(None); + + assert_eq!(test_dir.type_, Some(String::from("dev"))); + } else { + dbg!(config.sources); + unreachable!() + } + } + #[test] fn test_detect_gentypeconfig() { let json = r#" @@ -535,6 +607,134 @@ mod tests { ); } + #[test] + fn test_get_suffix() { + let json = r#" + { + "name": "testrepo", + "sources": { + "dir": "src", + "subdirs": true + }, + "package-specs": [ + { + "module": "es6", + "in-source": true + } + ], + "suffix": ".mjs" + } + "#; + + let config = serde_json::from_str::(json).unwrap(); + assert_eq!( + config.get_suffix(&config.get_package_specs().first().unwrap()), + ".mjs" + ); + } + + #[test] + fn test_dependencies() { + let json = r#" + { + "name": "testrepo", + "sources": { + "dir": "src", + "subdirs": true + }, + "package-specs": [ + { + "module": "es6", + "in-source": true + } + ], + "suffix": ".mjs", + "bs-dependencies": [ "@testrepo/main" ] + } + "#; + + let config = serde_json::from_str::(json).unwrap(); + assert_eq!(config.bs_dependencies, Some(vec!["@testrepo/main".to_string()])); + } + + #[test] + fn test_dependencies_alias() { + let json = r#" + { + "name": "testrepo", + "sources": { + "dir": "src", + "subdirs": true + }, + "package-specs": [ + { + "module": "es6", + "in-source": true + } + ], + "suffix": ".mjs", + "dependencies": [ "@testrepo/main" ] + } + "#; + + let config = serde_json::from_str::(json).unwrap(); + assert_eq!(config.bs_dependencies, Some(vec!["@testrepo/main".to_string()])); + } + + #[test] + fn test_dev_dependencies() { + let json = r#" + { + "name": "testrepo", + "sources": { + "dir": "src", + "subdirs": true + }, + "package-specs": [ + { + "module": "es6", + "in-source": true + } + ], + "suffix": ".mjs", + "bs-dev-dependencies": [ "@testrepo/main" ] + } + "#; + + let config = serde_json::from_str::(json).unwrap(); + assert_eq!( + config.bs_dev_dependencies, + Some(vec!["@testrepo/main".to_string()]) + ); + } + + #[test] + fn test_dev_dependencies_alias() { + let json = r#" + { + "name": "testrepo", + "sources": { + "dir": "src", + "subdirs": true + }, + "package-specs": [ + { + "module": "es6", + "in-source": true + } + ], + "suffix": ".mjs", + "dev-dependencies": [ "@testrepo/main" ] + } + "#; + + let config = serde_json::from_str::(json).unwrap(); + assert_eq!( + config.bs_dev_dependencies, + Some(vec!["@testrepo/main".to_string()]) + ); + } + #[test] fn test_check_if_rescript11_or_higher() { assert_eq!(check_if_rescript11_or_higher("11.0.0"), Ok(true)); diff --git a/rewatch/src/helpers.rs b/rewatch/src/helpers.rs index 0f1e76da07..58fb734154 100644 --- a/rewatch/src/helpers.rs +++ b/rewatch/src/helpers.rs @@ -25,12 +25,12 @@ pub mod emojis { pub static COMMAND: Emoji<'_, '_> = Emoji("๐Ÿƒ ", ""); pub static TREE: Emoji<'_, '_> = Emoji("๐Ÿ“ฆ ", ""); pub static SWEEP: Emoji<'_, '_> = Emoji("๐Ÿงน ", ""); - pub static LOOKING_GLASS: Emoji<'_, '_> = Emoji("๐Ÿ•ต๏ธ ", ""); + pub static LOOKING_GLASS: Emoji<'_, '_> = Emoji("๐Ÿ‘€ ", ""); pub static CODE: Emoji<'_, '_> = Emoji("๐Ÿงฑ ", ""); - pub static SWORDS: Emoji<'_, '_> = Emoji("โš”๏ธ ", ""); - pub static DEPS: Emoji<'_, '_> = Emoji("๏ธ๐ŸŒด ", ""); - pub static CHECKMARK: Emoji<'_, '_> = Emoji("๏ธโœ… ", ""); - pub static CROSS: Emoji<'_, '_> = Emoji("๏ธ๐Ÿ›‘ ", ""); + pub static SWORDS: Emoji<'_, '_> = Emoji("๐Ÿคบ ", ""); + pub static DEPS: Emoji<'_, '_> = Emoji("๐ŸŒด ", ""); + pub static CHECKMARK: Emoji<'_, '_> = Emoji("โœ… ", ""); + pub static CROSS: Emoji<'_, '_> = Emoji("โŒ ", ""); pub static SPARKLES: Emoji<'_, '_> = Emoji("โœจ ", ""); pub static COMPILE_STATE: Emoji<'_, '_> = Emoji("๐Ÿ“ ", ""); pub static LINE_CLEAR: &str = "\x1b[2K\r"; @@ -139,26 +139,31 @@ pub fn contains_ascii_characters(str: &str) -> bool { false } -pub fn create_build_path(build_path: &str) { +pub fn create_path(path: &str) { fs::DirBuilder::new() .recursive(true) - .create(PathBuf::from(build_path.to_string())) + .create(PathBuf::from(path.to_string())) .unwrap(); } +pub fn create_path_for_path(path: &Path) { + fs::DirBuilder::new().recursive(true).create(path).unwrap(); +} + pub fn get_bsc(root_path: &str, workspace_root: Option) -> String { let subfolder = match (std::env::consts::OS, std::env::consts::ARCH) { - ("macos", "aarch64") => "darwinarm64", - ("macos", _) => "darwin", - ("linux", "aarch64") => "linuxarm64", - ("linux", _) => "linux", - ("windows", _) => "win32", + ("macos", "aarch64") => "darwin-arm64", + ("macos", _) => "darwin-x64", + ("linux", "aarch64") => "linux-arm64", + ("linux", _) => "linux-x64", + ("windows", "aarch64") => "win-arm64", + ("windows", _) => "win-x64", _ => panic!("Unsupported architecture"), }; match ( PathBuf::from(format!( - "{}/node_modules/rescript/{}/bsc.exe", + "{}/node_modules/@rescript/{}/bin/bsc.exe", root_path, subfolder )) .canonicalize(), @@ -184,6 +189,24 @@ pub fn string_ends_with_any(s: &Path, suffixes: &[&str]) -> bool { .any(|&suffix| s.extension().unwrap_or(&OsString::new()).to_str().unwrap_or("") == suffix) } +fn path_to_ast_extension(path: &Path) -> &str { + let extension = path.extension().unwrap().to_str().unwrap(); + if extension.ends_with("i") { + ".iast" + } else { + ".ast" + } +} + +pub fn get_ast_path(source_file: &str) -> PathBuf { + let source_path = Path::new(source_file); + + source_path.parent().unwrap().join( + file_path_to_compiler_asset_basename(source_file, &packages::Namespace::NoNamespace) + + path_to_ast_extension(source_path), + ) +} + pub fn get_compiler_asset( package: &packages::Package, namespace: &packages::Namespace, @@ -194,18 +217,15 @@ pub fn get_compiler_asset( "ast" | "iast" => &packages::Namespace::NoNamespace, _ => namespace, }; - package.get_build_path() + package.get_ocaml_build_path() + "/" + &file_path_to_compiler_asset_basename(source_file, namespace) + "." + extension } -pub fn canonicalize_string_path(path: &str) -> Option { - return Path::new(path) - .canonicalize() - .ok() - .map(|path| path.to_str().expect("Could not canonicalize").to_string()); +pub fn canonicalize_string_path(path: &str) -> Option { + return Path::new(path).canonicalize().ok(); } pub fn get_bs_compiler_asset( @@ -221,7 +241,7 @@ pub fn get_bs_compiler_asset( let dir = std::path::Path::new(&source_file).parent().unwrap(); - std::path::Path::new(&package.get_bs_build_path()) + std::path::Path::new(&package.get_build_path()) .join(dir) .join(file_path_to_compiler_asset_basename(source_file, namespace) + extension) .to_str() @@ -293,7 +313,7 @@ pub fn format_namespaced_module_name(module_name: &str) -> String { } } -pub fn compute_file_hash(path: &str) -> Option { +pub fn compute_file_hash(path: &Path) -> Option { match fs::read(path) { Ok(str) => Some(blake3::hash(&str)), Err(_) => None, @@ -342,3 +362,10 @@ pub fn read_file(path: &Path) -> Result { file.read_to_string(&mut contents)?; Ok(contents) } + +pub fn get_source_file_from_rescript_file(path: &Path, suffix: &str) -> PathBuf { + path.with_extension( + // suffix.to_string includes the ., so we need to remove it + &suffix.to_string()[1..], + ) +} diff --git a/rewatch/src/main.rs b/rewatch/src/main.rs index 565db3d93f..3ff476875e 100644 --- a/rewatch/src/main.rs +++ b/rewatch/src/main.rs @@ -41,29 +41,37 @@ struct Args { #[arg(short, long)] after_build: Option, - #[arg(short, long)] - no_timing: Option, + // Disable timing on the output + #[arg(short, long, default_value = "false", num_args = 0..=1)] + no_timing: bool, /// Verbosity: /// -v -> Debug /// -vv -> Trace /// -q -> Warn - /// -qq -> Error - /// -qqq -> Off. + /// -qq -> Error + /// -qqq -> Off. /// Default (/ no argument given): 'info' #[command(flatten)] verbose: clap_verbosity_flag::Verbosity, /// This creates a source_dirs.json file at the root of the monorepo, which is needed when you /// want to use Reanalyze - #[arg(short, long)] - create_sourcedirs: Option, + #[arg(short, long, default_value_t = false, num_args = 0..=1)] + create_sourcedirs: bool, /// This prints the compiler arguments. It expects the path to a rescript.json file. /// This also requires --bsc-path and --rescript-version to be present #[arg(long)] compiler_args: Option, + /// This is the flag to also compile development dependencies + /// It's important to know that we currently do not discern between project src, and + /// dependencies. So enabling this flag will enable building _all_ development dependencies of + /// _all_ packages + #[arg(long, default_value_t = false, num_args = 0..=1)] + dev: bool, + /// To be used in conjunction with compiler_args #[arg(long)] rescript_version: Option, @@ -94,7 +102,7 @@ fn main() -> Result<()> { Some(path) => { println!( "{}", - build::get_compiler_args(&path, args.rescript_version, args.bsc_path)? + build::get_compiler_args(&path, args.rescript_version, args.bsc_path, args.dev)? ); std::process::exit(0); } @@ -106,22 +114,23 @@ fn main() -> Result<()> { match lock::get(&folder) { lock::Lock::Error(ref e) => { - log::error!("Could not start Rewatch: {e}"); + println!("Could not start Rewatch: {e}"); std::process::exit(1) } lock::Lock::Aquired(_) => match command { - Command::Clean => build::clean::clean(&folder, show_progress, args.bsc_path), + Command::Clean => build::clean::clean(&folder, show_progress, args.bsc_path, args.dev), Command::Build => { match build::build( &filter, &folder, show_progress, - args.no_timing.unwrap_or(false), - args.create_sourcedirs.unwrap_or(false), + args.no_timing, + args.create_sourcedirs, args.bsc_path, + args.dev, ) { Err(e) => { - log::error!("{e}"); + println!("{e}"); std::process::exit(1) } Ok(_) => { @@ -138,7 +147,9 @@ fn main() -> Result<()> { show_progress, &folder, args.after_build, - args.create_sourcedirs.unwrap_or(false), + args.create_sourcedirs, + args.dev, + args.bsc_path, ); Ok(()) diff --git a/rewatch/src/sourcedirs.rs b/rewatch/src/sourcedirs.rs index ff206639eb..ed704aa7e9 100644 --- a/rewatch/src/sourcedirs.rs +++ b/rewatch/src/sourcedirs.rs @@ -85,7 +85,7 @@ pub fn print(buildstate: &BuildState) { // Write sourcedirs.json write_sourcedirs_files( - package.get_bs_build_path(), + package.get_build_path(), &SourceDirs { dirs: &dirs.clone().into_iter().collect::>(), pkgs: &pkgs.clone().flatten().collect::>(), @@ -109,7 +109,7 @@ pub fn print(buildstate: &BuildState) { // Write sourcedirs.json write_sourcedirs_files( - root_package.get_bs_build_path(), + root_package.get_build_path(), &SourceDirs { dirs: &merged_dirs.into_iter().collect::>(), pkgs: &merged_pkgs.into_iter().collect::>(), diff --git a/rewatch/src/watcher.rs b/rewatch/src/watcher.rs index 9fc140a181..6b99db75bc 100644 --- a/rewatch/src/watcher.rs +++ b/rewatch/src/watcher.rs @@ -53,9 +53,18 @@ async fn async_watch( filter: &Option, after_build: Option, create_sourcedirs: bool, + build_dev_deps: bool, + bsc_path: Option, ) -> notify::Result<()> { - let mut build_state = - build::initialize_build(None, filter, show_progress, path, None).expect("Can't initialize build"); + let mut build_state = build::initialize_build( + None, + filter, + show_progress, + path, + bsc_path.clone(), + build_dev_deps, + ) + .expect("Can't initialize build"); let mut needs_compile_type = CompileType::Incremental; // create a mutex to capture if ctrl-c was pressed let ctrlc_pressed = Arc::new(Mutex::new(false)); @@ -90,6 +99,20 @@ async fn async_watch( } for event in events { + // if there is a file named rewatch.lock in the events path, we can quit the watcher + if let Some(_) = event.paths.iter().find(|path| path.ends_with("rewatch.lock")) { + match event.kind { + EventKind::Remove(_) => { + if show_progress { + println!("\nExiting... (lockfile removed)"); + } + clean::cleanup_after_build(&build_state); + return Ok(()); + } + _ => (), + } + } + let paths = event .paths .iter() @@ -190,6 +213,7 @@ async fn async_watch( show_progress, !initial_build, create_sourcedirs, + build_dev_deps, ) .is_ok() { @@ -212,8 +236,15 @@ async fn async_watch( } CompileType::Full => { let timing_total = Instant::now(); - build_state = build::initialize_build(None, filter, show_progress, path, None) - .expect("Can't initialize build"); + build_state = build::initialize_build( + None, + filter, + show_progress, + path, + bsc_path.clone(), + build_dev_deps, + ) + .expect("Can't initialize build"); let _ = build::incremental_build( &mut build_state, None, @@ -221,6 +252,7 @@ async fn async_watch( show_progress, false, create_sourcedirs, + build_dev_deps, ); if let Some(a) = after_build.clone() { cmd::run(a) @@ -255,6 +287,8 @@ pub fn start( folder: &str, after_build: Option, create_sourcedirs: bool, + build_dev_deps: bool, + bsc_path: Option, ) { futures::executor::block_on(async { let queue = Arc::new(FifoQueue::>::new()); @@ -274,10 +308,12 @@ pub fn start( filter, after_build, create_sourcedirs, + build_dev_deps, + bsc_path, ) .await { - log::error!("{:?}", e) + println!("{:?}", e) } }) } diff --git a/rewatch/testrepo/.gitignore b/rewatch/testrepo/.gitignore new file mode 100644 index 0000000000..d9170dc4bb --- /dev/null +++ b/rewatch/testrepo/.gitignore @@ -0,0 +1,12 @@ +.DS_Store +**/node_modules/ +**/lib/ +.bsb.lock +.merlin +.DS_Store +.cmi +.cmt +.cmj +.ast +.asti +.yarn/install-state.gz diff --git a/rewatch/testrepo/bsconfig.json b/rewatch/testrepo/bsconfig.json new file mode 100644 index 0000000000..53fc846288 --- /dev/null +++ b/rewatch/testrepo/bsconfig.json @@ -0,0 +1,32 @@ +{ + "name": "testrepo", + "sources": { + "dir": "src", + "subdirs": true + }, + "package-specs": [ + { + "module": "es6", + "in-source": true + } + ], + "warnings": { + "error": false + }, + "suffix": ".mjs", + "pinned-dependencies": [ + "@testrepo/main", + "@testrepo/dep01", + "@testrepo/dep02", + "@testrepo/new-namespace" + ], + "bs-dependencies": [ + "@testrepo/main", + "@testrepo/dep01", + "@testrepo/dep02", + "@testrepo/new-namespace" + ], + "reason": { + "react-jsx": 3 + } +} diff --git a/rewatch/testrepo/package.json b/rewatch/testrepo/package.json new file mode 100644 index 0000000000..15e6d4a5cc --- /dev/null +++ b/rewatch/testrepo/package.json @@ -0,0 +1,23 @@ +{ + "name": "testrepo", + "private": true, + "workspaces": { + "packages": [ + "packages/main", + "packages/dep01", + "packages/dep02", + "packages/new-namespace" + ] + }, + "dependencies": { + "rescript": "ci" + }, + "scripts": { + "build": "../target/release/rewatch build .", + "build:rescript": "rescript build -with-deps", + "watch": "../target/release/rewatch watch .", + "watch:rescript": "rescript watch -with-deps", + "clean": "../target/release/rewatch clean .", + "clean:rescript": "rescript clean" + } +} diff --git a/rewatch/testrepo/packages/dep01/README.md b/rewatch/testrepo/packages/dep01/README.md new file mode 100644 index 0000000000..78ee1dac74 --- /dev/null +++ b/rewatch/testrepo/packages/dep01/README.md @@ -0,0 +1,21 @@ +# ReScript Project Template + +The only official ReScript starter template. + +## Installation + +```sh +npm install +``` + +## Build + +- Build: `npm run res:build` +- Clean: `npm run res:clean` +- Build & watch: `npm run res:dev` + +## Run + +```sh +node src/Demo.bs.js +``` diff --git a/rewatch/testrepo/packages/dep01/bsconfig.json b/rewatch/testrepo/packages/dep01/bsconfig.json new file mode 100644 index 0000000000..106a46fd01 --- /dev/null +++ b/rewatch/testrepo/packages/dep01/bsconfig.json @@ -0,0 +1,13 @@ +{ + "name": "@testrepo/dep01", + "sources": { + "dir": "src", + "subdirs": true + }, + "package-specs": { + "module": "es6", + "in-source": true + }, + "suffix": ".bs.js", + "bs-dependencies": ["@testrepo/dep02"] +} diff --git a/rewatch/testrepo/packages/dep01/package.json b/rewatch/testrepo/packages/dep01/package.json new file mode 100644 index 0000000000..9209fbbaf8 --- /dev/null +++ b/rewatch/testrepo/packages/dep01/package.json @@ -0,0 +1,17 @@ +{ + "name": "@testrepo/dep01", + "version": "0.0.1", + "scripts": { + "res:build": "rescript", + "res:clean": "rescript clean", + "res:dev": "rescript build -w" + }, + "keywords": [ + "rescript" + ], + "author": "", + "license": "MIT", + "dependencies": { + "@testrepo/dep02": "*" + } +} diff --git a/rewatch/testrepo/packages/dep01/src/Demo.bs.js b/rewatch/testrepo/packages/dep01/src/Demo.bs.js new file mode 100644 index 0000000000..7002a36c8a --- /dev/null +++ b/rewatch/testrepo/packages/dep01/src/Demo.bs.js @@ -0,0 +1,7 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE +'use strict'; + + +console.log("Hello, World!"); + +/* Not a pure module */ diff --git a/rewatch/testrepo/packages/dep01/src/Dep01.mjs b/rewatch/testrepo/packages/dep01/src/Dep01.mjs new file mode 100644 index 0000000000..9cee96c513 --- /dev/null +++ b/rewatch/testrepo/packages/dep01/src/Dep01.mjs @@ -0,0 +1,13 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + +import * as Dep02 from "@testrepo/dep02/src/Dep02.mjs"; + +function log() { + console.log("02"); + Dep02.log(); +} + +export { + log, +} +/* Dep02 Not a pure module */ diff --git a/rewatch/testrepo/packages/dep01/src/Dep01.res b/rewatch/testrepo/packages/dep01/src/Dep01.res new file mode 100644 index 0000000000..f3b84140c1 --- /dev/null +++ b/rewatch/testrepo/packages/dep01/src/Dep01.res @@ -0,0 +1,4 @@ +let log = () => { + Js.log("02") + Dep02.log() +} diff --git a/rewatch/testrepo/packages/dep02/README.md b/rewatch/testrepo/packages/dep02/README.md new file mode 100644 index 0000000000..78ee1dac74 --- /dev/null +++ b/rewatch/testrepo/packages/dep02/README.md @@ -0,0 +1,21 @@ +# ReScript Project Template + +The only official ReScript starter template. + +## Installation + +```sh +npm install +``` + +## Build + +- Build: `npm run res:build` +- Clean: `npm run res:clean` +- Build & watch: `npm run res:dev` + +## Run + +```sh +node src/Demo.bs.js +``` diff --git a/rewatch/testrepo/packages/dep02/bsconfig.json b/rewatch/testrepo/packages/dep02/bsconfig.json new file mode 100644 index 0000000000..0355169956 --- /dev/null +++ b/rewatch/testrepo/packages/dep02/bsconfig.json @@ -0,0 +1,13 @@ +{ + "name": "@testrepo/dep02", + "sources": { + "dir": "src", + "subdirs": true + }, + "package-specs": { + "module": "es6", + "in-source": true + }, + "suffix": ".bs.js", + "bs-dependencies": ["@testrepo/new-namespace"] +} diff --git a/rewatch/testrepo/packages/dep02/package.json b/rewatch/testrepo/packages/dep02/package.json new file mode 100644 index 0000000000..ee0c5676bf --- /dev/null +++ b/rewatch/testrepo/packages/dep02/package.json @@ -0,0 +1,14 @@ +{ + "name": "@testrepo/dep02", + "version": "0.0.1", + "scripts": { + "res:build": "rescript", + "res:clean": "rescript clean", + "res:dev": "rescript build -w" + }, + "keywords": [ + "rescript" + ], + "author": "", + "license": "MIT" +} diff --git a/rewatch/testrepo/packages/dep02/src/Array.mjs b/rewatch/testrepo/packages/dep02/src/Array.mjs new file mode 100644 index 0000000000..8fca907c33 --- /dev/null +++ b/rewatch/testrepo/packages/dep02/src/Array.mjs @@ -0,0 +1,540 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + +import * as Js_array from "rescript/lib/es6/Js_array.js"; +import * as Belt_Array from "rescript/lib/es6/Belt_Array.js"; +import * as Belt_SortArray from "rescript/lib/es6/Belt_SortArray.js"; +import * as Primitive_option from "rescript/lib/es6/Primitive_option.js"; + +function includes(prim0, prim1) { + return prim0.includes(prim1); +} + +function head(t) { + return Belt_Array.get(t, 0); +} + +function take(t, n) { + return Belt_Array.slice(t, 0, n); +} + +function last(t) { + return Belt_Array.get(t, t.length - 1 | 0); +} + +function isEmpty(t) { + return t.length === 0; +} + +function isNotEmpty(t) { + return t.length !== 0; +} + +function append(t, v) { + return Belt_Array.concat(t, [v]); +} + +function prepend(t, v) { + return Belt_Array.concat([v], t); +} + +function mapi(prim0, prim1) { + return prim0.map(prim1); +} + +function flatten(t) { + return Belt_Array.concatMany(Belt_Array.map(t, x => x)); +} + +function find(t, fn) { + return Js_array.find(fn, t); +} + +function findIndex(t, fn) { + return Js_array.findIndex(fn, t); +} + +function filter(prim0, prim1) { + return prim0.filter(prim1); +} + +function reject(t, fn) { + return t.filter(el => !fn(el)); +} + +function sortBy(t, fn) { + return Belt_SortArray.stableSortBy(t, (a, b) => { + let match = fn(a, b); + if (match === "greater_than") { + return 1; + } else if (match === "less_than") { + return -1; + } else { + return 0; + } + }); +} + +function joinWith(prim0, prim1) { + return prim0.join(prim1); +} + +function join(__x) { + return __x.join(""); +} + +let $$String = { + joinWith: joinWith, + join: join +}; + +function eqBy(_xs, _ys, fn) { + while (true) { + let ys = _ys; + let xs = _xs; + let match = Belt_Array.get(xs, 0); + let match$1 = Belt_Array.get(ys, 0); + if (match === undefined) { + return match$1 === undefined; + } + if (match$1 === undefined) { + return false; + } + if (!fn(Primitive_option.valFromOption(match), Primitive_option.valFromOption(match$1))) { + return false; + } + _ys = Belt_Array.sliceToEnd(ys, 1); + _xs = Belt_Array.sliceToEnd(xs, 1); + continue; + }; +} + +function takeWhile(t, fn) { + let a = { + contents: [] + }; + let maxLength = t.length - 1 | 0; + let iter = _idx => { + while (true) { + let idx = _idx; + if (idx >= maxLength) { + return; + } + let item = t[idx]; + if (!fn(item)) { + return; + } + a.contents = Belt_Array.concat(a.contents, [item]); + _idx = idx + 1 | 0; + continue; + }; + }; + iter(0); + return a.contents; +} + +function distinct(t, eq) { + let maxIdx = t.length; + let _acc = []; + let _idx = 0; + while (true) { + let idx = _idx; + let acc = _acc; + if (idx >= maxIdx) { + return acc; + } + let y = t[idx]; + let acc$1 = Belt_Array.some(acc, x => eq(x, y)) ? acc : Belt_Array.concat(acc, [y]); + _idx = idx + 1 | 0; + _acc = acc$1; + continue; + }; +} + +function partition(t, fn) { + let maxLength = t.length; + let _a = []; + let _b = []; + let _idx = 0; + while (true) { + let idx = _idx; + let b = _b; + let a = _a; + if (idx >= maxLength) { + return [ + a, + b + ]; + } + let item = t[idx]; + let idx$1 = idx + 1 | 0; + if (fn(item)) { + _idx = idx$1; + _a = Belt_Array.concat(a, [item]); + continue; + } + _idx = idx$1; + _b = Belt_Array.concat(b, [item]); + continue; + }; +} + +function replaceAt(t, idx, item) { + return Belt_Array.mapWithIndex(t, (idx$p, el) => { + if (idx === idx$p) { + return item; + } else { + return el; + } + }); +} + +function indexOfBy(t, fn, value) { + let _idx = 0; + while (true) { + let idx = _idx; + let value$p = Belt_Array.get(t, idx); + if (value$p === undefined) { + return; + } + if (fn(value, Primitive_option.valFromOption(value$p))) { + return idx; + } + _idx = idx + 1 | 0; + continue; + }; +} + +function swapAt(t, i, j) { + let match = Belt_Array.get(t, i); + let match$1 = Belt_Array.get(t, j); + if (match === undefined) { + return t; + } + if (match$1 === undefined) { + return t; + } + let b = Primitive_option.valFromOption(match$1); + let a = Primitive_option.valFromOption(match); + return Belt_Array.mapWithIndex(t, (k, x) => { + if (i === k) { + return b; + } else if (j === k) { + return a; + } else { + return x; + } + }); +} + +function splitAt(t, i) { + if (i < 0 || i > t.length) { + return; + } + let a = Belt_Array.slice(t, 0, i); + let b = Belt_Array.sliceToEnd(t, i); + return [ + a, + b + ]; +} + +function insertAt(t, idx, x) { + let match = splitAt(t, idx); + if (match !== undefined) { + return Belt_Array.concat(match[0], Belt_Array.concat([x], match[1])); + } else { + return t; + } +} + +function flatMap(t, fn) { + return Belt_Array.concatMany(Belt_Array.map(t, fn)); +} + +function removeAt(t, idx) { + return Belt_Array.keepWithIndex(t, (param, i) => i !== idx); +} + +function drop(t, i) { + let l = t.length; + let start = i < 0 ? 0 : ( + l < i ? l : i + ); + return Belt_Array.sliceToEnd(t, start); +} + +function unsafePop(prim) { + return Primitive_option.fromUndefined(prim.pop()); +} + +function sum(xs) { + return Belt_Array.reduce(xs, 0, (a, b) => a + b | 0); +} + +let Int = { + sum: sum +}; + +function sum$1(xs) { + return Belt_Array.reduce(xs, 0, (a, b) => a + b); +} + +let Float = { + sum: sum$1 +}; + +function clear(t) { + t.length = 0; +} + +let get = Belt_Array.get; + +let getExn = Belt_Array.getExn; + +let set = Belt_Array.set; + +let setExn = Belt_Array.setExn; + +let shuffleInPlace = Belt_Array.shuffleInPlace; + +let shuffle = Belt_Array.shuffle; + +let reverseInPlace = Belt_Array.reverseInPlace; + +let reverse = Belt_Array.reverse; + +let make = Belt_Array.make; + +let range = Belt_Array.range; + +let rangeBy = Belt_Array.rangeBy; + +let makeByU = Belt_Array.makeByU; + +let makeBy = Belt_Array.makeBy; + +let makeByAndShuffleU = Belt_Array.makeByAndShuffleU; + +let makeByAndShuffle = Belt_Array.makeByAndShuffle; + +let zip = Belt_Array.zip; + +let zipByU = Belt_Array.zipByU; + +let zipBy = Belt_Array.zipBy; + +let unzip = Belt_Array.unzip; + +let concat = Belt_Array.concat; + +let concatMany = Belt_Array.concatMany; + +let slice = Belt_Array.slice; + +let sliceToEnd = Belt_Array.sliceToEnd; + +let fill = Belt_Array.fill; + +let blit = Belt_Array.blit; + +let blitUnsafe = Belt_Array.blitUnsafe; + +let forEachU = Belt_Array.forEachU; + +let forEach = Belt_Array.forEach; + +let mapU = Belt_Array.mapU; + +let map = Belt_Array.map; + +let flatMapU = Belt_Array.flatMapU; + +let getByU = Belt_Array.getByU; + +let getBy = Belt_Array.getBy; + +let getIndexByU = Belt_Array.getIndexByU; + +let getIndexBy = Belt_Array.getIndexBy; + +let keepU = Belt_Array.keepU; + +let keep = Belt_Array.keep; + +let keepWithIndexU = Belt_Array.keepWithIndexU; + +let keepWithIndex = Belt_Array.keepWithIndex; + +let keepMapU = Belt_Array.keepMapU; + +let keepMap = Belt_Array.keepMap; + +let forEachWithIndexU = Belt_Array.forEachWithIndexU; + +let forEachWithIndex = Belt_Array.forEachWithIndex; + +let mapWithIndexU = Belt_Array.mapWithIndexU; + +let mapWithIndex = Belt_Array.mapWithIndex; + +let partitionU = Belt_Array.partitionU; + +let reduceU = Belt_Array.reduceU; + +let reduce = Belt_Array.reduce; + +let reduceReverseU = Belt_Array.reduceReverseU; + +let reduceReverse = Belt_Array.reduceReverse; + +let reduceReverse2U = Belt_Array.reduceReverse2U; + +let reduceReverse2 = Belt_Array.reduceReverse2; + +let reduceWithIndexU = Belt_Array.reduceWithIndexU; + +let reduceWithIndex = Belt_Array.reduceWithIndex; + +let joinWithU = Belt_Array.joinWithU; + +let joinWith$1 = Belt_Array.joinWith; + +let someU = Belt_Array.someU; + +let some = Belt_Array.some; + +let everyU = Belt_Array.everyU; + +let every = Belt_Array.every; + +let every2U = Belt_Array.every2U; + +let every2 = Belt_Array.every2; + +let some2U = Belt_Array.some2U; + +let some2 = Belt_Array.some2; + +let cmpU = Belt_Array.cmpU; + +let cmp = Belt_Array.cmp; + +let eqU = Belt_Array.eqU; + +let eq = Belt_Array.eq; + +let initU = Belt_Array.initU; + +let init = Belt_Array.init; + +let at = Belt_Array.get; + +let sortByRaw = Belt_SortArray.stableSortBy; + +export { + get, + getExn, + set, + setExn, + shuffleInPlace, + shuffle, + reverseInPlace, + reverse, + make, + range, + rangeBy, + makeByU, + makeBy, + makeByAndShuffleU, + makeByAndShuffle, + zip, + zipByU, + zipBy, + unzip, + concat, + concatMany, + slice, + sliceToEnd, + fill, + blit, + blitUnsafe, + forEachU, + forEach, + mapU, + map, + flatMapU, + getByU, + getBy, + getIndexByU, + getIndexBy, + keepU, + keep, + keepWithIndexU, + keepWithIndex, + keepMapU, + keepMap, + forEachWithIndexU, + forEachWithIndex, + mapWithIndexU, + mapWithIndex, + partitionU, + reduceU, + reduce, + reduceReverseU, + reduceReverse, + reduceReverse2U, + reduceReverse2, + reduceWithIndexU, + reduceWithIndex, + joinWithU, + joinWith$1 as joinWith, + someU, + some, + everyU, + every, + every2U, + every2, + some2U, + some2, + cmpU, + cmp, + eqU, + eq, + initU, + init, + at, + includes, + head, + take, + last, + isEmpty, + isNotEmpty, + append, + prepend, + mapi, + flatten, + find, + findIndex, + filter, + reject, + sortBy, + sortByRaw, + $$String, + eqBy, + takeWhile, + distinct, + partition, + replaceAt, + indexOfBy, + swapAt, + splitAt, + insertAt, + flatMap, + removeAt, + drop, + unsafePop, + Int, + Float, + clear, +} +/* No side effect */ diff --git a/rewatch/testrepo/packages/dep02/src/Array.res b/rewatch/testrepo/packages/dep02/src/Array.res new file mode 100644 index 0000000000..60e6fe5d10 --- /dev/null +++ b/rewatch/testrepo/packages/dep02/src/Array.res @@ -0,0 +1,176 @@ +// Array module +include Belt.Array + +let at = get + +let includes = Js.Array2.includes + +let head = t => t->get(0) + +let take = (t, n) => slice(~offset=0, ~len=n, t) + +let last = t => t->at(length(t) - 1) + +let isEmpty = t => t->length == 0 + +let isNotEmpty = t => t->length > 0 + +let append = (t, v) => t->concat([v]) + +let prepend = (t, v) => [v]->concat(t) + +let flatMap = (t, fn) => t->map(fn)->concatMany + +let mapi = Js.Array2.mapi + +let flatten = t => t->flatMap(x => x) + +let find = (t, fn) => Js.Array.find(fn, t) + +let findIndex = (t, fn) => Js.Array.findIndex(fn, t) + +let filter = Js.Array2.filter + +let reject = (t, fn) => t->filter(el => !fn(el)) + +let sortBy = (t, fn) => + Belt.SortArray.stableSortBy(t, (a, b) => { + switch fn(a, b) { + | #less_than => -1 + | #equal_to => 0 + | #greater_than => 1 + } + }) + +let sortByRaw = Belt.SortArray.stableSortBy + +module String = { + let joinWith = Js.Array2.joinWith + let join = joinWith(_, "") +} + +let rec eqBy = (xs, ys, ~fn) => { + let tailOrEmpty = sliceToEnd(_, 1) + switch (head(xs), head(ys)) { + | (None, None) => true + | (Some(x), Some(y)) if fn(x, y) => eqBy(tailOrEmpty(xs), tailOrEmpty(ys), ~fn) + | _ => false + } +} + +let takeWhile = (t, fn) => { + let a = ref([]) + + let maxLength = t->length - 1 + let rec iter = idx => { + if idx < maxLength { + let item = t->getUnsafe(idx) + if fn(item) { + a := concat(a.contents, [item]) + iter(idx + 1) + } + } + } + iter(0) + + a.contents +} + +let distinct = (t, eq) => { + let maxIdx = t->length + let rec aux = (acc, idx) => { + if idx < maxIdx { + let y = t->getUnsafe(idx) + let acc = if !(acc->some(x => eq(x, y))) { + acc->concat([y]) + } else { + acc + } + aux(acc, idx + 1) + } else { + acc + } + } + aux([], 0) +} + +let partition = (t, fn) => { + let maxLength = t->length + let rec iter = (a, b, idx) => { + if idx < maxLength { + let item = t->getUnsafe(idx) + let idx = idx + 1 + if fn(item) { + iter(concat(a, [item]), b, idx) + } else { + iter(a, concat(b, [item]), idx) + } + } else { + (a, b) + } + } + iter([], [], 0) +} + +let replaceAt = (t: array<'a>, idx: int, item: 'a) => + t->mapWithIndex((idx', el) => + if idx == idx' { + item + } else { + el + } + ) + +let indexOfBy = (t, fn, value) => { + let rec aux = idx => { + switch at(t, idx) { + | None => None + | Some(value') if fn(value, value') => Some(idx) + | _ => aux(idx + 1) + } + } + aux(0) +} + +let swapAt = (t, i, j) => { + switch (at(t, i), at(t, j)) { + | (Some(a), Some(b)) => t->mapWithIndex((k, x) => i == k ? b : j == k ? a : x) + | _ => t + } +} + +let splitAt = (t, i) => + if i < 0 || i > length(t) { + None + } else { + let a = t->slice(~offset=0, ~len=i) + let b = t->sliceToEnd(i) + Some((a, b)) + } + +let insertAt = (t, idx, x) => + switch t->splitAt(idx) { + | Some((before, after)) => before->concat([x]->concat(after)) + | None => t + } + +let flatMap = (t, fn) => t->map(fn)->concatMany + +let removeAt = (t, idx) => t->keepWithIndex((_, i) => i != idx) + +let drop = (t, i) => { + let l = t->length + let start = i < 0 ? 0 : l < i ? l : i + t->sliceToEnd(start) +} + +let unsafePop = Js.Array.pop + +module Int = { + let sum = xs => reduce(xs, 0, (a, b) => a + b) +} + +module Float = { + let sum = xs => reduce(xs, 0., (a, b) => a +. b) +} +let clear = t => truncateToLengthUnsafe(t, 0) diff --git a/rewatch/testrepo/packages/dep02/src/Dep02.mjs b/rewatch/testrepo/packages/dep02/src/Dep02.mjs new file mode 100644 index 0000000000..92546945c3 --- /dev/null +++ b/rewatch/testrepo/packages/dep02/src/Dep02.mjs @@ -0,0 +1,19 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + +import * as NS_alias$$atNewNamespace from "@testrepo/new-namespace/src/NS_alias.mjs"; + +function log() { + [ + "a", + "b" + ].forEach(prim => { + console.log(prim); + }); +} + +console.log(NS_alias$$atNewNamespace.hello_world()); + +export { + log, +} +/* Not a pure module */ diff --git a/rewatch/testrepo/packages/dep02/src/Dep02.res b/rewatch/testrepo/packages/dep02/src/Dep02.res new file mode 100644 index 0000000000..e832615245 --- /dev/null +++ b/rewatch/testrepo/packages/dep02/src/Dep02.res @@ -0,0 +1,3 @@ +open Array +let log = () => ["a", "b"]->forEach(Js.log) +Js.log(NS.Alias.hello_world()) diff --git a/rewatch/testrepo/packages/main/README.md b/rewatch/testrepo/packages/main/README.md new file mode 100644 index 0000000000..78ee1dac74 --- /dev/null +++ b/rewatch/testrepo/packages/main/README.md @@ -0,0 +1,21 @@ +# ReScript Project Template + +The only official ReScript starter template. + +## Installation + +```sh +npm install +``` + +## Build + +- Build: `npm run res:build` +- Clean: `npm run res:clean` +- Build & watch: `npm run res:dev` + +## Run + +```sh +node src/Demo.bs.js +``` diff --git a/rewatch/testrepo/packages/main/bsconfig.json b/rewatch/testrepo/packages/main/bsconfig.json new file mode 100644 index 0000000000..f169104564 --- /dev/null +++ b/rewatch/testrepo/packages/main/bsconfig.json @@ -0,0 +1,15 @@ +{ + "name": "@testrepo/main", + "sources": { + "dir": "src", + "subdirs": true + }, + "package-specs": { + "module": "commonjs", + "in-source": true + }, + "suffix": ".bs.js", + "bs-dependencies": [ + "@testrepo/dep01" + ] +} diff --git a/rewatch/testrepo/packages/main/package.json b/rewatch/testrepo/packages/main/package.json new file mode 100644 index 0000000000..10954e0797 --- /dev/null +++ b/rewatch/testrepo/packages/main/package.json @@ -0,0 +1,17 @@ +{ + "name": "@testrepo/main", + "version": "0.0.1", + "scripts": { + "res:build": "rescript", + "res:clean": "rescript clean", + "res:dev": "rescript build -w" + }, + "keywords": [ + "rescript" + ], + "author": "", + "license": "MIT", + "dependencies": { + "@testrepo/dep01": "*" + } +} diff --git a/rewatch/testrepo/packages/main/src/Demo.bs.js b/rewatch/testrepo/packages/main/src/Demo.bs.js new file mode 100644 index 0000000000..7002a36c8a --- /dev/null +++ b/rewatch/testrepo/packages/main/src/Demo.bs.js @@ -0,0 +1,7 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE +'use strict'; + + +console.log("Hello, World!"); + +/* Not a pure module */ diff --git a/rewatch/testrepo/packages/main/src/InternalDep.mjs b/rewatch/testrepo/packages/main/src/InternalDep.mjs new file mode 100644 index 0000000000..2cfc571d10 --- /dev/null +++ b/rewatch/testrepo/packages/main/src/InternalDep.mjs @@ -0,0 +1,9 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + + +let value = 1; + +export { + value, +} +/* No side effect */ diff --git a/rewatch/testrepo/packages/main/src/InternalDep.res b/rewatch/testrepo/packages/main/src/InternalDep.res new file mode 100644 index 0000000000..3c37c33b59 --- /dev/null +++ b/rewatch/testrepo/packages/main/src/InternalDep.res @@ -0,0 +1 @@ +let value = 1 diff --git a/rewatch/testrepo/packages/main/src/Main.mjs b/rewatch/testrepo/packages/main/src/Main.mjs new file mode 100644 index 0000000000..e4df550c4b --- /dev/null +++ b/rewatch/testrepo/packages/main/src/Main.mjs @@ -0,0 +1,20 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + +import * as Dep01 from "@testrepo/dep01/src/Dep01.mjs"; +import * as InternalDep from "./InternalDep.mjs"; + +console.log("01"); + +Dep01.log(); + +console.log(InternalDep.value); + +let $$Array; + +let $$String; + +export { + $$Array, + $$String, +} +/* Not a pure module */ diff --git a/rewatch/testrepo/packages/main/src/Main.res b/rewatch/testrepo/packages/main/src/Main.res new file mode 100644 index 0000000000..619e734d77 --- /dev/null +++ b/rewatch/testrepo/packages/main/src/Main.res @@ -0,0 +1,7 @@ +Js.log("01") +Dep01.log() + +Js.log(InternalDep.value) + +module Array = Belt.Array +module String = Js.String diff --git a/rewatch/testrepo/packages/main/src/ModuleWithInterface.mjs b/rewatch/testrepo/packages/main/src/ModuleWithInterface.mjs new file mode 100644 index 0000000000..7f3349f4a0 --- /dev/null +++ b/rewatch/testrepo/packages/main/src/ModuleWithInterface.mjs @@ -0,0 +1,9 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + + +let hello = "world"; + +export { + hello, +} +/* No side effect */ diff --git a/rewatch/testrepo/packages/main/src/ModuleWithInterface.res b/rewatch/testrepo/packages/main/src/ModuleWithInterface.res new file mode 100644 index 0000000000..1ca4d4444d --- /dev/null +++ b/rewatch/testrepo/packages/main/src/ModuleWithInterface.res @@ -0,0 +1,2 @@ +type hello = string +let hello = "world" diff --git a/rewatch/testrepo/packages/main/src/ModuleWithInterface.resi b/rewatch/testrepo/packages/main/src/ModuleWithInterface.resi new file mode 100644 index 0000000000..42a1f844fc --- /dev/null +++ b/rewatch/testrepo/packages/main/src/ModuleWithInterface.resi @@ -0,0 +1,2 @@ +type hello +let hello: hello diff --git a/rewatch/testrepo/packages/main/src/output.txt b/rewatch/testrepo/packages/main/src/output.txt new file mode 100644 index 0000000000..821eb9c321 --- /dev/null +++ b/rewatch/testrepo/packages/main/src/output.txt @@ -0,0 +1,7 @@ +bla +Hello world +01 +02 +a +b +1 diff --git a/rewatch/testrepo/packages/new-namespace/bsconfig.json b/rewatch/testrepo/packages/new-namespace/bsconfig.json new file mode 100644 index 0000000000..3b796b905a --- /dev/null +++ b/rewatch/testrepo/packages/new-namespace/bsconfig.json @@ -0,0 +1,15 @@ +{ + "name": "@testrepo/new-namespace", + "namespace": "NewNamespace", + "namespace-entry": "NS", + "sources": { + "dir": "src", + "subdirs": true + }, + "package-specs": { + "module": "es6", + "in-source": true + }, + "bs-dependencies": ["@testrepo/dep01"], + "suffix": ".bs.js" +} diff --git a/rewatch/testrepo/packages/new-namespace/package.json b/rewatch/testrepo/packages/new-namespace/package.json new file mode 100644 index 0000000000..8e30fe2bec --- /dev/null +++ b/rewatch/testrepo/packages/new-namespace/package.json @@ -0,0 +1,9 @@ +{ + "name": "@testrepo/new-namespace", + "version": "0.0.1", + "keywords": [ + "rescript" + ], + "author": "", + "license": "MIT" +} diff --git a/rewatch/testrepo/packages/new-namespace/src/NS.mjs b/rewatch/testrepo/packages/new-namespace/src/NS.mjs new file mode 100644 index 0000000000..5a1ebae134 --- /dev/null +++ b/rewatch/testrepo/packages/new-namespace/src/NS.mjs @@ -0,0 +1,9 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + + +let Alias; + +export { + Alias, +} +/* No side effect */ diff --git a/rewatch/testrepo/packages/new-namespace/src/NS.res b/rewatch/testrepo/packages/new-namespace/src/NS.res new file mode 100644 index 0000000000..75421b420e --- /dev/null +++ b/rewatch/testrepo/packages/new-namespace/src/NS.res @@ -0,0 +1 @@ +module Alias = NS_alias diff --git a/rewatch/testrepo/packages/new-namespace/src/NS_alias.mjs b/rewatch/testrepo/packages/new-namespace/src/NS_alias.mjs new file mode 100644 index 0000000000..52a4a7e518 --- /dev/null +++ b/rewatch/testrepo/packages/new-namespace/src/NS_alias.mjs @@ -0,0 +1,14 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + +import * as Other_module$$atNewNamespace from "./Other_module.mjs"; + +function hello_world() { + return "Hello world"; +} + +Other_module$$atNewNamespace.bla(); + +export { + hello_world, +} +/* Not a pure module */ diff --git a/rewatch/testrepo/packages/new-namespace/src/NS_alias.res b/rewatch/testrepo/packages/new-namespace/src/NS_alias.res new file mode 100644 index 0000000000..27a251d707 --- /dev/null +++ b/rewatch/testrepo/packages/new-namespace/src/NS_alias.res @@ -0,0 +1,2 @@ +let hello_world = () => "Hello world" +Other_module.bla() diff --git a/rewatch/testrepo/packages/new-namespace/src/Other_module.mjs b/rewatch/testrepo/packages/new-namespace/src/Other_module.mjs new file mode 100644 index 0000000000..0f2f321053 --- /dev/null +++ b/rewatch/testrepo/packages/new-namespace/src/Other_module.mjs @@ -0,0 +1,11 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + + +function bla() { + console.log("bla"); +} + +export { + bla, +} +/* No side effect */ diff --git a/rewatch/testrepo/packages/new-namespace/src/Other_module.res b/rewatch/testrepo/packages/new-namespace/src/Other_module.res new file mode 100644 index 0000000000..b265646f33 --- /dev/null +++ b/rewatch/testrepo/packages/new-namespace/src/Other_module.res @@ -0,0 +1 @@ +let bla = () => Js.log("bla") diff --git a/rewatch/testrepo/src/Test.mjs b/rewatch/testrepo/src/Test.mjs new file mode 100644 index 0000000000..7f3349f4a0 --- /dev/null +++ b/rewatch/testrepo/src/Test.mjs @@ -0,0 +1,9 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + + +let hello = "world"; + +export { + hello, +} +/* No side effect */ diff --git a/rewatch/testrepo/src/Test.res b/rewatch/testrepo/src/Test.res new file mode 100644 index 0000000000..cab79024b0 --- /dev/null +++ b/rewatch/testrepo/src/Test.res @@ -0,0 +1 @@ +let hello = "world" diff --git a/rewatch/testrepo/yarn.lock b/rewatch/testrepo/yarn.lock new file mode 100644 index 0000000000..8679d90fc4 --- /dev/null +++ b/rewatch/testrepo/yarn.lock @@ -0,0 +1,55 @@ +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! + +__metadata: + version: 8 + cacheKey: 10c0 + +"@testrepo/dep01@npm:*, @testrepo/dep01@workspace:packages/dep01": + version: 0.0.0-use.local + resolution: "@testrepo/dep01@workspace:packages/dep01" + dependencies: + "@testrepo/dep02": "npm:*" + languageName: unknown + linkType: soft + +"@testrepo/dep02@npm:*, @testrepo/dep02@workspace:packages/dep02": + version: 0.0.0-use.local + resolution: "@testrepo/dep02@workspace:packages/dep02" + languageName: unknown + linkType: soft + +"@testrepo/main@workspace:packages/main": + version: 0.0.0-use.local + resolution: "@testrepo/main@workspace:packages/main" + dependencies: + "@testrepo/dep01": "npm:*" + languageName: unknown + linkType: soft + +"@testrepo/new-namespace@workspace:packages/new-namespace": + version: 0.0.0-use.local + resolution: "@testrepo/new-namespace@workspace:packages/new-namespace" + languageName: unknown + linkType: soft + +"rescript@npm:ci": + version: 12.0.0-alpha.12 + resolution: "rescript@npm:12.0.0-alpha.12" + bin: + bsc: cli/bsc.js + bstracing: lib/bstracing.js + rescript: cli/rescript.js + rescript-tools: cli/rescript-tools.js + rewatch: cli/rewatch.js + checksum: 10c0/494a23c413905981fffc6230ad1b1019ed5fb1701a21f3eeb1526fb8cc78c511f82ac4edf151bbb881bef1a854895edd2085522ce51e11b359833ae743b7d9d8 + languageName: node + linkType: hard + +"testrepo@workspace:.": + version: 0.0.0-use.local + resolution: "testrepo@workspace:." + dependencies: + rescript: "npm:ci" + languageName: unknown + linkType: soft diff --git a/rewatch/tests/compile.sh b/rewatch/tests/compile.sh index 2697d274f4..dd39bf5b96 100755 --- a/rewatch/tests/compile.sh +++ b/rewatch/tests/compile.sh @@ -33,36 +33,36 @@ fi node ./packages/main/src/Main.mjs > ./packages/main/src/output.txt mv ./packages/main/src/Main.res ./packages/main/src/Main2.res -rewatch build --no-timing=true &> ../tests/snapshots/rename-file.txt +rewatch build &> ../tests/snapshots/rename-file.txt mv ./packages/main/src/Main2.res ./packages/main/src/Main.res # Rename a file with a dependent - this should trigger an error mv ./packages/main/src/InternalDep.res ./packages/main/src/InternalDep2.res -rewatch build --no-timing=true &> ../tests/snapshots/rename-file-internal-dep.txt +rewatch build &> ../tests/snapshots/rename-file-internal-dep.txt # replace the absolute path so the snapshot is the same on all machines replace "s/$(pwd | sed "s/\//\\\\\//g")//g" ../tests/snapshots/rename-file-internal-dep.txt mv ./packages/main/src/InternalDep2.res ./packages/main/src/InternalDep.res # Rename a file with a dependent in a namespaced package - this should trigger an error (regression) mv ./packages/new-namespace/src/Other_module.res ./packages/new-namespace/src/Other_module2.res -rewatch build --no-timing=true &> ../tests/snapshots/rename-file-internal-dep-namespace.txt +rewatch build &> ../tests/snapshots/rename-file-internal-dep-namespace.txt # replace the absolute path so the snapshot is the same on all machines replace "s/$(pwd | sed "s/\//\\\\\//g")//g" ../tests/snapshots/rename-file-internal-dep-namespace.txt mv ./packages/new-namespace/src/Other_module2.res ./packages/new-namespace/src/Other_module.res rewatch build &> /dev/null mv ./packages/main/src/ModuleWithInterface.resi ./packages/main/src/ModuleWithInterface2.resi -rewatch build --no-timing=true &> ../tests/snapshots/rename-interface-file.txt +rewatch build &> ../tests/snapshots/rename-interface-file.txt mv ./packages/main/src/ModuleWithInterface2.resi ./packages/main/src/ModuleWithInterface.resi rewatch build &> /dev/null mv ./packages/main/src/ModuleWithInterface.res ./packages/main/src/ModuleWithInterface2.res -rewatch build --no-timing=true &> ../tests/snapshots/rename-file-with-interface.txt +rewatch build &> ../tests/snapshots/rename-file-with-interface.txt mv ./packages/main/src/ModuleWithInterface2.res ./packages/main/src/ModuleWithInterface.res rewatch build &> /dev/null # when deleting a file that other files depend on, the compile should fail rm packages/dep02/src/Dep02.res -rewatch build --no-timing=true &> ../tests/snapshots/remove-file.txt +rewatch build &> ../tests/snapshots/remove-file.txt # replace the absolute path so the snapshot is the same on all machines replace "s/$(pwd | sed "s/\//\\\\\//g")//g" ../tests/snapshots/remove-file.txt git checkout -- packages/dep02/src/Dep02.res @@ -70,9 +70,37 @@ rewatch build &> /dev/null # it should show an error when we have a dependency cycle echo 'Dep01.log()' >> packages/new-namespace/src/NS_alias.res -rewatch build --no-timing=true &> ../tests/snapshots/dependency-cycle.txt +rewatch build &> ../tests/snapshots/dependency-cycle.txt git checkout -- packages/new-namespace/src/NS_alias.res -rewatch build &> /dev/null + +# it should compile dev dependencies with the --dev flag +rewatch clean &> /dev/null +rewatch build --dev &> /dev/null; +if [ $? -ne 0 ]; +then + error "Failed to compile dev dependencies" + exit 1 +fi + +file_count=$(find ./packages/with-dev-deps/test -name *.mjs | wc -l) +if [ "$file_count" -eq 1 ]; +then + success "Compiled dev dependencies successfully" +else + error "Expected 2 files to be compiled with the --dev flag, found $file_count" + exit 1 +fi + +rewatch clean --dev &> /dev/null +file_count=$(find ./packages/with-dev-deps -name *.mjs | wc -l) +if [ "$file_count" -eq 0 ]; +then + success "Cleaned dev dependencies successfully" +else + error "Expected 0 files remaining after cleaning, found $file_count" + exit 1 +fi + # it should not loop (we had an infinite loop when clean building with a cycle) rewatch clean &> /dev/null diff --git a/rewatch/tests/lock.sh b/rewatch/tests/lock.sh index 019e6166b0..4522a7a037 100755 --- a/rewatch/tests/lock.sh +++ b/rewatch/tests/lock.sh @@ -14,20 +14,21 @@ else fi exit_watcher() { - # we need to kill the parent process (rewatch) - kill $(pgrep -P $!); + # Try to find child process, if not found just kill the process directly + rm lib/rewatch.lock } -rewatch watch &>/dev/null & -success "Watcher Started" +rewatch_bg watch > /dev/null 2>&1 & sleep 1 -if rewatch watch 2>&1 | grep 'Could not start Rewatch:' &> /dev/null; +if rewatch watch | grep 'Could not start Rewatch:' &> /dev/null; then + # rm output.txt success "Lock is correctly set" exit_watcher else + # rm output.txt error "Not setting lock correctly" exit_watcher exit 1 @@ -36,7 +37,7 @@ fi sleep 1 touch tmp.txt -rewatch watch &> tmp.txt & +rewatch_bg watch > tmp.txt 2>&1 & success "Watcher Started" sleep 1 @@ -51,4 +52,4 @@ else exit_watcher fi -rm tmp.txt +rm tmp.txt \ No newline at end of file diff --git a/rewatch/tests/snapshots/dependency-cycle.txt b/rewatch/tests/snapshots/dependency-cycle.txt index b30824a963..6c5236a57d 100644 --- a/rewatch/tests/snapshots/dependency-cycle.txt +++ b/rewatch/tests/snapshots/dependency-cycle.txt @@ -1,18 +1,16 @@ -[1/7] ๐Ÿ“ฆ Building package tree... - [1/7] ๐Ÿ“ฆ Built package tree in 0.00s -[2/7] ๐Ÿ•ต๏ธ Finding source files... - [2/7] ๐Ÿ•ต๏ธ Found source files in 0.00s -[3/7] ๐Ÿ“ Reading compile state... - [3/7] ๐Ÿ“ Read compile state 0.00s -[4/7] ๐Ÿงน Cleaning up previous build... - [4/7] ๐Ÿงน Cleaned 0/11 0.00s +[1/7] ๐Ÿ“ฆ Building package tree... [1/7] ๐Ÿ“ฆ Built package tree in 0.00s +[2/7] ๐Ÿ‘€ Finding source files... [2/7] ๐Ÿ‘€ Found source files in 0.00s +[3/7] ๐Ÿ“ Reading compile state... [3/7] ๐Ÿ“ Read compile state 0.00s +[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 0/94 0.00s  [5/7] ๐Ÿงฑ Parsed 1 source files in 0.00s - [6/7] ๏ธ๐ŸŒด Collected deps in 0.00s - [7/7] ๏ธ๐Ÿ›‘ Compiled 0 modules in 0.00s -ERROR: + [6/7] ๐ŸŒด Collected deps in 0.00s + [7/7] โŒ Compiled 0 modules in 0.00s Can't continue... Found a circular dependency in your code: -NewNamespace.NS_alias -> Dep01 -> Dep02 -> NS -> NewNamespace.NS_alias +Dep01 + โ†’ Dep02 + โ†’ NS + โ†’ NewNamespace.NS_alias + โ†’ Dep01 -ERROR: -Incremental build failed. Error:  ๏ธ๐Ÿ›‘ Failed to Compile. See Errors Above +Incremental build failed. Error:  โŒ Failed to Compile. See Errors Above diff --git a/rewatch/tests/snapshots/remove-file.txt b/rewatch/tests/snapshots/remove-file.txt index 402cff956b..d17ec131a4 100644 --- a/rewatch/tests/snapshots/remove-file.txt +++ b/rewatch/tests/snapshots/remove-file.txt @@ -1,15 +1,10 @@ -[1/7] ๐Ÿ“ฆ Building package tree... - [1/7] ๐Ÿ“ฆ Built package tree in 0.00s -[2/7] ๐Ÿ•ต๏ธ Finding source files... - [2/7] ๐Ÿ•ต๏ธ Found source files in 0.00s -[3/7] ๐Ÿ“ Reading compile state... - [3/7] ๐Ÿ“ Read compile state 0.00s -[4/7] ๐Ÿงน Cleaning up previous build... - [4/7] ๐Ÿงน Cleaned 1/11 0.00s +[1/7] ๐Ÿ“ฆ Building package tree... [1/7] ๐Ÿ“ฆ Built package tree in 0.00s +[2/7] ๐Ÿ‘€ Finding source files... [2/7] ๐Ÿ‘€ Found source files in 0.00s +[3/7] ๐Ÿ“ Reading compile state... [3/7] ๐Ÿ“ Read compile state 0.00s +[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 1/94 0.00s  [5/7] ๐Ÿงฑ Parsed 0 source files in 0.00s - [6/7] ๏ธ๐ŸŒด Collected deps in 0.00s - [7/7] ๏ธ๐Ÿ›‘ Compiled 1 modules in 0.00s -ERROR: + [6/7] ๐ŸŒด Collected deps in 0.00s + [7/7] โŒ Compiled 1 modules in 0.00s We've found a bug for you! /packages/dep01/src/Dep01.res:3:9-17 @@ -22,10 +17,9 @@ ERROR: The module or file Dep02 can't be found. - If it's a third-party dependency: - - Did you add it to the "bs-dependencies" or "bs-dev-dependencies" in rescript.json? - - Did you include the file's directory to the "sources" in rescript.json? + - Did you add it to the "bs-dependencies" or "bs-dev-dependencies" in bsconfig.json? + - Did you include the file's directory to the "sources" in bsconfig.json? -ERROR: -Incremental build failed. Error:  ๏ธ๐Ÿ›‘ Failed to Compile. See Errors Above +Incremental build failed. Error:  โŒ Failed to Compile. See Errors Above diff --git a/rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt b/rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt index bafc2ba959..72fedd6dd3 100644 --- a/rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt +++ b/rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt @@ -1,15 +1,10 @@ -[1/7] ๐Ÿ“ฆ Building package tree... - [1/7] ๐Ÿ“ฆ Built package tree in 0.00s -[2/7] ๐Ÿ•ต๏ธ Finding source files... - [2/7] ๐Ÿ•ต๏ธ Found source files in 0.00s -[3/7] ๐Ÿ“ Reading compile state... - [3/7] ๐Ÿ“ Read compile state 0.00s -[4/7] ๐Ÿงน Cleaning up previous build... - [4/7] ๐Ÿงน Cleaned 2/11 0.00s +[1/7] ๐Ÿ“ฆ Building package tree... [1/7] ๐Ÿ“ฆ Built package tree in 0.00s +[2/7] ๐Ÿ‘€ Finding source files... [2/7] ๐Ÿ‘€ Found source files in 0.00s +[3/7] ๐Ÿ“ Reading compile state... [3/7] ๐Ÿ“ Read compile state 0.00s +[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 2/94 0.00s  [5/7] ๐Ÿงฑ Parsed 2 source files in 0.00s - [6/7] ๏ธ๐ŸŒด Collected deps in 0.00s - [7/7] ๏ธ๐Ÿ›‘ Compiled 3 modules in 0.00s -ERROR: + [6/7] ๐ŸŒด Collected deps in 0.00s + [7/7] โŒ Compiled 3 modules in 0.00s We've found a bug for you! /packages/new-namespace/src/NS_alias.res:2:1-16 @@ -20,12 +15,11 @@ ERROR: The module or file Other_module can't be found. - If it's a third-party dependency: - - Did you add it to the "bs-dependencies" or "bs-dev-dependencies" in rescript.json? - - Did you include the file's directory to the "sources" in rescript.json? + - Did you add it to the "bs-dependencies" or "bs-dev-dependencies" in bsconfig.json? + - Did you include the file's directory to the "sources" in bsconfig.json? Hint: Did you mean Other_module2? -ERROR: -Incremental build failed. Error:  ๏ธ๐Ÿ›‘ Failed to Compile. See Errors Above +Incremental build failed. Error:  โŒ Failed to Compile. See Errors Above diff --git a/rewatch/tests/snapshots/rename-file-internal-dep.txt b/rewatch/tests/snapshots/rename-file-internal-dep.txt index 69e10d6ca2..bb0e0f148e 100644 --- a/rewatch/tests/snapshots/rename-file-internal-dep.txt +++ b/rewatch/tests/snapshots/rename-file-internal-dep.txt @@ -1,15 +1,10 @@ -[1/7] ๐Ÿ“ฆ Building package tree... - [1/7] ๐Ÿ“ฆ Built package tree in 0.00s -[2/7] ๐Ÿ•ต๏ธ Finding source files... - [2/7] ๐Ÿ•ต๏ธ Found source files in 0.00s -[3/7] ๐Ÿ“ Reading compile state... - [3/7] ๐Ÿ“ Read compile state 0.00s -[4/7] ๐Ÿงน Cleaning up previous build... - [4/7] ๐Ÿงน Cleaned 2/11 0.00s +[1/7] ๐Ÿ“ฆ Building package tree... [1/7] ๐Ÿ“ฆ Built package tree in 0.00s +[2/7] ๐Ÿ‘€ Finding source files... [2/7] ๐Ÿ‘€ Found source files in 0.00s +[3/7] ๐Ÿ“ Reading compile state... [3/7] ๐Ÿ“ Read compile state 0.00s +[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 2/94 0.00s  [5/7] ๐Ÿงฑ Parsed 2 source files in 0.00s - [6/7] ๏ธ๐ŸŒด Collected deps in 0.00s - [7/7] ๏ธ๐Ÿ›‘ Compiled 2 modules in 0.00s -ERROR: + [6/7] ๐ŸŒด Collected deps in 0.00s + [7/7] โŒ Compiled 2 modules in 0.00s We've found a bug for you! /packages/main/src/Main.res:4:8-24 @@ -22,10 +17,9 @@ ERROR: The module or file InternalDep can't be found. - If it's a third-party dependency: - - Did you add it to the "bs-dependencies" or "bs-dev-dependencies" in rescript.json? - - Did you include the file's directory to the "sources" in rescript.json? + - Did you add it to the "bs-dependencies" or "bs-dev-dependencies" in bsconfig.json? + - Did you include the file's directory to the "sources" in bsconfig.json? -ERROR: -Incremental build failed. Error:  ๏ธ๐Ÿ›‘ Failed to Compile. See Errors Above +Incremental build failed. Error:  โŒ Failed to Compile. See Errors Above diff --git a/rewatch/tests/snapshots/rename-file-with-interface.txt b/rewatch/tests/snapshots/rename-file-with-interface.txt index 9927321c2f..45d05ea95f 100644 --- a/rewatch/tests/snapshots/rename-file-with-interface.txt +++ b/rewatch/tests/snapshots/rename-file-with-interface.txt @@ -1,15 +1,11 @@ -[1/7] ๐Ÿ“ฆ Building package tree... - [1/7] ๐Ÿ“ฆ Built package tree in 0.00s -[2/7] ๐Ÿ•ต๏ธ Finding source files... -WARN: +[1/7] ๐Ÿ“ฆ Building package tree... [1/7] ๐Ÿ“ฆ Built package tree in 0.00s +[2/7] ๐Ÿ‘€ Finding source files...WARN:  No implementation file found for interface file (skipping): src/ModuleWithInterface.resi - [2/7] ๐Ÿ•ต๏ธ Found source files in 0.00s -[3/7] ๐Ÿ“ Reading compile state... - [3/7] ๐Ÿ“ Read compile state 0.00s -[4/7] ๐Ÿงน Cleaning up previous build... - [4/7] ๐Ÿงน Cleaned 2/11 0.00s + [2/7] ๐Ÿ‘€ Found source files in 0.00s +[3/7] ๐Ÿ“ Reading compile state... [3/7] ๐Ÿ“ Read compile state 0.00s +[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 2/94 0.00s  [5/7] ๐Ÿงฑ Parsed 1 source files in 0.00s - [6/7] ๏ธ๐ŸŒด Collected deps in 0.00s - [7/7] โš”๏ธ Compiled 1 modules in 0.00s + [6/7] ๐ŸŒด Collected deps in 0.00s + [7/7] ๐Ÿคบ Compiled 2 modules in 0.00s  โœจ Finished Compilation in 0.00s diff --git a/rewatch/tests/snapshots/rename-file.txt b/rewatch/tests/snapshots/rename-file.txt index d8206e1b53..7965bd423b 100644 --- a/rewatch/tests/snapshots/rename-file.txt +++ b/rewatch/tests/snapshots/rename-file.txt @@ -1,13 +1,9 @@ -[1/7] ๐Ÿ“ฆ Building package tree... - [1/7] ๐Ÿ“ฆ Built package tree in 0.00s -[2/7] ๐Ÿ•ต๏ธ Finding source files... - [2/7] ๐Ÿ•ต๏ธ Found source files in 0.00s -[3/7] ๐Ÿ“ Reading compile state... - [3/7] ๐Ÿ“ Read compile state 0.00s -[4/7] ๐Ÿงน Cleaning up previous build... - [4/7] ๐Ÿงน Cleaned 1/11 0.00s +[1/7] ๐Ÿ“ฆ Building package tree... [1/7] ๐Ÿ“ฆ Built package tree in 0.00s +[2/7] ๐Ÿ‘€ Finding source files... [2/7] ๐Ÿ‘€ Found source files in 0.00s +[3/7] ๐Ÿ“ Reading compile state... [3/7] ๐Ÿ“ Read compile state 0.00s +[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 1/94 0.00s  [5/7] ๐Ÿงฑ Parsed 1 source files in 0.00s - [6/7] ๏ธ๐ŸŒด Collected deps in 0.00s - [7/7] โš”๏ธ Compiled 1 modules in 0.00s + [6/7] ๐ŸŒด Collected deps in 0.00s + [7/7] ๐Ÿคบ Compiled 1 modules in 0.00s  โœจ Finished Compilation in 0.00s diff --git a/rewatch/tests/snapshots/rename-interface-file.txt b/rewatch/tests/snapshots/rename-interface-file.txt index 50dcd91249..be2cd61a21 100644 --- a/rewatch/tests/snapshots/rename-interface-file.txt +++ b/rewatch/tests/snapshots/rename-interface-file.txt @@ -1,15 +1,11 @@ -[1/7] ๐Ÿ“ฆ Building package tree... - [1/7] ๐Ÿ“ฆ Built package tree in 0.00s -[2/7] ๐Ÿ•ต๏ธ Finding source files... -WARN: +[1/7] ๐Ÿ“ฆ Building package tree... [1/7] ๐Ÿ“ฆ Built package tree in 0.00s +[2/7] ๐Ÿ‘€ Finding source files...WARN:  No implementation file found for interface file (skipping): src/ModuleWithInterface2.resi - [2/7] ๐Ÿ•ต๏ธ Found source files in 0.00s -[3/7] ๐Ÿ“ Reading compile state... - [3/7] ๐Ÿ“ Read compile state 0.00s -[4/7] ๐Ÿงน Cleaning up previous build... - [4/7] ๐Ÿงน Cleaned 1/11 0.00s + [2/7] ๐Ÿ‘€ Found source files in 0.00s +[3/7] ๐Ÿ“ Reading compile state... [3/7] ๐Ÿ“ Read compile state 0.00s +[4/7] ๐Ÿงน Cleaning up previous build... [4/7] ๐Ÿงน Cleaned 1/94 0.00s  [5/7] ๐Ÿงฑ Parsed 1 source files in 0.00s - [6/7] ๏ธ๐ŸŒด Collected deps in 0.00s - [7/7] โš”๏ธ Compiled 1 modules in 0.00s + [6/7] ๐ŸŒด Collected deps in 0.00s + [7/7] ๐Ÿคบ Compiled 2 modules in 0.00s  โœจ Finished Compilation in 0.00s diff --git a/rewatch/tests/suffix.sh b/rewatch/tests/suffix.sh index 6790d99fb5..3768005297 100755 --- a/rewatch/tests/suffix.sh +++ b/rewatch/tests/suffix.sh @@ -25,13 +25,13 @@ else fi # Count files with new extension -file_count=$(find . -name *.res.js | wc -l) +file_count=$(find ./packages -name *.res.js | wc -l) -if [ "$file_count" -eq 10 ]; +if [ "$file_count" -eq 24 ]; then success "Found files with correct suffix" else - error "Suffix not correctly used" + error "Suffix not correctly used, got $file_count files" exit 1 fi diff --git a/rewatch/tests/suite-ci.sh b/rewatch/tests/suite-ci.sh index bcec5677f7..60970745e1 100755 --- a/rewatch/tests/suite-ci.sh +++ b/rewatch/tests/suite-ci.sh @@ -2,23 +2,35 @@ # Make sure we are in the right directory cd $(dirname $0) +# Get rewatch executable location from the first argument or use default +if [ -n "$1" ]; then + REWATCH_EXECUTABLE="$1" +else + REWATCH_EXECUTABLE="../target/release/rewatch" +fi +export REWATCH_EXECUTABLE + source ./utils.sh -bold "Check if build exists" -if test -f ../target/release/rewatch; -then - success "Build exists" -else - error "Build does not exist. Exiting..." - exit 1 -fi +bold "Rescript version" +(cd ../testrepo && ./node_modules/.bin/rescript -v) + +# we need to reset the yarn.lock and package.json to the original state +# so there is not diff in git. The CI will install new ReScript package +bold "Reset package.json and yarn.lock" +git checkout ../testrepo/yarn.lock &> /dev/null +git checkout ../testrepo/package.json &> /dev/null +success "Reset package.json and yarn.lock" bold "Make sure the testrepo is clean" -if git diff --exit-code ../testrepo &> /dev/null; +if git diff --exit-code ../testrepo &> diff.txt; then + rm diff.txt success "Testrepo has no changes" else error "Testrepo is not clean to start with" + cat diff.txt + rm diff.txt exit 1 fi diff --git a/rewatch/tests/utils.sh b/rewatch/tests/utils.sh index 3f6218d4c5..f2ee211ddd 100644 --- a/rewatch/tests/utils.sh +++ b/rewatch/tests/utils.sh @@ -3,7 +3,8 @@ overwrite() { echo -e "\r\033[1A\033[0K$@"; } success() { echo -e "- โœ… \033[32m$1\033[0m"; } error() { echo -e "- ๐Ÿ›‘ \033[31m$1\033[0m"; } bold() { echo -e "\033[1m$1\033[0m"; } -rewatch() { RUST_BACKTRACE=1 ../target/release/rewatch --no-timing=true $1; } +rewatch() { RUST_BACKTRACE=1 $REWATCH_EXECUTABLE --no-timing=true $@; } +rewatch_bg() { RUST_BACKTRACE=1 nohup $REWATCH_EXECUTABLE --no-timing=true $@; } replace() { if [[ $OSTYPE == 'darwin'* ]]; diff --git a/rewatch/tests/watch.sh b/rewatch/tests/watch.sh index 20546d865b..e3a24c0997 100755 --- a/rewatch/tests/watch.sh +++ b/rewatch/tests/watch.sh @@ -13,10 +13,10 @@ fi exit_watcher() { # we need to kill the parent process (rewatch) - kill $(pgrep -P $!); + rm lib/rewatch.lock } -rewatch watch &>/dev/null & +rewatch_bg watch > /dev/null 2>&1 & success "Watcher Started" echo 'Js.log("added-by-test")' >> ./packages/main/src/Main.res diff --git a/runtime/rescript.json b/runtime/rescript.json index b9e194db8f..0d7134657b 100644 --- a/runtime/rescript.json +++ b/runtime/rescript.json @@ -5,6 +5,16 @@ "dir": "." } ], + "package-specs": [ + { + "module": "commonjs", + "in-source": false + }, + { + "module": "esmodule", + "in-source": false + } + ], "bsc-flags": [ "-make-runtime", "-nostdlib", diff --git a/scripts/buildRuntimeRewatch.sh b/scripts/buildRuntimeRewatch.sh new file mode 100755 index 0000000000..78a8d65d9a --- /dev/null +++ b/scripts/buildRuntimeRewatch.sh @@ -0,0 +1,12 @@ +#!/bin/bash +set -e +shopt -s extglob + +(cd runtime && ../cli/rewatch.js clean) +(cd runtime && ../cli/rewatch.js build) + +cp runtime/lib/es6/!(Pervasives_mini).js lib/es6 +cp runtime/lib/js/!(Pervasives_mini).js lib/js +cp runtime/lib/bs/!(Pervasives_mini|Belt_internal*).cmi lib/ocaml/ +cp runtime/lib/bs/!(Pervasives_mini).@(cmi|cmj|cmt|cmti) lib/ocaml/ +cp runtime/!(Pervasives_mini).@(res|resi) lib/ocaml/ \ No newline at end of file