diff --git a/.cargo/config b/.cargo/config new file mode 100644 index 00000000000000..ac2b23f8146846 --- /dev/null +++ b/.cargo/config @@ -0,0 +1,2 @@ +[target.x86_64-pc-windows-msvc] +rustflags = ["-C", "target-feature=+crt-static"] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 14db798c38d48a..ffe5a25c4d244d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,33 +4,37 @@ on: [push, pull_request] jobs: build: - name: ${{ matrix.kind }} ${{ matrix.os }} - runs-on: ${{ matrix.os }} + name: ${{ matrix.config.kind }} ${{ matrix.config.os }} + if: | + github.event_name == 'push' || + !startsWith(github.event.pull_request.head.label, 'denoland:') + runs-on: ${{ matrix.config.os }} timeout-minutes: 60 strategy: matrix: - os: [macOS-latest, ubuntu-16.04, windows-2019] - kind: ['test_release', 'test_debug', 'bench', 'lint'] - exclude: - - os: windows-2019 - kind: 'bench' - - os: macOS-latest - kind: 'bench' - - - os: windows-2019 - kind: 'lint' + config: - os: macOS-latest - kind: 'lint' - + kind: test_release - os: windows-2019 - kind: 'test_debug' - - os: macOS-latest - kind: 'test_debug' + kind: test_release + - os: ubuntu-16.04 + kind: test_release + - os: ubuntu-16.04 + kind: test_debug + - os: ubuntu-16.04 + kind: bench + - os: ubuntu-16.04 + kind: lint + + # Always run master branch builds to completion. This allows the cache to + # stay mostly up-to-date in situations where a single job fails due to + # e.g. a flaky test. + fail-fast: + ${{ github.event_name != 'push' || github.ref != 'refs/heads/master' }} env: + CARGO_INCREMENTAL: 0 RUST_BACKTRACE: full - RUSTC_WRAPPER: sccache - V8_BINARY: true steps: - name: Configure git @@ -46,27 +50,10 @@ jobs: submodules: true - name: Create source tarballs (release, linux) - if: startsWith(matrix.os, 'ubuntu') && matrix.kind == 'test_release' && startsWith(github.ref, 'refs/tags/') && github.repository == 'denoland/deno' + if: startsWith(matrix.config.os, 'ubuntu') && matrix.config.kind == 'test_release' && startsWith(github.ref, 'refs/tags/') && github.repository == 'denoland/deno' run: | mkdir -p target/release - tar --exclude=".git*" --exclude=target --exclude=deno_typescript/typescript/tests --exclude=third_party/cpplint --exclude=third_party/node_modules --exclude=third_party/python_packages --exclude=third_party/prebuilt -czvf target/release/deno_src.tar.gz -C .. deno - - # Cache https://github.com/actions/cache/blob/master/examples.md#rust---cargo - - name: Cache cargo registry - uses: actions/cache@v1 - with: - path: ~/.cargo/registry - key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} - - name: Cache cargo index - uses: actions/cache@v1 - with: - path: ~/.cargo/git - key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }} - - name: Cache cargo build - uses: actions/cache@v1 - with: - path: target - key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }} + tar --exclude=.cargo_home --exclude=".git*" --exclude=target --exclude=deno_typescript/typescript/tests --exclude=third_party/cpplint --exclude=third_party/node_modules --exclude=third_party/python_packages --exclude=third_party/prebuilt -czvf target/release/deno_src.tar.gz -C .. deno - name: Install rust uses: hecrj/setup-rust-action@v1 @@ -74,7 +61,7 @@ jobs: rust-version: "1.42.0" - name: Install clippy and rustfmt - if: matrix.kind == 'lint' + if: matrix.config.kind == 'lint' run: | rustup component add clippy rustup component add rustfmt @@ -86,35 +73,13 @@ jobs: architecture: x64 - name: Remove unused versions of Python - if: startsWith(matrix.os, 'windows') + if: startsWith(matrix.config.os, 'windows') run: |- $env:PATH -split ";" | Where-Object { Test-Path "$_\python.exe" } | Select-Object -Skip 1 | ForEach-Object { Move-Item "$_" "$_.disabled" } - - name: Environment (linux) - if: startsWith(matrix.os, 'ubuntu') - # In order to test the installer scripts in std we need a deno - # executable in the path. See - # https://github.com/denoland/deno/blob/27cd2c97f18c0392bc04c66b786717b2bc677315/std/installer/mod.ts#L185-L193 - # TODO(ry) This path modification should rather be done in "cargo test". - run: | - echo ::add-path::`pwd`/third_party/prebuilt/linux64 - echo ::add-path::`pwd`/target/release - - - name: Environment (mac) - if: startsWith(matrix.os, 'macOS') - run: | - echo ::add-path::`pwd`/third_party/prebuilt/mac - echo ::add-path::`pwd`/target/release - - - name: Environment (windows) - if: startsWith(matrix.os, 'windows') - run: | - echo ::add-path::$(pwd)\third_party\prebuilt\win - echo ::add-path::$(pwd)\target\release - - name: Log versions run: | node -v @@ -122,56 +87,60 @@ jobs: rustc --version cargo --version - - name: Start sccache (azure) - if: startsWith(matrix.os, 'windows') == false - env: - SCCACHE_AZURE_BLOB_CONTAINER: deno-sccache2 - SCCACHE_AZURE_CONNECTION_STRING: ${{ secrets.SCCACHE_AZURE_CONNECTION_STRING || 'DefaultEndpointsProtocol=https;AccountName=denosccache;EndpointSuffix=core.windows.net' }} - SCCACHE_IDLE_TIMEOUT: 0 - run: sccache --start-server - - # TODO(ry) We want to use Azure because it's cheaper. However sccache on - # Windows has a bug when using Azure. The bug manifests itself as a - # "multiple input files" error message. - - name: Start sccache (s3) - if: startsWith(matrix.os, 'windows') - env: - AWS_ACCESS_KEY_ID: AKIAIVRN52PLDBP55LBQ - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - SCCACHE_BUCKET: deno-sccache - SCCACHE_IDLE_TIMEOUT: 0 - run: sccache --start-server + - name: Configure cargo data directory + # After this point, all cargo registry and crate data is stored in + # $GITHUB_WORKSPACE/.cargo_home. This allows us to cache only the files + # that are needed during the build process. Additionally, this works + # around a bug in the 'cache' action that causes directories outside of + # the workspace dir to be saved/restored incorrectly. + run: echo "::set-env name=CARGO_HOME::$(pwd)/.cargo_home" + + - name: Cache + uses: actions/cache@master + with: + # Note: crates from the denoland/deno git repo always get rebuilt, + # and their outputs ('deno', 'libdeno.rlib' etc.) are quite big, + # so we cache only those subdirectories of target/{debug|release} that + # contain the build output for crates that come from the registry. + path: |- + .cargo_home + target/*/.* + target/*/build + target/*/deps + target/*/gn_out + key: + ${{ matrix.config.os }}-${{ matrix.config.kind }}-${{ hashFiles('Cargo.lock') }} - name: lint.py - if: matrix.kind == 'lint' + if: matrix.config.kind == 'lint' run: python ./tools/lint.py - name: test_format.py - if: matrix.kind == 'lint' + if: matrix.config.kind == 'lint' run: python ./tools/test_format.py - name: Build release - if: matrix.kind == 'test_release' || matrix.kind == 'bench' + if: matrix.config.kind == 'test_release' || matrix.config.kind == 'bench' run: cargo build --release --locked --all-targets - name: Build debug - if: matrix.kind == 'test_debug' + if: matrix.config.kind == 'test_debug' run: cargo build --locked --all-targets - name: Test release - if: matrix.kind == 'test_release' + if: matrix.config.kind == 'test_release' run: cargo test --release --locked --all-targets - name: Test debug - if: matrix.kind == 'test_debug' + if: matrix.config.kind == 'test_debug' run: cargo test --locked --all-targets - name: Run Benchmarks - if: matrix.kind == 'bench' + if: matrix.config.kind == 'bench' run: python ./tools/benchmark.py --release - name: Post Benchmarks - if: matrix.kind == 'bench' && github.ref == 'refs/heads/master' && github.repository == 'denoland/deno' + if: matrix.config.kind == 'bench' && github.ref == 'refs/heads/master' && github.repository == 'denoland/deno' env: DENOBOT_PAT: ${{ secrets.DENOBOT_PAT }} run: | @@ -185,33 +154,52 @@ jobs: git push origin gh-pages - name: Worker info - if: matrix.kind == 'bench' + if: matrix.config.kind == 'bench' run: | cat /proc/cpuinfo cat /proc/meminfo - name: Pre-release (linux) - if: startsWith(matrix.os, 'ubuntu') && matrix.kind == 'test_release' - run: gzip -f -S _linux_x64.gz target/release/deno + if: startsWith(matrix.config.os, 'ubuntu') && matrix.config.kind == 'test_release' + run: | + cd target/release + # New filename + zip -r deno-x86_64-unknown-linux-gnu.zip deno + # Old filename (remove once deno_install updated) + gzip -f -S _linux_x64.gz deno - name: Pre-release (mac) - if: startsWith(matrix.os, 'macOS') && matrix.kind == 'test_release' - run: gzip -f -S _osx_x64.gz target/release/deno + if: startsWith(matrix.config.os, 'macOS') && matrix.config.kind == 'test_release' + run: | + cd target/release + # New filename + zip -r deno-x86_64-apple-darwin.zip deno + # Old filename (remove once deno_install updated) + gzip -f -S _osx_x64.gz deno - name: Pre-release (windows) - if: startsWith(matrix.os, 'windows') && matrix.kind == 'test_release' - run: Compress-Archive -CompressionLevel Optimal -Force -Path target/release/deno.exe -DestinationPath target/release/deno_win_x64.zip + if: startsWith(matrix.config.os, 'windows') && matrix.config.kind == 'test_release' + run: | + # Old filename (remove once deno_install updated) + Compress-Archive -CompressionLevel Optimal -Force -Path target/release/deno.exe -DestinationPath target/release/deno_win_x64.zip + # New filename + Compress-Archive -CompressionLevel Optimal -Force -Path target/release/deno.exe -DestinationPath target/release/deno-x86_64-pc-windows-msvc.zip - name: Release uses: softprops/action-gh-release@v1 - if: matrix.kind == 'test_release' && startsWith(github.ref, 'refs/tags/') && github.repository == 'denoland/deno' + if: matrix.config.kind == 'test_release' && startsWith(github.ref, 'refs/tags/') && github.repository == 'denoland/deno' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: files: | + # Old filenames (remove once deno_install updated) target/release/deno_win_x64.zip target/release/deno_linux_x64.gz target/release/deno_osx_x64.gz + # New filenames + target/release/deno-x86_64-pc-windows-msvc.zip + target/release/deno-x86_64-unknown-linux-gnu.zip + target/release/deno-x86_64-apple-darwin.zip target/release/deno_src.tar.gz draft: true @@ -219,8 +207,8 @@ jobs: if: > startsWith(github.ref, 'refs/tags/') && github.repository == 'denoland/deno' && - matrix.kind == 'test_release' && - startsWith(matrix.os, 'ubuntu') + matrix.config.kind == 'test_release' && + startsWith(matrix.config.os, 'ubuntu') env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} run: | @@ -232,6 +220,3 @@ jobs: cd ../cli sleep 30 cargo publish - - - name: Stop sccache - run: sccache --stop-server diff --git a/.gitignore b/.gitignore index 8d1a2b8a1324ce..eff476d86e6f5b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.pyc *.swp +/.cargo_home/ /.idea/ /.vscode/ gclient_config.py_entries diff --git a/Cargo.lock b/Cargo.lock index 0105ea6a396b9f..00d54efa9b414f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -169,6 +169,12 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" +[[package]] +name = "base64" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5ca2cd0adc3f48f9e9ea5a6bbdf9ccc0bfade884847e484d452414c7ccffb3" + [[package]] name = "bitflags" version = "1.2.1" @@ -186,6 +192,27 @@ dependencies = [ "constant_time_eq", ] +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding", + "byte-tools", + "byteorder", + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", +] + [[package]] name = "brotli" version = "3.3.0" @@ -207,12 +234,28 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "buf_redux" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f" +dependencies = [ + "memchr", + "safemem", +] + [[package]] name = "bumpalo" version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f359dc14ff8911330a51ef78022d376f25ed00248912803b58f00cb1c27f742" +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + [[package]] name = "byteorder" version = "1.3.4" @@ -416,7 +459,7 @@ dependencies = [ [[package]] name = "deno" -version = "0.36.0" +version = "0.38.0" dependencies = [ "atty", "base64 0.11.0", @@ -435,7 +478,7 @@ dependencies = [ "indexmap", "lazy_static", "libc", - "log", + "log 0.4.8", "nix", "notify", "os_pipe", @@ -445,18 +488,26 @@ dependencies = [ "reqwest", "ring", "rustyline", + "semver-parser 0.9.0", "serde", "serde_derive", "serde_json", "sourcemap", + "swc_common", + "swc_ecma_ast", + "swc_ecma_parser", + "swc_ecma_parser_macros", "sys-info", "tempfile", "termcolor", "tokio", "tokio-rustls", + "tokio-tungstenite", "url 2.1.1", "utime", + "uuid", "walkdir", + "warp", "webpki", "webpki-roots 0.19.0", "winapi 0.3.8", @@ -464,14 +515,14 @@ dependencies = [ [[package]] name = "deno_core" -version = "0.36.0" +version = "0.38.0" dependencies = [ "derive_deref", "downcast-rs", "futures 0.3.4", "lazy_static", "libc", - "log", + "log 0.4.8", "rusty_v8", "serde_json", "tokio", @@ -480,7 +531,7 @@ dependencies = [ [[package]] name = "deno_typescript" -version = "0.36.0" +version = "0.38.0" dependencies = [ "deno_core", "serde", @@ -498,6 +549,15 @@ dependencies = [ "syn 0.15.44", ] +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array", +] + [[package]] name = "dirs" version = "2.0.2" @@ -551,24 +611,25 @@ checksum = "52ba6eb47c2131e784a38b726eb54c1e1484904f013e576a25354d0124161af6" [[package]] name = "dprint-core" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d1aa8ea00ca5fb5a92278a6596b14b0f8336c3d0b6c6cbde4b46817dcd2ed0" +checksum = "8fb2332f10c6acf94b5d469ed993cf52ed7a1369b80523fb9cb21fa10c6b6887" dependencies = [ "serde", ] [[package]] name = "dprint-plugin-typescript" -version = "0.8.1" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dcf2ac362cb71dac70767cd23fba63063fb47bdb84ccef8b42ba03e17c0451d" +checksum = "66d1fc740f63f2fd73c63d4c55632f81fa41ec84ae531258e0e1e014bb3eb30a" dependencies = [ "dprint-core", "serde", "swc_common", "swc_ecma_ast", "swc_ecma_parser", + "swc_ecma_parser_macros", ] [[package]] @@ -624,6 +685,12 @@ dependencies = [ "backtrace", ] +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + [[package]] name = "filetime" version = "0.2.8" @@ -826,6 +893,15 @@ dependencies = [ "byteorder", ] +[[package]] +name = "generic-array" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" +dependencies = [ + "typenum", +] + [[package]] name = "getrandom" version = "0.1.14" @@ -856,7 +932,7 @@ dependencies = [ "futures-util", "http", "indexmap", - "log", + "log 0.4.8", "slab", "tokio", "tokio-util", @@ -872,6 +948,31 @@ dependencies = [ "autocfg 0.1.7", ] +[[package]] +name = "headers" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed18eb2459bf1a09ad2d6b1547840c3e5e62882fa09b9a6a20b1de8e3228848f" +dependencies = [ + "base64 0.12.0", + "bitflags", + "bytes 0.5.4", + "headers-core", + "http", + "mime 0.3.16", + "sha-1", + "time", +] + +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http", +] + [[package]] name = "hermit-abi" version = "0.1.8" @@ -923,7 +1024,7 @@ dependencies = [ "http-body", "httparse", "itoa", - "log", + "log 0.4.8", "net2", "pin-project", "time", @@ -942,7 +1043,7 @@ dependencies = [ "ct-logs", "futures-util", "hyper", - "log", + "log 0.4.8", "rustls", "rustls-native-certs", "tokio", @@ -1021,6 +1122,15 @@ dependencies = [ "libc", ] +[[package]] +name = "input_buffer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a8a95243d5a0398cae618ec29477c6e3cb631152be5c19481f80bc71559754" +dependencies = [ + "bytes 0.5.4", +] + [[package]] name = "iovec" version = "0.1.4" @@ -1083,6 +1193,15 @@ dependencies = [ "scopeguard", ] +[[package]] +name = "log" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" +dependencies = [ + "log 0.4.8", +] + [[package]] name = "log" version = "0.4.8" @@ -1110,20 +1229,41 @@ version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" +[[package]] +name = "mime" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" +dependencies = [ + "log 0.3.9", +] + [[package]] name = "mime" version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +[[package]] +name = "mime_guess" +version = "1.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216929a5ee4dd316b1702eedf5e74548c123d370f47841ceaac38ca154690ca3" +dependencies = [ + "mime 0.2.6", + "phf", + "phf_codegen", + "unicase 1.4.2", +] + [[package]] name = "mime_guess" version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212" dependencies = [ - "mime", - "unicase", + "mime 0.3.16", + "unicase 2.6.0", ] [[package]] @@ -1147,7 +1287,7 @@ dependencies = [ "iovec", "kernel32-sys", "libc", - "log", + "log 0.4.8", "miow 0.2.1", "net2", "slab", @@ -1161,7 +1301,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" dependencies = [ "lazycell", - "log", + "log 0.4.8", "mio", "slab", ] @@ -1172,7 +1312,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f5e374eff525ce1c5b7687c4cef63943e7686524a387933ad27ca7ec43779cb3" dependencies = [ - "log", + "log 0.4.8", "mio", "miow 0.3.3", "winapi 0.3.8", @@ -1211,6 +1351,24 @@ dependencies = [ "winapi 0.3.8", ] +[[package]] +name = "multipart" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136eed74cadb9edd2651ffba732b19a450316b680e4f48d6c79e905799e19d01" +dependencies = [ + "buf_redux", + "httparse", + "log 0.4.8", + "mime 0.2.6", + "mime_guess 1.8.8", + "quick-error", + "rand 0.6.5", + "safemem", + "tempfile", + "twoway", +] + [[package]] name = "net2" version = "0.2.33" @@ -1309,6 +1467,12 @@ version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b" +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + [[package]] name = "openssl-probe" version = "0.1.2" @@ -1400,23 +1564,62 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +[[package]] +name = "phf" +version = "0.7.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3da44b85f8e8dfaec21adae67f95d93244b2ecf6ad2a692320598dcc8e6dd18" +dependencies = [ + "phf_shared 0.7.24", +] + +[[package]] +name = "phf_codegen" +version = "0.7.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e" +dependencies = [ + "phf_generator 0.7.24", + "phf_shared 0.7.24", +] + +[[package]] +name = "phf_generator" +version = "0.7.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662" +dependencies = [ + "phf_shared 0.7.24", + "rand 0.6.5", +] + [[package]] name = "phf_generator" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" dependencies = [ - "phf_shared", + "phf_shared 0.8.0", "rand 0.7.3", ] +[[package]] +name = "phf_shared" +version = "0.7.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0" +dependencies = [ + "siphasher 0.2.3", + "unicase 1.4.2", +] + [[package]] name = "phf_shared" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" dependencies = [ - "siphasher", + "siphasher 0.3.1", ] [[package]] @@ -1519,6 +1722,12 @@ dependencies = [ "libc", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quote" version = "0.6.13" @@ -1778,9 +1987,9 @@ dependencies = [ "hyper-rustls", "js-sys", "lazy_static", - "log", - "mime", - "mime_guess", + "log 0.4.8", + "mime 0.3.16", + "mime_guess 2.0.3", "percent-encoding 2.1.0", "pin-project-lite", "rustls", @@ -1846,7 +2055,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0d4a31f5d68413404705d6982529b0e11a9aacd4839d1d6222ee3b8cb4015e1" dependencies = [ "base64 0.11.0", - "log", + "log 0.4.8", "ring", "sct", "webpki", @@ -1866,9 +2075,9 @@ dependencies = [ [[package]] name = "rusty_v8" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eebb25415f6eedee924beffe4386375adafeaa69694383139c77336e88d204c3" +checksum = "fee528081d3eb7efe829a0021063df092a241837f3c063fb825bf7aa8858f80c" dependencies = [ "bitflags", "cargo_gn", @@ -1886,7 +2095,7 @@ dependencies = [ "cfg-if", "dirs", "libc", - "log", + "log 0.4.8", "memchr", "nix", "unicode-segmentation", @@ -1901,6 +2110,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "535622e6be132bccd223f4bb2b8ac8d53cda3c7a6394944d3b2b33fb974f9d76" +[[package]] +name = "safemem" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" + [[package]] name = "same-file" version = "1.0.6" @@ -1970,7 +2185,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ - "semver-parser", + "semver-parser 0.7.0", ] [[package]] @@ -1979,6 +2194,12 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +[[package]] +name = "semver-parser" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b46e1121e8180c12ff69a742aabc4f310542b6ccb69f1691689ac17fdf8618aa" + [[package]] name = "serde" version = "1.0.104" @@ -2023,6 +2244,18 @@ dependencies = [ "url 2.1.1", ] +[[package]] +name = "sha-1" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" +dependencies = [ + "block-buffer", + "digest", + "fake-simd", + "opaque-debug", +] + [[package]] name = "signal-hook-registry" version = "1.2.0" @@ -2033,6 +2266,12 @@ dependencies = [ "libc", ] +[[package]] +name = "siphasher" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" + [[package]] name = "siphasher" version = "0.3.1" @@ -2108,7 +2347,7 @@ checksum = "2940c75beb4e3bf3a494cef919a747a2cb81e52571e212bfbd185074add7208a" dependencies = [ "lazy_static", "new_debug_unreachable", - "phf_shared", + "phf_shared 0.8.0", "precomputed-hash", "serde", ] @@ -2119,8 +2358,8 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f24c8e5e19d22a726626f1a5e16fe15b132dcf21d10177fa5a45ce7962996b97" dependencies = [ - "phf_generator", - "phf_shared", + "phf_generator 0.8.0", + "phf_shared 0.8.0", "proc-macro2 1.0.9", "quote 1.0.3", ] @@ -2174,7 +2413,7 @@ dependencies = [ "from_variant", "fxhash", "hashbrown", - "log", + "log 0.4.8", "parking_lot 0.7.1", "scoped-tls", "serde", @@ -2200,13 +2439,13 @@ dependencies = [ [[package]] name = "swc_ecma_parser" -version = "0.21.5" +version = "0.21.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9519ab89ac37f65eb7d58f892f89aaa4dc64979b660a029025dbb9ee2a2b2903" +checksum = "c7fd022bbe8fdd94649a0165a53dc7fbd850370a40609b9c3fddd404b99427fb" dependencies = [ "either", "enum_kind", - "log", + "log 0.4.8", "num-bigint", "once_cell", "regex", @@ -2369,7 +2608,7 @@ checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" dependencies = [ "bytes 0.4.12", "futures 0.1.29", - "log", + "log 0.4.8", ] [[package]] @@ -2395,6 +2634,19 @@ dependencies = [ "webpki", ] +[[package]] +name = "tokio-tungstenite" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8b8fe88007ebc363512449868d7da4389c9400072a3f666f212c7280082882a" +dependencies = [ + "futures 0.3.4", + "log 0.4.8", + "pin-project", + "tokio", + "tungstenite", +] + [[package]] name = "tokio-util" version = "0.2.0" @@ -2404,7 +2656,7 @@ dependencies = [ "bytes 0.5.4", "futures-core", "futures-sink", - "log", + "log 0.4.8", "pin-project-lite", "tokio", ] @@ -2421,13 +2673,56 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" +[[package]] +name = "tungstenite" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfea31758bf674f990918962e8e5f07071a3161bd7c4138ed23e416e1ac4264e" +dependencies = [ + "base64 0.11.0", + "byteorder", + "bytes 0.5.4", + "http", + "httparse", + "input_buffer", + "log 0.4.8", + "rand 0.7.3", + "sha-1", + "url 2.1.1", + "utf-8", +] + +[[package]] +name = "twoway" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1" +dependencies = [ + "memchr", +] + +[[package]] +name = "typenum" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" + +[[package]] +name = "unicase" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" +dependencies = [ + "version_check 0.1.5", +] + [[package]] name = "unicase" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" dependencies = [ - "version_check", + "version_check 0.9.1", ] [[package]] @@ -2500,6 +2795,18 @@ dependencies = [ "percent-encoding 2.1.0", ] +[[package]] +name = "urlencoding" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df3561629a8bb4c57e5a2e4c43348d9e29c7c29d9b1c4c1f47166deca8f37ed" + +[[package]] +name = "utf-8" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7" + [[package]] name = "utf8parse" version = "0.1.1" @@ -2517,12 +2824,27 @@ dependencies = [ "winapi 0.2.8", ] +[[package]] +name = "uuid" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11" +dependencies = [ + "rand 0.7.3", +] + [[package]] name = "vec_map" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" +[[package]] +name = "version_check" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" + [[package]] name = "version_check" version = "0.9.1" @@ -2552,10 +2874,36 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" dependencies = [ - "log", + "log 0.4.8", "try-lock", ] +[[package]] +name = "warp" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54cd1e2b3eb3539284d88b76a9afcf5e20f2ef2fab74db5b21a1c30d7d945e82" +dependencies = [ + "bytes 0.5.4", + "futures 0.3.4", + "headers", + "http", + "hyper", + "log 0.4.8", + "mime 0.3.16", + "mime_guess 2.0.3", + "multipart", + "pin-project", + "scoped-tls", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-tungstenite", + "tower-service", + "urlencoding", +] + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -2582,7 +2930,7 @@ checksum = "e0da9c9a19850d3af6df1cb9574970b566d617ecfaf36eb0b706b6f3ef9bd2f8" dependencies = [ "bumpalo", "lazy_static", - "log", + "log 0.4.8", "proc-macro2 1.0.9", "quote 1.0.3", "syn 1.0.16", diff --git a/Releases.md b/Releases.md index 301ae8628b19b1..c4fb7bf94f6a33 100644 --- a/Releases.md +++ b/Releases.md @@ -6,6 +6,63 @@ https://github.com/denoland/deno/releases We also have one-line install commands at https://github.com/denoland/deno_install +### v0.38.0 / 2020.03.28 + +- feat: Add "deno doc" subcommand (#4500) +- feat: Support --inspect, Chrome Devtools support (#4484) +- feat: Support Unix Domain Sockets (#4176) +- feat: add queueMicrotask to d.ts (#4477) +- feat: window.close() (#4474) +- fix(console): replace object abbreviation with line breaking (#4425) +- fix: add fsEvent notify::Error casts (#4488) +- fix: hide source line if error message longer than 150 chars (#4487) +- fix: parsing bug (#4483) +- fix: remove extra dot in Permission request output (#4471) +- refactor: rename ConsoleOptions to InspectOptions (#4493) +- upgrade: dprint 0.9.6 (#4509, #4491) +- upgrade: prettier 2 for internal code formatting (#4498) +- upgrade: rusty_v8 to v0.3.9 (#4505) + +### v0.37.1 / 2020.03.23 + +- fix: Statically link the C runtime library on Windows (#4469) + +### v0.37.0 / 2020.03.23 + +- BREAKING CHANGE: FileInfo.len renamed to FileName.size (#4338) +- BREAKING CHANGE: Rename Deno.run's args to cmd (#4444) +- feat(ci): Releases should all use zip and LLVM target triples (#4460) +- feat(console): Symbol.toStringTag and display Object symbol entries (#4388) +- feat(std/node): Add chmod Node polyfill (#4358) +- feat(std/node): Add node querystring polyfill (#4370) +- feat(std/node): Node polyfill for fs.chown and fs.close (#4377) +- feat(std/permissions): Add helper functions for permissions to std (#4258) +- feat(std/types): Provide types for React and ReactDOM (#4376) +- feat(test): Add option to skip tests (#4351) +- feat(test): Add support for jsx/tsx for deno test (#4369) +- feat: Add mode option to open/create (#4289) +- feat: Deno.test() sanitizes ops and resources (#4399) +- feat: Fetch should accept a FormData body (#4363) +- feat: First pass at "deno upgrade" (#4328) +- feat: Prvode way to build Deno without building V8 from source (#4412) +- feat: Remove `Object.prototype.__proto__` (#4341) +- fix(std/http): Close open connections on server close (#3679) +- fix(std/http): Properly await ops in a server test (#4436) +- fix(std/http): Remove bad error handling (#4435) +- fix(std/node): Node polyfill fsAppend rework (#4322) +- fix(std/node): Stack traces for modules imported via require (#4035) +- fix: Importing JSON doesn't work in bundles (#4404) +- fix: Simplify timer with macrotask callback (#4385) +- fix: Test runner ConnectionReset bug (#4424) +- fix: chmod should throw on Windows (#4446) +- fix: fetch closes unused body (#4393) +- perf: Optimize TextEncoder and TextDecoder (#4430, #4349) +- refactor: Improve test runner (#4336, #4352, #4356, #4371) +- refactor: Remove std/testing/runner.ts, use deno test (#4397, #4392) +- upgrade: Rust 1.42.0 (#4331) +- upgrade: Rust crates (#4412) +- upgrade: to rusty_v8 0.3.5 / v8 8.2.308 (#4364) + ### v0.36.0 / 2020.03.11 - BREAKING CHANGE: Remove Deno.errors.Other (#4249) diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 6dfa81477119c4..4f81afa06a8251 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno" -version = "0.36.0" +version = "0.38.0" license = "MIT" authors = ["the Deno authors"] edition = "2018" @@ -19,12 +19,12 @@ name = "deno" path = "main.rs" [build-dependencies] -deno_core = { path = "../core", version = "0.36.0" } -deno_typescript = { path = "../deno_typescript", version = "0.36.0" } +deno_core = { path = "../core", version = "0.38.0" } +deno_typescript = { path = "../deno_typescript", version = "0.38.0" } [dependencies] -deno_core = { path = "../core", version = "0.36.0" } -deno_typescript = { path = "../deno_typescript", version = "0.36.0" } +deno_core = { path = "../core", version = "0.38.0" } +deno_typescript = { path = "../deno_typescript", version = "0.38.0" } atty = "0.2.14" base64 = "0.11.0" @@ -33,7 +33,7 @@ byteorder = "1.3.4" clap = "2.33.0" dirs = "2.0.2" dlopen = "0.1.8" -dprint-plugin-typescript = "0.8.1" +dprint-plugin-typescript = "0.9.6" futures = { version = "0.3.4", features = ["compat", "io-compat"] } glob = "0.3.0" http = "0.2.0" @@ -54,13 +54,22 @@ sys-info = "=0.5.8" # 0.5.9 and 0.5.10 are broken on windows. sourcemap = "5.0.0" tempfile = "3.1.0" termcolor = "1.1.0" -tokio = { version = "0.2.13", features = ["rt-core", "tcp", "udp", "process", "fs", "blocking", "sync", "io-std", "macros", "time"] } +tokio = { version = "0.2.13", features = ["rt-core", "tcp", "udp", "uds", "process", "fs", "blocking", "sync", "io-std", "macros", "time"] } tokio-rustls = "0.13.0" url = "2.1.1" utime = "0.2.1" webpki = "0.21.2" webpki-roots = "0.19.0" walkdir = "2.3.1" +warp = "0.2.2" +semver-parser = "0.9.0" +# TODO(bartlomieju): make sure we're using exactly same versions +# of "swc_*" as dprint-plugin-typescript +swc_common = "=0.5.9" +swc_ecma_ast = "=0.18.1" +swc_ecma_parser = "=0.21.8" +swc_ecma_parser_macros = "=0.4.1" +uuid = { version = "0.8", features = ["v4"] } [target.'cfg(windows)'.dependencies] winapi = "0.3.8" @@ -71,6 +80,8 @@ nix = "0.14" # rustyline depends on 0.14, to avoid duplicates we do too. [dev-dependencies] os_pipe = "0.9.1" +# Used for testing inspector. Keep in-sync with warp. +tokio-tungstenite = { version = "0.10", features = ["connect"] } [target.'cfg(unix)'.dev-dependencies] pty = "0.2.2" diff --git a/cli/colors.rs b/cli/colors.rs index 5afd773cd59d50..764704a5b8d1ee 100644 --- a/cli/colors.rs +++ b/cli/colors.rs @@ -3,7 +3,7 @@ use regex::Regex; use std::env; use std::fmt; use std::io::Write; -use termcolor::Color::{Ansi256, Black, Red, White}; +use termcolor::Color::{Ansi256, Black, Magenta, Red, White}; use termcolor::{Ansi, ColorSpec, WriteColor}; #[cfg(windows)] @@ -88,6 +88,12 @@ pub fn green(s: String) -> impl fmt::Display { style(&s, style_spec) } +pub fn magenta(s: String) -> impl fmt::Display { + let mut style_spec = ColorSpec::new(); + style_spec.set_fg(Some(Magenta)); + style(&s, style_spec) +} + pub fn bold(s: String) -> impl fmt::Display { let mut style_spec = ColorSpec::new(); style_spec.set_bold(true); diff --git a/cli/compilers/ts.rs b/cli/compilers/ts.rs index 4f822dc2ce9b42..a74e4a0966e791 100644 --- a/cli/compilers/ts.rs +++ b/cli/compilers/ts.rs @@ -553,7 +553,9 @@ impl SourceMapGetter for TsCompiler { .try_resolve_and_get_source_file(script_name) .and_then(|out| { str::from_utf8(&out.source_code).ok().and_then(|v| { - let lines: Vec<&str> = v.lines().collect(); + // Do NOT use .lines(): it skips the terminating empty line. + // (due to internally using .split_terminator() instead of .split()) + let lines: Vec<&str> = v.split('\n').collect(); assert!(lines.len() > line); Some(lines[line].to_string()) }) diff --git a/cli/doc/class.rs b/cli/doc/class.rs new file mode 100644 index 00000000000000..635fd585a7d52b --- /dev/null +++ b/cli/doc/class.rs @@ -0,0 +1,207 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +use serde::Serialize; +use swc_common; +use swc_common::SourceMap; +use swc_common::Spanned; +use swc_ecma_ast; + +use super::function::function_to_function_def; +use super::function::FunctionDef; +use super::parser::DocParser; +use super::ts_type::ts_type_ann_to_def; +use super::ts_type::TsTypeDef; +use super::Location; +use super::ParamDef; + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ClassConstructorDef { + pub js_doc: Option, + pub accessibility: Option, + pub name: String, + pub params: Vec, + pub location: Location, +} + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ClassPropertyDef { + pub js_doc: Option, + pub ts_type: Option, + pub readonly: bool, + pub accessibility: Option, + pub is_abstract: bool, + pub is_static: bool, + pub name: String, + pub location: Location, +} + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ClassMethodDef { + pub js_doc: Option, + // pub ts_type: Option, + // pub readonly: bool, + pub accessibility: Option, + pub is_abstract: bool, + pub is_static: bool, + pub name: String, + pub kind: swc_ecma_ast::MethodKind, + pub function_def: FunctionDef, + pub location: Location, +} + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ClassDef { + // TODO: decorators, super_class, implements, + // type_params, super_type_params + pub is_abstract: bool, + pub constructors: Vec, + pub properties: Vec, + pub methods: Vec, +} + +fn prop_name_to_string( + source_map: &SourceMap, + prop_name: &swc_ecma_ast::PropName, +) -> String { + use swc_ecma_ast::PropName; + match prop_name { + PropName::Ident(ident) => ident.sym.to_string(), + PropName::Str(str_) => str_.value.to_string(), + PropName::Num(num) => num.value.to_string(), + PropName::Computed(comp_prop_name) => { + source_map.span_to_snippet(comp_prop_name.span).unwrap() + } + } +} + +pub fn get_doc_for_class_decl( + doc_parser: &DocParser, + class_decl: &swc_ecma_ast::ClassDecl, +) -> (String, ClassDef) { + let mut constructors = vec![]; + let mut methods = vec![]; + let mut properties = vec![]; + + for member in &class_decl.class.body { + use swc_ecma_ast::ClassMember::*; + + match member { + Constructor(ctor) => { + let ctor_js_doc = doc_parser.js_doc_for_span(ctor.span()); + let constructor_name = + prop_name_to_string(&doc_parser.source_map, &ctor.key); + + let mut params = vec![]; + + for param in &ctor.params { + use swc_ecma_ast::Pat; + use swc_ecma_ast::PatOrTsParamProp::*; + + let param_def = match param { + Pat(pat) => match pat { + Pat::Ident(ident) => { + let ts_type = ident + .type_ann + .as_ref() + .map(|rt| ts_type_ann_to_def(&doc_parser.source_map, rt)); + + ParamDef { + name: ident.sym.to_string(), + ts_type, + } + } + _ => ParamDef { + name: "".to_string(), + ts_type: None, + }, + }, + TsParamProp(_) => ParamDef { + name: "".to_string(), + ts_type: None, + }, + }; + params.push(param_def); + } + + let constructor_def = ClassConstructorDef { + js_doc: ctor_js_doc, + accessibility: ctor.accessibility, + name: constructor_name, + params, + location: doc_parser + .source_map + .lookup_char_pos(ctor.span.lo()) + .into(), + }; + constructors.push(constructor_def); + } + Method(class_method) => { + let method_js_doc = doc_parser.js_doc_for_span(class_method.span()); + let method_name = + prop_name_to_string(&doc_parser.source_map, &class_method.key); + let fn_def = + function_to_function_def(doc_parser, &class_method.function); + let method_def = ClassMethodDef { + js_doc: method_js_doc, + accessibility: class_method.accessibility, + is_abstract: class_method.is_abstract, + is_static: class_method.is_static, + name: method_name, + kind: class_method.kind, + function_def: fn_def, + location: doc_parser + .source_map + .lookup_char_pos(class_method.span.lo()) + .into(), + }; + methods.push(method_def); + } + ClassProp(class_prop) => { + let prop_js_doc = doc_parser.js_doc_for_span(class_prop.span()); + + let ts_type = class_prop + .type_ann + .as_ref() + .map(|rt| ts_type_ann_to_def(&doc_parser.source_map, rt)); + + use swc_ecma_ast::Expr; + let prop_name = match &*class_prop.key { + Expr::Ident(ident) => ident.sym.to_string(), + _ => "".to_string(), + }; + + let prop_def = ClassPropertyDef { + js_doc: prop_js_doc, + ts_type, + readonly: class_prop.readonly, + is_abstract: class_prop.is_abstract, + is_static: class_prop.is_static, + accessibility: class_prop.accessibility, + name: prop_name, + location: doc_parser + .source_map + .lookup_char_pos(class_prop.span.lo()) + .into(), + }; + properties.push(prop_def); + } + // TODO: + TsIndexSignature(_) => {} + PrivateMethod(_) => {} + PrivateProp(_) => {} + } + } + + let class_name = class_decl.ident.sym.to_string(); + let class_def = ClassDef { + is_abstract: class_decl.class.is_abstract, + constructors, + properties, + methods, + }; + + (class_name, class_def) +} diff --git a/cli/doc/enum.rs b/cli/doc/enum.rs new file mode 100644 index 00000000000000..f71c1553703fe2 --- /dev/null +++ b/cli/doc/enum.rs @@ -0,0 +1,41 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +use serde::Serialize; +use swc_ecma_ast; + +use super::parser::DocParser; + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct EnumMemberDef { + pub name: String, +} + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct EnumDef { + pub members: Vec, +} + +pub fn get_doc_for_ts_enum_decl( + _doc_parser: &DocParser, + enum_decl: &swc_ecma_ast::TsEnumDecl, +) -> (String, EnumDef) { + let enum_name = enum_decl.id.sym.to_string(); + let mut members = vec![]; + + for enum_member in &enum_decl.members { + use swc_ecma_ast::TsEnumMemberId::*; + + let member_name = match &enum_member.id { + Ident(ident) => ident.sym.to_string(), + Str(str_) => str_.value.to_string(), + }; + + let member_def = EnumMemberDef { name: member_name }; + members.push(member_def); + } + + let enum_def = EnumDef { members }; + + (enum_name, enum_def) +} diff --git a/cli/doc/function.rs b/cli/doc/function.rs new file mode 100644 index 00000000000000..ec7f9bf3882f27 --- /dev/null +++ b/cli/doc/function.rs @@ -0,0 +1,70 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +use serde::Serialize; +use swc_ecma_ast; + +use super::parser::DocParser; +use super::ts_type::ts_type_ann_to_def; +use super::ts_type::TsTypeDef; +use super::ParamDef; + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct FunctionDef { + pub params: Vec, + pub return_type: Option, + pub is_async: bool, + pub is_generator: bool, + // TODO: type_params, decorators +} + +pub fn function_to_function_def( + doc_parser: &DocParser, + function: &swc_ecma_ast::Function, +) -> FunctionDef { + let mut params = vec![]; + + for param in &function.params { + use swc_ecma_ast::Pat; + + let param_def = match param { + Pat::Ident(ident) => { + let ts_type = ident + .type_ann + .as_ref() + .map(|rt| ts_type_ann_to_def(&doc_parser.source_map, rt)); + + ParamDef { + name: ident.sym.to_string(), + ts_type, + } + } + _ => ParamDef { + name: "".to_string(), + ts_type: None, + }, + }; + + params.push(param_def); + } + + let maybe_return_type = function + .return_type + .as_ref() + .map(|rt| ts_type_ann_to_def(&doc_parser.source_map, rt)); + + FunctionDef { + params, + return_type: maybe_return_type, + is_async: function.is_async, + is_generator: function.is_generator, + } +} + +pub fn get_doc_for_fn_decl( + doc_parser: &DocParser, + fn_decl: &swc_ecma_ast::FnDecl, +) -> (String, FunctionDef) { + let name = fn_decl.ident.sym.to_string(); + let fn_def = function_to_function_def(doc_parser, &fn_decl.function); + (name, fn_def) +} diff --git a/cli/doc/interface.rs b/cli/doc/interface.rs new file mode 100644 index 00000000000000..b7e123773ccc8d --- /dev/null +++ b/cli/doc/interface.rs @@ -0,0 +1,243 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +use serde::Serialize; +use swc_ecma_ast; + +use super::parser::DocParser; +use super::ts_type::ts_type_ann_to_def; +use super::ts_type::TsTypeDef; +use super::Location; +use super::ParamDef; + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct InterfaceMethodDef { + // TODO: type_params + pub name: String, + pub location: Location, + pub js_doc: Option, + pub params: Vec, + pub return_type: Option, +} + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct InterfacePropertyDef { + // TODO: type_params + pub name: String, + pub location: Location, + pub js_doc: Option, + pub params: Vec, + pub computed: bool, + pub optional: bool, + pub ts_type: Option, +} + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct InterfaceCallSignatureDef { + // TODO: type_params + pub location: Location, + pub js_doc: Option, + pub params: Vec, + pub ts_type: Option, +} + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct InterfaceDef { + // TODO: extends, type params + pub methods: Vec, + pub properties: Vec, + pub call_signatures: Vec, +} + +fn expr_to_name(expr: &swc_ecma_ast::Expr) -> String { + use swc_ecma_ast::Expr::*; + use swc_ecma_ast::ExprOrSuper::*; + + match expr { + Ident(ident) => ident.sym.to_string(), + Member(member_expr) => { + let left = match &member_expr.obj { + Super(_) => "TODO".to_string(), + Expr(boxed_expr) => expr_to_name(&*boxed_expr), + }; + let right = expr_to_name(&*member_expr.prop); + format!("[{}.{}]", left, right) + } + _ => "".to_string(), + } +} + +pub fn get_doc_for_ts_interface_decl( + doc_parser: &DocParser, + interface_decl: &swc_ecma_ast::TsInterfaceDecl, +) -> (String, InterfaceDef) { + let interface_name = interface_decl.id.sym.to_string(); + + let mut methods = vec![]; + let mut properties = vec![]; + let mut call_signatures = vec![]; + + for type_element in &interface_decl.body.body { + use swc_ecma_ast::TsTypeElement::*; + + match &type_element { + TsMethodSignature(ts_method_sig) => { + let method_js_doc = doc_parser.js_doc_for_span(ts_method_sig.span); + + let mut params = vec![]; + + for param in &ts_method_sig.params { + use swc_ecma_ast::TsFnParam::*; + + let param_def = match param { + Ident(ident) => { + let ts_type = ident + .type_ann + .as_ref() + .map(|rt| ts_type_ann_to_def(&doc_parser.source_map, rt)); + + ParamDef { + name: ident.sym.to_string(), + ts_type, + } + } + _ => ParamDef { + name: "".to_string(), + ts_type: None, + }, + }; + + params.push(param_def); + } + + let name = expr_to_name(&*ts_method_sig.key); + + let maybe_return_type = ts_method_sig + .type_ann + .as_ref() + .map(|rt| ts_type_ann_to_def(&doc_parser.source_map, rt)); + + let method_def = InterfaceMethodDef { + name, + js_doc: method_js_doc, + location: doc_parser + .source_map + .lookup_char_pos(ts_method_sig.span.lo()) + .into(), + params, + return_type: maybe_return_type, + }; + methods.push(method_def); + } + TsPropertySignature(ts_prop_sig) => { + let prop_js_doc = doc_parser.js_doc_for_span(ts_prop_sig.span); + let name = match &*ts_prop_sig.key { + swc_ecma_ast::Expr::Ident(ident) => ident.sym.to_string(), + _ => "TODO".to_string(), + }; + + let mut params = vec![]; + + for param in &ts_prop_sig.params { + use swc_ecma_ast::TsFnParam::*; + + let param_def = match param { + Ident(ident) => { + let ts_type = ident + .type_ann + .as_ref() + .map(|rt| ts_type_ann_to_def(&doc_parser.source_map, rt)); + + ParamDef { + name: ident.sym.to_string(), + ts_type, + } + } + _ => ParamDef { + name: "".to_string(), + ts_type: None, + }, + }; + + params.push(param_def); + } + + let ts_type = ts_prop_sig + .type_ann + .as_ref() + .map(|rt| ts_type_ann_to_def(&doc_parser.source_map, rt)); + + let prop_def = InterfacePropertyDef { + name, + js_doc: prop_js_doc, + location: doc_parser + .source_map + .lookup_char_pos(ts_prop_sig.span.lo()) + .into(), + params, + ts_type, + computed: ts_prop_sig.computed, + optional: ts_prop_sig.optional, + }; + properties.push(prop_def); + } + TsCallSignatureDecl(ts_call_sig) => { + let call_sig_js_doc = doc_parser.js_doc_for_span(ts_call_sig.span); + + let mut params = vec![]; + for param in &ts_call_sig.params { + use swc_ecma_ast::TsFnParam::*; + + let param_def = match param { + Ident(ident) => { + let ts_type = ident + .type_ann + .as_ref() + .map(|rt| ts_type_ann_to_def(&doc_parser.source_map, rt)); + + ParamDef { + name: ident.sym.to_string(), + ts_type, + } + } + _ => ParamDef { + name: "".to_string(), + ts_type: None, + }, + }; + + params.push(param_def); + } + + let ts_type = ts_call_sig + .type_ann + .as_ref() + .map(|rt| ts_type_ann_to_def(&doc_parser.source_map, rt)); + + let call_sig_def = InterfaceCallSignatureDef { + js_doc: call_sig_js_doc, + location: doc_parser + .source_map + .lookup_char_pos(ts_call_sig.span.lo()) + .into(), + params, + ts_type, + }; + call_signatures.push(call_sig_def); + } + // TODO: + TsConstructSignatureDecl(_) => {} + TsIndexSignature(_) => {} + } + } + + let interface_def = InterfaceDef { + methods, + properties, + call_signatures, + }; + + (interface_name, interface_def) +} diff --git a/cli/doc/mod.rs b/cli/doc/mod.rs new file mode 100644 index 00000000000000..4926dccd7b85cf --- /dev/null +++ b/cli/doc/mod.rs @@ -0,0 +1,63 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +pub mod class; +pub mod r#enum; +pub mod function; +pub mod interface; +pub mod module; +pub mod namespace; +mod node; +pub mod parser; +pub mod printer; +pub mod ts_type; +pub mod type_alias; +pub mod variable; + +pub use node::DocNode; +pub use node::DocNodeKind; +pub use node::Location; +pub use node::ParamDef; +pub use parser::DocParser; + +#[cfg(test)] +mod tests; + +pub fn find_node_by_name_recursively( + doc_nodes: Vec, + name: String, +) -> Option { + let mut parts = name.splitn(2, '.'); + let name = parts.next(); + let leftover = parts.next(); + name?; + let node = find_node_by_name(doc_nodes, name.unwrap().to_string()); + match node { + Some(node) => match node.kind { + DocNodeKind::Namespace => { + if let Some(leftover) = leftover { + find_node_by_name_recursively( + node.namespace_def.unwrap().elements, + leftover.to_string(), + ) + } else { + Some(node) + } + } + _ => { + if leftover.is_none() { + Some(node) + } else { + None + } + } + }, + _ => None, + } +} + +fn find_node_by_name(doc_nodes: Vec, name: String) -> Option { + let node = doc_nodes.iter().find(|node| node.name == name); + match node { + Some(node) => Some(node.clone()), + None => None, + } +} diff --git a/cli/doc/module.rs b/cli/doc/module.rs new file mode 100644 index 00000000000000..e6c97771a90dab --- /dev/null +++ b/cli/doc/module.rs @@ -0,0 +1,189 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +use swc_common; +use swc_common::Spanned; +use swc_ecma_ast; + +use super::parser::DocParser; +use super::DocNode; +use super::DocNodeKind; + +pub fn get_doc_node_for_export_decl( + doc_parser: &DocParser, + export_decl: &swc_ecma_ast::ExportDecl, +) -> DocNode { + let export_span = export_decl.span(); + use swc_ecma_ast::Decl; + + let js_doc = doc_parser.js_doc_for_span(export_span); + let location = doc_parser + .source_map + .lookup_char_pos(export_span.lo()) + .into(); + + match &export_decl.decl { + Decl::Class(class_decl) => { + let (name, class_def) = + super::class::get_doc_for_class_decl(doc_parser, class_decl); + DocNode { + kind: DocNodeKind::Class, + name, + location, + js_doc, + class_def: Some(class_def), + function_def: None, + variable_def: None, + enum_def: None, + type_alias_def: None, + namespace_def: None, + interface_def: None, + } + } + Decl::Fn(fn_decl) => { + let (name, function_def) = + super::function::get_doc_for_fn_decl(doc_parser, fn_decl); + DocNode { + kind: DocNodeKind::Function, + name, + location, + js_doc, + function_def: Some(function_def), + class_def: None, + variable_def: None, + enum_def: None, + type_alias_def: None, + namespace_def: None, + interface_def: None, + } + } + Decl::Var(var_decl) => { + let (name, var_def) = + super::variable::get_doc_for_var_decl(doc_parser, var_decl); + DocNode { + kind: DocNodeKind::Variable, + name, + location, + js_doc, + variable_def: Some(var_def), + function_def: None, + class_def: None, + enum_def: None, + type_alias_def: None, + namespace_def: None, + interface_def: None, + } + } + Decl::TsInterface(ts_interface_decl) => { + let (name, interface_def) = + super::interface::get_doc_for_ts_interface_decl( + doc_parser, + ts_interface_decl, + ); + DocNode { + kind: DocNodeKind::Interface, + name, + location, + js_doc, + interface_def: Some(interface_def), + variable_def: None, + function_def: None, + class_def: None, + enum_def: None, + type_alias_def: None, + namespace_def: None, + } + } + Decl::TsTypeAlias(ts_type_alias) => { + let (name, type_alias_def) = + super::type_alias::get_doc_for_ts_type_alias_decl( + doc_parser, + ts_type_alias, + ); + DocNode { + kind: DocNodeKind::TypeAlias, + name, + location, + js_doc, + type_alias_def: Some(type_alias_def), + interface_def: None, + variable_def: None, + function_def: None, + class_def: None, + enum_def: None, + namespace_def: None, + } + } + Decl::TsEnum(ts_enum) => { + let (name, enum_def) = + super::r#enum::get_doc_for_ts_enum_decl(doc_parser, ts_enum); + DocNode { + kind: DocNodeKind::Enum, + name, + location, + js_doc, + enum_def: Some(enum_def), + type_alias_def: None, + interface_def: None, + variable_def: None, + function_def: None, + class_def: None, + namespace_def: None, + } + } + Decl::TsModule(ts_module) => { + let (name, namespace_def) = + super::namespace::get_doc_for_ts_module(doc_parser, ts_module); + DocNode { + kind: DocNodeKind::Namespace, + name, + location, + js_doc, + namespace_def: Some(namespace_def), + enum_def: None, + type_alias_def: None, + interface_def: None, + variable_def: None, + function_def: None, + class_def: None, + } + } + } +} + +#[allow(unused)] +pub fn get_doc_nodes_for_named_export( + doc_parser: &DocParser, + named_export: &swc_ecma_ast::NamedExport, +) -> Vec { + let file_name = named_export.src.as_ref().expect("").value.to_string(); + // TODO: resolve specifier + let source_code = + std::fs::read_to_string(&file_name).expect("Failed to read file"); + let doc_nodes = doc_parser + .parse(file_name, source_code) + .expect("Failed to print docs"); + let reexports: Vec = named_export + .specifiers + .iter() + .map(|export_specifier| { + use swc_ecma_ast::ExportSpecifier::*; + + match export_specifier { + Named(named_export_specifier) => { + Some(named_export_specifier.orig.sym.to_string()) + } + // TODO: + Namespace(_) => None, + Default(_) => None, + } + }) + .filter(|s| s.is_some()) + .map(|s| s.unwrap()) + .collect(); + + let reexports_docs: Vec = doc_nodes + .into_iter() + .filter(|doc_node| reexports.contains(&doc_node.name)) + .collect(); + + reexports_docs +} diff --git a/cli/doc/namespace.rs b/cli/doc/namespace.rs new file mode 100644 index 00000000000000..ed6aac2f314f0b --- /dev/null +++ b/cli/doc/namespace.rs @@ -0,0 +1,81 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +use serde::Serialize; +use swc_ecma_ast; + +use super::parser::DocParser; +use super::DocNode; +use super::DocNodeKind; + +#[derive(Debug, Serialize, Clone)] +pub struct NamespaceDef { + pub elements: Vec, +} + +pub fn get_doc_for_ts_namespace_decl( + doc_parser: &DocParser, + ts_namespace_decl: &swc_ecma_ast::TsNamespaceDecl, +) -> DocNode { + let js_doc = doc_parser.js_doc_for_span(ts_namespace_decl.span); + let location = doc_parser + .source_map + .lookup_char_pos(ts_namespace_decl.span.lo()) + .into(); + let namespace_name = ts_namespace_decl.id.sym.to_string(); + + use swc_ecma_ast::TsNamespaceBody::*; + + let elements = match &*ts_namespace_decl.body { + TsModuleBlock(ts_module_block) => { + doc_parser.get_doc_nodes_for_module_body(ts_module_block.body.clone()) + } + TsNamespaceDecl(ts_namespace_decl) => { + vec![get_doc_for_ts_namespace_decl(doc_parser, ts_namespace_decl)] + } + }; + + let ns_def = NamespaceDef { elements }; + + DocNode { + kind: DocNodeKind::Namespace, + name: namespace_name, + location, + js_doc, + namespace_def: Some(ns_def), + function_def: None, + variable_def: None, + enum_def: None, + class_def: None, + type_alias_def: None, + interface_def: None, + } +} + +pub fn get_doc_for_ts_module( + doc_parser: &DocParser, + ts_module_decl: &swc_ecma_ast::TsModuleDecl, +) -> (String, NamespaceDef) { + use swc_ecma_ast::TsModuleName; + let namespace_name = match &ts_module_decl.id { + TsModuleName::Ident(ident) => ident.sym.to_string(), + TsModuleName::Str(str_) => str_.value.to_string(), + }; + + let elements = if let Some(body) = &ts_module_decl.body { + use swc_ecma_ast::TsNamespaceBody::*; + + match &body { + TsModuleBlock(ts_module_block) => { + doc_parser.get_doc_nodes_for_module_body(ts_module_block.body.clone()) + } + TsNamespaceDecl(ts_namespace_decl) => { + vec![get_doc_for_ts_namespace_decl(doc_parser, ts_namespace_decl)] + } + } + } else { + vec![] + }; + + let ns_def = NamespaceDef { elements }; + + (namespace_name, ns_def) +} diff --git a/cli/doc/node.rs b/cli/doc/node.rs new file mode 100644 index 00000000000000..da4b81c112bb37 --- /dev/null +++ b/cli/doc/node.rs @@ -0,0 +1,77 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +use serde::Serialize; +use swc_common; + +#[derive(Debug, PartialEq, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub enum DocNodeKind { + Function, + Variable, + Class, + Enum, + Interface, + TypeAlias, + Namespace, +} + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ParamDef { + pub name: String, + pub ts_type: Option, +} + +#[derive(Debug, Serialize, Clone)] +pub struct Location { + pub filename: String, + pub line: usize, + pub col: usize, +} + +impl Into for swc_common::Loc { + fn into(self) -> Location { + use swc_common::FileName::*; + + let filename = match &self.file.name { + Real(path_buf) => path_buf.to_string_lossy().to_string(), + Custom(str_) => str_.to_string(), + _ => panic!("invalid filename"), + }; + + Location { + filename, + line: self.line, + col: self.col_display, + } + } +} + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct DocNode { + pub kind: DocNodeKind, + pub name: String, + pub location: Location, + pub js_doc: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub function_def: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub variable_def: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub enum_def: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub class_def: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub type_alias_def: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub namespace_def: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub interface_def: Option, +} diff --git a/cli/doc/parser.rs b/cli/doc/parser.rs new file mode 100644 index 00000000000000..bd3a648061bd3e --- /dev/null +++ b/cli/doc/parser.rs @@ -0,0 +1,189 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +use regex::Regex; +use std::sync::Arc; +use std::sync::RwLock; +use swc_common; +use swc_common::comments::CommentKind; +use swc_common::comments::Comments; +use swc_common::errors::Diagnostic; +use swc_common::errors::DiagnosticBuilder; +use swc_common::errors::Emitter; +use swc_common::errors::Handler; +use swc_common::errors::HandlerFlags; +use swc_common::FileName; +use swc_common::Globals; +use swc_common::SourceMap; +use swc_common::Span; +use swc_ecma_parser::lexer::Lexer; +use swc_ecma_parser::JscTarget; +use swc_ecma_parser::Parser; +use swc_ecma_parser::Session; +use swc_ecma_parser::SourceFileInput; +use swc_ecma_parser::Syntax; +use swc_ecma_parser::TsConfig; + +use super::DocNode; + +pub type SwcDiagnostics = Vec; + +#[derive(Clone, Default)] +pub struct BufferedError(Arc>); + +impl Emitter for BufferedError { + fn emit(&mut self, db: &DiagnosticBuilder) { + self.0.write().unwrap().push((**db).clone()); + } +} + +impl From for Vec { + fn from(buf: BufferedError) -> Self { + let s = buf.0.read().unwrap(); + s.clone() + } +} + +pub struct DocParser { + pub buffered_error: BufferedError, + pub source_map: Arc, + pub handler: Handler, + pub comments: Comments, + pub globals: Globals, +} + +impl DocParser { + pub fn default() -> Self { + let buffered_error = BufferedError::default(); + + let handler = Handler::with_emitter_and_flags( + Box::new(buffered_error.clone()), + HandlerFlags { + dont_buffer_diagnostics: true, + can_emit_warnings: true, + ..Default::default() + }, + ); + + DocParser { + buffered_error, + source_map: Arc::new(SourceMap::default()), + handler, + comments: Comments::default(), + globals: Globals::new(), + } + } + + pub fn parse( + &self, + file_name: String, + source_code: String, + ) -> Result, SwcDiagnostics> { + swc_common::GLOBALS.set(&self.globals, || { + let swc_source_file = self + .source_map + .new_source_file(FileName::Custom(file_name), source_code); + + let buffered_err = self.buffered_error.clone(); + let session = Session { + handler: &self.handler, + }; + + let mut ts_config = TsConfig::default(); + ts_config.dynamic_import = true; + let syntax = Syntax::Typescript(ts_config); + + let lexer = Lexer::new( + session, + syntax, + JscTarget::Es2019, + SourceFileInput::from(&*swc_source_file), + Some(&self.comments), + ); + + let mut parser = Parser::new_from(session, lexer); + + let module = + parser + .parse_module() + .map_err(move |mut err: DiagnosticBuilder| { + err.cancel(); + SwcDiagnostics::from(buffered_err) + })?; + + let doc_entries = self.get_doc_nodes_for_module_body(module.body); + Ok(doc_entries) + }) + } + + pub fn get_doc_nodes_for_module_decl( + &self, + module_decl: &swc_ecma_ast::ModuleDecl, + ) -> Vec { + use swc_ecma_ast::ModuleDecl; + + match module_decl { + ModuleDecl::ExportDecl(export_decl) => { + vec![super::module::get_doc_node_for_export_decl( + self, + export_decl, + )] + } + ModuleDecl::ExportNamed(_named_export) => { + vec![] + // TODO(bartlomieju): + // super::module::get_doc_nodes_for_named_export(self, named_export) + } + ModuleDecl::ExportDefaultDecl(_) => vec![], + ModuleDecl::ExportDefaultExpr(_) => vec![], + ModuleDecl::ExportAll(_) => vec![], + ModuleDecl::TsExportAssignment(_) => vec![], + ModuleDecl::TsNamespaceExport(_) => vec![], + _ => vec![], + } + } + + pub fn get_doc_nodes_for_module_body( + &self, + module_body: Vec, + ) -> Vec { + let mut doc_entries: Vec = vec![]; + for node in module_body.iter() { + if let swc_ecma_ast::ModuleItem::ModuleDecl(module_decl) = node { + doc_entries.extend(self.get_doc_nodes_for_module_decl(module_decl)); + } + } + doc_entries + } + + pub fn js_doc_for_span(&self, span: Span) -> Option { + let comments = self.comments.take_leading_comments(span.lo())?; + let js_doc_comment = comments.iter().find(|comment| { + comment.kind == CommentKind::Block && comment.text.starts_with('*') + })?; + + let mut margin_pat = String::from(""); + if let Some(margin) = self.source_map.span_to_margin(span) { + for _ in 0..margin { + margin_pat.push(' '); + } + } + + let js_doc_re = Regex::new(r#" ?\* ?"#).unwrap(); + let txt = js_doc_comment + .text + .split('\n') + .map(|line| js_doc_re.replace(line, "").to_string()) + .map(|line| { + if line.starts_with(&margin_pat) { + line[margin_pat.len()..].to_string() + } else { + line + } + }) + .collect::>() + .join("\n"); + + let txt = txt.trim_start().trim_end().to_string(); + + Some(txt) + } +} diff --git a/cli/doc/printer.rs b/cli/doc/printer.rs new file mode 100644 index 00000000000000..19c1c0d3b44567 --- /dev/null +++ b/cli/doc/printer.rs @@ -0,0 +1,485 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + +// TODO(ry) This module builds up output by appending to a string. Instead it +// should either use a formatting trait +// https://doc.rust-lang.org/std/fmt/index.html#formatting-traits +// Or perhaps implement a Serializer for serde +// https://docs.serde.rs/serde/ser/trait.Serializer.html + +// TODO(ry) The methods in this module take ownership of the DocNodes, this is +// unnecessary and can result in unnecessary copying. Instead they should take +// references. + +use crate::colors; +use crate::doc; +use crate::doc::ts_type::TsTypeDefKind; +use crate::doc::DocNodeKind; + +pub fn format(doc_nodes: Vec) -> String { + format_(doc_nodes, 0) +} + +pub fn format_details(node: doc::DocNode) -> String { + let mut details = String::new(); + + details.push_str(&format!( + "{}", + colors::gray(format!( + "Defined in {}:{}:{} \n\n", + node.location.filename, node.location.line, node.location.col + )) + )); + + details.push_str(&format_signature(&node, 0)); + + let js_doc = node.js_doc.clone(); + if let Some(js_doc) = js_doc { + details.push_str(&format_jsdoc(js_doc, false, 1)); + } + details.push_str("\n"); + + let maybe_extra = match node.kind { + DocNodeKind::Class => Some(format_class_details(node)), + DocNodeKind::Namespace => Some(format_namespace_details(node)), + _ => None, + }; + + if let Some(extra) = maybe_extra { + details.push_str(&extra); + } + + details +} + +fn kind_order(kind: &doc::DocNodeKind) -> i64 { + match kind { + DocNodeKind::Function => 0, + DocNodeKind::Variable => 1, + DocNodeKind::Class => 2, + DocNodeKind::Enum => 3, + DocNodeKind::Interface => 4, + DocNodeKind::TypeAlias => 5, + DocNodeKind::Namespace => 6, + } +} + +fn format_signature(node: &doc::DocNode, indent: i64) -> String { + match node.kind { + DocNodeKind::Function => format_function_signature(&node, indent), + DocNodeKind::Variable => format_variable_signature(&node, indent), + DocNodeKind::Class => format_class_signature(&node, indent), + DocNodeKind::Enum => format_enum_signature(&node, indent), + DocNodeKind::Interface => format_interface_signature(&node, indent), + DocNodeKind::TypeAlias => format_type_alias_signature(&node, indent), + DocNodeKind::Namespace => format_namespace_signature(&node, indent), + } +} + +fn format_(doc_nodes: Vec, indent: i64) -> String { + let mut sorted = doc_nodes; + sorted.sort_unstable_by(|a, b| { + let kind_cmp = kind_order(&a.kind).cmp(&kind_order(&b.kind)); + if kind_cmp == core::cmp::Ordering::Equal { + a.name.cmp(&b.name) + } else { + kind_cmp + } + }); + + let mut output = String::new(); + + for node in sorted { + output.push_str(&format_signature(&node, indent)); + if node.js_doc.is_some() { + output.push_str(&format_jsdoc( + node.js_doc.as_ref().unwrap().to_string(), + true, + indent, + )); + } + output.push_str("\n"); + if DocNodeKind::Namespace == node.kind { + output.push_str(&format_( + node.namespace_def.as_ref().unwrap().elements.clone(), + indent + 1, + )); + output.push_str("\n"); + }; + } + + output +} + +fn render_params(params: Vec) -> String { + let mut rendered = String::from(""); + if !params.is_empty() { + for param in params { + rendered += param.name.as_str(); + if param.ts_type.is_some() { + rendered += ": "; + rendered += render_ts_type(param.ts_type.unwrap()).as_str(); + } + rendered += ", "; + } + rendered.truncate(rendered.len() - 2); + } + rendered +} + +fn render_ts_type(ts_type: doc::ts_type::TsTypeDef) -> String { + let kind = ts_type.kind.unwrap(); + match kind { + TsTypeDefKind::Array => { + format!("{}[]", render_ts_type(*ts_type.array.unwrap())) + } + TsTypeDefKind::Conditional => { + let conditional = ts_type.conditional_type.unwrap(); + format!( + "{} extends {} ? {} : {}", + render_ts_type(*conditional.check_type), + render_ts_type(*conditional.extends_type), + render_ts_type(*conditional.true_type), + render_ts_type(*conditional.false_type) + ) + } + TsTypeDefKind::FnOrConstructor => { + let fn_or_constructor = ts_type.fn_or_constructor.unwrap(); + format!( + "{}({}) => {}", + if fn_or_constructor.constructor { + "new " + } else { + "" + }, + render_params(fn_or_constructor.params), + render_ts_type(fn_or_constructor.ts_type), + ) + } + TsTypeDefKind::IndexedAccess => { + let indexed_access = ts_type.indexed_access.unwrap(); + format!( + "{}[{}]", + render_ts_type(*indexed_access.obj_type), + render_ts_type(*indexed_access.index_type) + ) + } + TsTypeDefKind::Intersection => { + let intersection = ts_type.intersection.unwrap(); + let mut output = "".to_string(); + if !intersection.is_empty() { + for ts_type in intersection { + output += render_ts_type(ts_type).as_str(); + output += " & " + } + output.truncate(output.len() - 3); + } + output + } + TsTypeDefKind::Keyword => ts_type.keyword.unwrap(), + TsTypeDefKind::Literal => { + let literal = ts_type.literal.unwrap(); + match literal.kind { + doc::ts_type::LiteralDefKind::Boolean => { + format!("{}", literal.boolean.unwrap()) + } + doc::ts_type::LiteralDefKind::String => { + "\"".to_string() + literal.string.unwrap().as_str() + "\"" + } + doc::ts_type::LiteralDefKind::Number => { + format!("{}", literal.number.unwrap()) + } + } + } + TsTypeDefKind::Optional => "_optional_".to_string(), + TsTypeDefKind::Parenthesized => { + format!("({})", render_ts_type(*ts_type.parenthesized.unwrap())) + } + TsTypeDefKind::Rest => { + format!("...{}", render_ts_type(*ts_type.rest.unwrap())) + } + TsTypeDefKind::This => "this".to_string(), + TsTypeDefKind::Tuple => { + let tuple = ts_type.tuple.unwrap(); + let mut output = "".to_string(); + if !tuple.is_empty() { + for ts_type in tuple { + output += render_ts_type(ts_type).as_str(); + output += ", " + } + output.truncate(output.len() - 2); + } + output + } + TsTypeDefKind::TypeLiteral => { + let mut output = "".to_string(); + let type_literal = ts_type.type_literal.unwrap(); + for node in type_literal.call_signatures { + output += format!( + "({}): {}, ", + render_params(node.params), + render_ts_type(node.ts_type.unwrap()) + ) + .as_str() + } + for node in type_literal.methods { + output += format!( + "{}({}): {}, ", + node.name, + render_params(node.params), + render_ts_type(node.return_type.unwrap()) + ) + .as_str() + } + for node in type_literal.properties { + output += + format!("{}: {}, ", node.name, render_ts_type(node.ts_type.unwrap())) + .as_str() + } + if !output.is_empty() { + output.truncate(output.len() - 2); + } + "{ ".to_string() + output.as_str() + " }" + } + TsTypeDefKind::TypeOperator => { + let operator = ts_type.type_operator.unwrap(); + format!("{} {}", operator.operator, render_ts_type(operator.ts_type)) + } + TsTypeDefKind::TypeQuery => { + format!("typeof {}", ts_type.type_query.unwrap()) + } + TsTypeDefKind::TypeRef => { + let type_ref = ts_type.type_ref.unwrap(); + let mut final_output = type_ref.type_name; + if type_ref.type_params.is_some() { + let mut output = "".to_string(); + let type_params = type_ref.type_params.unwrap(); + if !type_params.is_empty() { + for ts_type in type_params { + output += render_ts_type(ts_type).as_str(); + output += ", " + } + output.truncate(output.len() - 2); + } + final_output += format!("<{}>", output).as_str(); + } + final_output + } + TsTypeDefKind::Union => { + let union = ts_type.union.unwrap(); + let mut output = "".to_string(); + if !union.is_empty() { + for ts_type in union { + output += render_ts_type(ts_type).as_str(); + output += " | " + } + output.truncate(output.len() - 3); + } + output + } + } +} + +fn add_indent(string: String, indent: i64) -> String { + let mut indent_str = String::new(); + for _ in 0..(indent * 2) { + indent_str += " "; + } + indent_str += string.as_str(); + indent_str +} + +// TODO: this should use some sort of markdown to console parser. +fn format_jsdoc(jsdoc: String, truncated: bool, indent: i64) -> String { + let mut lines = jsdoc.split("\n\n").map(|line| line.replace("\n", " ")); + + let mut js_doc = String::new(); + + if truncated { + let first_line = lines.next().unwrap_or_else(|| "".to_string()); + js_doc.push_str(&add_indent(format!("{}\n", first_line), indent + 1)); + } else { + for line in lines { + js_doc.push_str(&add_indent(format!("{}\n", line), indent + 1)); + } + } + format!("{}", colors::gray(js_doc)) +} + +fn format_class_details(node: doc::DocNode) -> String { + let mut details = String::new(); + + let class_def = node.class_def.unwrap(); + for node in class_def.constructors { + details.push_str(&add_indent( + format!( + "{} {}({})\n", + colors::magenta("constructor".to_string()), + colors::bold(node.name), + render_params(node.params), + ), + 1, + )); + } + for node in class_def.properties.iter().filter(|node| { + node + .accessibility + .unwrap_or(swc_ecma_ast::Accessibility::Public) + != swc_ecma_ast::Accessibility::Private + }) { + details.push_str(&add_indent( + format!( + "{}{}: {}\n", + colors::magenta( + match node + .accessibility + .unwrap_or(swc_ecma_ast::Accessibility::Public) + { + swc_ecma_ast::Accessibility::Protected => "protected ".to_string(), + _ => "".to_string(), + } + ), + colors::bold(node.name.clone()), + render_ts_type(node.ts_type.clone().unwrap()) + ), + 1, + )); + } + for node in class_def.methods.iter().filter(|node| { + node + .accessibility + .unwrap_or(swc_ecma_ast::Accessibility::Public) + != swc_ecma_ast::Accessibility::Private + }) { + let function_def = node.function_def.clone(); + details.push_str(&add_indent( + format!( + "{}{}{}({}): {}\n", + colors::magenta( + match node + .accessibility + .unwrap_or(swc_ecma_ast::Accessibility::Public) + { + swc_ecma_ast::Accessibility::Protected => "protected ".to_string(), + _ => "".to_string(), + } + ), + colors::magenta(match node.kind { + swc_ecma_ast::MethodKind::Getter => "get ".to_string(), + swc_ecma_ast::MethodKind::Setter => "set ".to_string(), + _ => "".to_string(), + }), + colors::bold(node.name.clone()), + render_params(function_def.params), + render_ts_type(function_def.return_type.unwrap()) + ), + 1, + )); + } + details.push_str("\n"); + details +} + +fn format_namespace_details(node: doc::DocNode) -> String { + let mut ns = String::new(); + + let elements = node.namespace_def.unwrap().elements; + for node in elements { + ns.push_str(&format_signature(&node, 1)); + } + ns.push_str("\n"); + ns +} + +fn format_function_signature(node: &doc::DocNode, indent: i64) -> String { + let function_def = node.function_def.clone().unwrap(); + let return_type = function_def.return_type.unwrap(); + add_indent( + format!( + "{} {}{}\n", + colors::magenta("function".to_string()), + colors::bold(node.name.clone()), + format!( + "({}): {}", + render_params(function_def.params), + render_ts_type(return_type).as_str() + ) + ), + indent, + ) +} + +fn format_class_signature(node: &doc::DocNode, indent: i64) -> String { + add_indent( + format!( + "{} {}\n", + colors::magenta("class".to_string()), + colors::bold(node.name.clone()) + ), + indent, + ) +} + +fn format_variable_signature(node: &doc::DocNode, indent: i64) -> String { + let variable_def = node.variable_def.clone().unwrap(); + add_indent( + format!( + "{} {}{}\n", + colors::magenta(match variable_def.kind { + swc_ecma_ast::VarDeclKind::Const => "const".to_string(), + swc_ecma_ast::VarDeclKind::Let => "let".to_string(), + swc_ecma_ast::VarDeclKind::Var => "var".to_string(), + }), + colors::bold(node.name.clone()), + if variable_def.ts_type.is_some() { + format!(": {}", render_ts_type(variable_def.ts_type.unwrap())) + } else { + "".to_string() + } + ), + indent, + ) +} + +fn format_enum_signature(node: &doc::DocNode, indent: i64) -> String { + add_indent( + format!( + "{} {}\n", + colors::magenta("enum".to_string()), + colors::bold(node.name.clone()) + ), + indent, + ) +} + +fn format_interface_signature(node: &doc::DocNode, indent: i64) -> String { + add_indent( + format!( + "{} {}\n", + colors::magenta("interface".to_string()), + colors::bold(node.name.clone()) + ), + indent, + ) +} + +fn format_type_alias_signature(node: &doc::DocNode, indent: i64) -> String { + add_indent( + format!( + "{} {}\n", + colors::magenta("type".to_string()), + colors::bold(node.name.clone()) + ), + indent, + ) +} + +fn format_namespace_signature(node: &doc::DocNode, indent: i64) -> String { + add_indent( + format!( + "{} {}\n", + colors::magenta("namespace".to_string()), + colors::bold(node.name.clone()) + ), + indent, + ) +} diff --git a/cli/doc/tests.rs b/cli/doc/tests.rs new file mode 100644 index 00000000000000..12621c56dbadec --- /dev/null +++ b/cli/doc/tests.rs @@ -0,0 +1,592 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +use super::DocParser; +use crate::colors; +use serde_json; +use serde_json::json; + +#[test] +fn export_fn() { + let source_code = r#"/** +* Hello there, this is a multiline JSdoc. +* +* It has many lines +* +* Or not that many? +*/ +export function foo(a: string, b: number): void { + console.log("Hello world"); +} +"#; + let entries = DocParser::default() + .parse("test.ts".to_string(), source_code.to_string()) + .unwrap(); + assert_eq!(entries.len(), 1); + let entry = &entries[0]; + let expected_json = json!({ + "functionDef": { + "isAsync": false, + "isGenerator": false, + "params": [ + { + "name": "a", + "tsType": { + "keyword": "string", + "kind": "keyword", + "repr": "string", + }, + }, + { + "name": "b", + "tsType": { + "keyword": "number", + "kind": "keyword", + "repr": "number", + }, + }, + ], + "returnType": { + "keyword": "void", + "kind": "keyword", + "repr": "void", + }, + }, + "jsDoc": "Hello there, this is a multiline JSdoc.\n\nIt has many lines\n\nOr not that many?", + "kind": "function", + "location": { + "col": 0, + "filename": "test.ts", + "line": 8, + }, + "name": "foo", + }); + let actual = serde_json::to_value(entry).unwrap(); + assert_eq!(actual, expected_json); + + assert!( + colors::strip_ansi_codes(super::printer::format(entries).as_str()) + .contains("Hello there") + ); +} + +#[test] +fn export_const() { + let source_code = + "/** Something about fizzBuzz */\nexport const fizzBuzz = \"fizzBuzz\";\n"; + let entries = DocParser::default() + .parse("test.ts".to_string(), source_code.to_string()) + .unwrap(); + assert_eq!(entries.len(), 1); + let entry = &entries[0]; + let expected_json = json!({ + "kind": "variable", + "name": "fizzBuzz", + "location": { + "filename": "test.ts", + "line": 2, + "col": 0 + }, + "jsDoc": "Something about fizzBuzz", + "variableDef": { + "tsType": null, + "kind": "const" + } + }); + let actual = serde_json::to_value(entry).unwrap(); + assert_eq!(actual, expected_json); + + assert!( + colors::strip_ansi_codes(super::printer::format(entries).as_str()) + .contains("Something about fizzBuzz") + ); +} + +#[test] +fn export_class() { + let source_code = r#" +/** Class doc */ +export class Foobar extends Fizz implements Buzz { + private private1: boolean; + protected protected1: number; + public public1: boolean; + public2: number; + + /** Constructor js doc */ + constructor(name: string, private private2: number, protected protected2: number) {} + + /** Async foo method */ + async foo(): Promise { + // + } + + /** Sync bar method */ + bar(): void { + // + } +} +"#; + let entries = DocParser::default() + .parse("test.ts".to_string(), source_code.to_string()) + .unwrap(); + assert_eq!(entries.len(), 1); + let expected_json = json!({ + "kind": "class", + "name": "Foobar", + "location": { + "filename": "test.ts", + "line": 3, + "col": 0 + }, + "jsDoc": "Class doc", + "classDef": { + "isAbstract": false, + "constructors": [ + { + "jsDoc": "Constructor js doc", + "accessibility": null, + "name": "constructor", + "params": [ + { + "name": "name", + "tsType": { + "repr": "string", + "kind": "keyword", + "keyword": "string" + } + }, + { + "name": "", + "tsType": null + }, + { + "name": "", + "tsType": null + } + ], + "location": { + "filename": "test.ts", + "line": 10, + "col": 4 + } + } + ], + "properties": [ + { + "jsDoc": null, + "tsType": { + "repr": "boolean", + "kind": "keyword", + "keyword": "boolean" + }, + "readonly": false, + "accessibility": "private", + "isAbstract": false, + "isStatic": false, + "name": "private1", + "location": { + "filename": "test.ts", + "line": 4, + "col": 4 + } + }, + { + "jsDoc": null, + "tsType": { + "repr": "number", + "kind": "keyword", + "keyword": "number" + }, + "readonly": false, + "accessibility": "protected", + "isAbstract": false, + "isStatic": false, + "name": "protected1", + "location": { + "filename": "test.ts", + "line": 5, + "col": 4 + } + }, + { + "jsDoc": null, + "tsType": { + "repr": "boolean", + "kind": "keyword", + "keyword": "boolean" + }, + "readonly": false, + "accessibility": "public", + "isAbstract": false, + "isStatic": false, + "name": "public1", + "location": { + "filename": "test.ts", + "line": 6, + "col": 4 + } + }, + { + "jsDoc": null, + "tsType": { + "repr": "number", + "kind": "keyword", + "keyword": "number" + }, + "readonly": false, + "accessibility": null, + "isAbstract": false, + "isStatic": false, + "name": "public2", + "location": { + "filename": "test.ts", + "line": 7, + "col": 4 + } + } + ], + "methods": [ + { + "jsDoc": "Async foo method", + "accessibility": null, + "isAbstract": false, + "isStatic": false, + "name": "foo", + "kind": "method", + "functionDef": { + "params": [], + "returnType": { + "repr": "Promise", + "kind": "typeRef", + "typeRef": { + "typeParams": [ + { + "repr": "void", + "kind": "keyword", + "keyword": "void" + } + ], + "typeName": "Promise" + } + }, + "isAsync": true, + "isGenerator": false + }, + "location": { + "filename": "test.ts", + "line": 13, + "col": 4 + } + }, + { + "jsDoc": "Sync bar method", + "accessibility": null, + "isAbstract": false, + "isStatic": false, + "name": "bar", + "kind": "method", + "functionDef": { + "params": [], + "returnType": { + "repr": "void", + "kind": "keyword", + "keyword": "void" + }, + "isAsync": false, + "isGenerator": false + }, + "location": { + "filename": "test.ts", + "line": 18, + "col": 4 + } + } + ] + } + }); + let entry = &entries[0]; + let actual = serde_json::to_value(entry).unwrap(); + assert_eq!(actual, expected_json); + + assert!( + colors::strip_ansi_codes(super::printer::format(entries).as_str()) + .contains("class Foobar") + ); +} + +#[test] +fn export_interface() { + let source_code = r#" +/** + * Interface js doc + */ +export interface Reader { + /** Read n bytes */ + read(buf: Uint8Array, something: unknown): Promise +} + "#; + let entries = DocParser::default() + .parse("test.ts".to_string(), source_code.to_string()) + .unwrap(); + assert_eq!(entries.len(), 1); + let entry = &entries[0]; + let expected_json = json!({ + "kind": "interface", + "name": "Reader", + "location": { + "filename": "test.ts", + "line": 5, + "col": 0 + }, + "jsDoc": "Interface js doc", + "interfaceDef": { + "methods": [ + { + "name": "read", + "location": { + "filename": "test.ts", + "line": 7, + "col": 4 + }, + "jsDoc": "Read n bytes", + "params": [ + { + "name": "buf", + "tsType": { + "repr": "Uint8Array", + "kind": "typeRef", + "typeRef": { + "typeParams": null, + "typeName": "Uint8Array" + } + } + }, + { + "name": "something", + "tsType": { + "repr": "unknown", + "kind": "keyword", + "keyword": "unknown" + } + } + ], + "returnType": { + "repr": "Promise", + "kind": "typeRef", + "typeRef": { + "typeParams": [ + { + "repr": "number", + "kind": "keyword", + "keyword": "number" + } + ], + "typeName": "Promise" + } + } + } + ], + "properties": [], + "callSignatures": [] + } + }); + let actual = serde_json::to_value(entry).unwrap(); + assert_eq!(actual, expected_json); + + assert!( + colors::strip_ansi_codes(super::printer::format(entries).as_str()) + .contains("interface Reader") + ); +} + +#[test] +fn export_type_alias() { + let source_code = r#" +/** Array holding numbers */ +export type NumberArray = Array; + "#; + let entries = DocParser::default() + .parse("test.ts".to_string(), source_code.to_string()) + .unwrap(); + assert_eq!(entries.len(), 1); + let entry = &entries[0]; + let expected_json = json!({ + "kind": "typeAlias", + "name": "NumberArray", + "location": { + "filename": "test.ts", + "line": 3, + "col": 0 + }, + "jsDoc": "Array holding numbers", + "typeAliasDef": { + "tsType": { + "repr": "Array", + "kind": "typeRef", + "typeRef": { + "typeParams": [ + { + "repr": "number", + "kind": "keyword", + "keyword": "number" + } + ], + "typeName": "Array" + } + } + } + }); + let actual = serde_json::to_value(entry).unwrap(); + assert_eq!(actual, expected_json); + + assert!( + colors::strip_ansi_codes(super::printer::format(entries).as_str()) + .contains("Array holding numbers") + ); +} + +#[test] +fn export_enum() { + let source_code = r#" +/** + * Some enum for good measure + */ +export enum Hello { + World = "world", + Fizz = "fizz", + Buzz = "buzz", +} + "#; + let entries = DocParser::default() + .parse("test.ts".to_string(), source_code.to_string()) + .unwrap(); + assert_eq!(entries.len(), 1); + let entry = &entries[0]; + let expected_json = json!({ + "kind": "enum", + "name": "Hello", + "location": { + "filename": "test.ts", + "line": 5, + "col": 0 + }, + "jsDoc": "Some enum for good measure", + "enumDef": { + "members": [ + { + "name": "World" + }, + { + "name": "Fizz" + }, + { + "name": "Buzz" + } + ] + } + }); + let actual = serde_json::to_value(entry).unwrap(); + assert_eq!(actual, expected_json); + + assert!(colors::strip_ansi_codes( + super::printer::format(entries.clone()).as_str() + ) + .contains("Some enum for good measure")); + assert!( + colors::strip_ansi_codes(super::printer::format(entries).as_str()) + .contains("enum Hello") + ); +} + +#[test] +fn export_namespace() { + let source_code = r#" +/** Namespace JSdoc */ +export namespace RootNs { + export const a = "a"; + + /** Nested namespace JSDoc */ + export namespace NestedNs { + export enum Foo { + a = 1, + b = 2, + c = 3, + } + } +} + "#; + let entries = DocParser::default() + .parse("test.ts".to_string(), source_code.to_string()) + .unwrap(); + assert_eq!(entries.len(), 1); + let entry = &entries[0]; + let expected_json = json!({ + "kind": "namespace", + "name": "RootNs", + "location": { + "filename": "test.ts", + "line": 3, + "col": 0 + }, + "jsDoc": "Namespace JSdoc", + "namespaceDef": { + "elements": [ + { + "kind": "variable", + "name": "a", + "location": { + "filename": "test.ts", + "line": 4, + "col": 4 + }, + "jsDoc": null, + "variableDef": { + "tsType": null, + "kind": "const" + } + }, + { + "kind": "namespace", + "name": "NestedNs", + "location": { + "filename": "test.ts", + "line": 7, + "col": 4 + }, + "jsDoc": "Nested namespace JSDoc", + "namespaceDef": { + "elements": [ + { + "kind": "enum", + "name": "Foo", + "location": { + "filename": "test.ts", + "line": 8, + "col": 6 + }, + "jsDoc": null, + "enumDef": { + "members": [ + { + "name": "a" + }, + { + "name": "b" + }, + { + "name": "c" + } + ] + } + } + ] + } + } + ] + } + }); + let actual = serde_json::to_value(entry).unwrap(); + assert_eq!(actual, expected_json); + assert!( + colors::strip_ansi_codes(super::printer::format(entries).as_str()) + .contains("namespace RootNs") + ); +} diff --git a/cli/doc/ts_type.rs b/cli/doc/ts_type.rs new file mode 100644 index 00000000000000..9a7d191bad1eab --- /dev/null +++ b/cli/doc/ts_type.rs @@ -0,0 +1,821 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +use super::ParamDef; +use serde::Serialize; +use swc_common::SourceMap; +use swc_ecma_ast; +use swc_ecma_ast::TsArrayType; +use swc_ecma_ast::TsConditionalType; +use swc_ecma_ast::TsFnOrConstructorType; +use swc_ecma_ast::TsIndexedAccessType; +use swc_ecma_ast::TsKeywordType; +use swc_ecma_ast::TsLit; +use swc_ecma_ast::TsLitType; +use swc_ecma_ast::TsOptionalType; +use swc_ecma_ast::TsParenthesizedType; +use swc_ecma_ast::TsRestType; +use swc_ecma_ast::TsThisType; +use swc_ecma_ast::TsTupleType; +use swc_ecma_ast::TsType; +use swc_ecma_ast::TsTypeAnn; +use swc_ecma_ast::TsTypeLit; +use swc_ecma_ast::TsTypeOperator; +use swc_ecma_ast::TsTypeQuery; +use swc_ecma_ast::TsTypeRef; +use swc_ecma_ast::TsUnionOrIntersectionType; + +// pub enum TsType { +// * TsKeywordType(TsKeywordType), +// * TsThisType(TsThisType), +// * TsFnOrConstructorType(TsFnOrConstructorType), +// * TsTypeRef(TsTypeRef), +// * TsTypeQuery(TsTypeQuery), +// * TsTypeLit(TsTypeLit), +// * TsArrayType(TsArrayType), +// * TsTupleType(TsTupleType), +// * TsOptionalType(TsOptionalType), +// * TsRestType(TsRestType), +// * TsUnionOrIntersectionType(TsUnionOrIntersectionType), +// * TsConditionalType(TsConditionalType), +// TsInferType(TsInferType), +// * TsParenthesizedType(TsParenthesizedType), +// * TsTypeOperator(TsTypeOperator), +// * TsIndexedAccessType(TsIndexedAccessType), +// TsMappedType(TsMappedType), +// * TsLitType(TsLitType), +// TsTypePredicate(TsTypePredicate), +// TsImportType(TsImportType), +// } + +impl Into for &TsLitType { + fn into(self) -> TsTypeDef { + let (repr, lit) = match &self.lit { + TsLit::Number(num) => ( + format!("{}", num.value), + LiteralDef { + kind: LiteralDefKind::Number, + number: Some(num.value), + string: None, + boolean: None, + }, + ), + TsLit::Str(str_) => ( + str_.value.to_string(), + LiteralDef { + kind: LiteralDefKind::String, + number: None, + string: Some(str_.value.to_string()), + boolean: None, + }, + ), + TsLit::Bool(bool_) => ( + bool_.value.to_string(), + LiteralDef { + kind: LiteralDefKind::Boolean, + number: None, + string: None, + boolean: Some(bool_.value), + }, + ), + }; + + TsTypeDef { + repr, + kind: Some(TsTypeDefKind::Literal), + literal: Some(lit), + ..Default::default() + } + } +} + +impl Into for &TsArrayType { + fn into(self) -> TsTypeDef { + let ts_type_def: TsTypeDef = (&*self.elem_type).into(); + + TsTypeDef { + array: Some(Box::new(ts_type_def)), + kind: Some(TsTypeDefKind::Array), + ..Default::default() + } + } +} + +impl Into for &TsTupleType { + fn into(self) -> TsTypeDef { + let mut type_defs = vec![]; + + for type_box in &self.elem_types { + let ts_type: &TsType = &(*type_box); + let def: TsTypeDef = ts_type.into(); + type_defs.push(def) + } + + TsTypeDef { + tuple: Some(type_defs), + kind: Some(TsTypeDefKind::Tuple), + ..Default::default() + } + } +} + +impl Into for &TsUnionOrIntersectionType { + fn into(self) -> TsTypeDef { + use swc_ecma_ast::TsUnionOrIntersectionType::*; + + match self { + TsUnionType(union_type) => { + let mut types_union = vec![]; + + for type_box in &union_type.types { + let ts_type: &TsType = &(*type_box); + let def: TsTypeDef = ts_type.into(); + types_union.push(def); + } + + TsTypeDef { + union: Some(types_union), + kind: Some(TsTypeDefKind::Union), + ..Default::default() + } + } + TsIntersectionType(intersection_type) => { + let mut types_intersection = vec![]; + + for type_box in &intersection_type.types { + let ts_type: &TsType = &(*type_box); + let def: TsTypeDef = ts_type.into(); + types_intersection.push(def); + } + + TsTypeDef { + intersection: Some(types_intersection), + kind: Some(TsTypeDefKind::Intersection), + ..Default::default() + } + } + } + } +} + +impl Into for &TsKeywordType { + fn into(self) -> TsTypeDef { + use swc_ecma_ast::TsKeywordTypeKind::*; + + let keyword_str = match self.kind { + TsAnyKeyword => "any", + TsUnknownKeyword => "unknown", + TsNumberKeyword => "number", + TsObjectKeyword => "object", + TsBooleanKeyword => "boolean", + TsBigIntKeyword => "bigint", + TsStringKeyword => "string", + TsSymbolKeyword => "symbol", + TsVoidKeyword => "void", + TsUndefinedKeyword => "undefined", + TsNullKeyword => "null", + TsNeverKeyword => "never", + }; + + TsTypeDef { + repr: keyword_str.to_string(), + kind: Some(TsTypeDefKind::Keyword), + keyword: Some(keyword_str.to_string()), + ..Default::default() + } + } +} + +impl Into for &TsTypeOperator { + fn into(self) -> TsTypeDef { + let ts_type = (&*self.type_ann).into(); + let type_operator_def = TsTypeOperatorDef { + operator: self.op.as_str().to_string(), + ts_type, + }; + + TsTypeDef { + type_operator: Some(Box::new(type_operator_def)), + kind: Some(TsTypeDefKind::TypeOperator), + ..Default::default() + } + } +} + +impl Into for &TsParenthesizedType { + fn into(self) -> TsTypeDef { + let ts_type = (&*self.type_ann).into(); + + TsTypeDef { + parenthesized: Some(Box::new(ts_type)), + kind: Some(TsTypeDefKind::Parenthesized), + ..Default::default() + } + } +} + +impl Into for &TsRestType { + fn into(self) -> TsTypeDef { + let ts_type = (&*self.type_ann).into(); + + TsTypeDef { + rest: Some(Box::new(ts_type)), + kind: Some(TsTypeDefKind::Rest), + ..Default::default() + } + } +} + +impl Into for &TsOptionalType { + fn into(self) -> TsTypeDef { + let ts_type = (&*self.type_ann).into(); + + TsTypeDef { + optional: Some(Box::new(ts_type)), + kind: Some(TsTypeDefKind::Optional), + ..Default::default() + } + } +} + +impl Into for &TsThisType { + fn into(self) -> TsTypeDef { + TsTypeDef { + repr: "this".to_string(), + this: Some(true), + kind: Some(TsTypeDefKind::This), + ..Default::default() + } + } +} + +fn ts_entity_name_to_name(entity_name: &swc_ecma_ast::TsEntityName) -> String { + use swc_ecma_ast::TsEntityName::*; + + match entity_name { + Ident(ident) => ident.sym.to_string(), + TsQualifiedName(ts_qualified_name) => { + let left = ts_entity_name_to_name(&ts_qualified_name.left); + let right = ts_qualified_name.right.sym.to_string(); + format!("{}.{}", left, right) + } + } +} + +impl Into for &TsTypeQuery { + fn into(self) -> TsTypeDef { + use swc_ecma_ast::TsTypeQueryExpr::*; + + let type_name = match &self.expr_name { + TsEntityName(entity_name) => ts_entity_name_to_name(&*entity_name), + Import(import_type) => import_type.arg.value.to_string(), + }; + + TsTypeDef { + repr: type_name.to_string(), + type_query: Some(type_name), + kind: Some(TsTypeDefKind::TypeQuery), + ..Default::default() + } + } +} + +impl Into for &TsTypeRef { + fn into(self) -> TsTypeDef { + let type_name = ts_entity_name_to_name(&self.type_name); + + let type_params = if let Some(type_params_inst) = &self.type_params { + let mut ts_type_defs = vec![]; + + for type_box in &type_params_inst.params { + let ts_type: &TsType = &(*type_box); + let def: TsTypeDef = ts_type.into(); + ts_type_defs.push(def); + } + + Some(ts_type_defs) + } else { + None + }; + + TsTypeDef { + repr: type_name.to_string(), + type_ref: Some(TsTypeRefDef { + type_name, + type_params, + }), + kind: Some(TsTypeDefKind::TypeRef), + ..Default::default() + } + } +} + +impl Into for &TsIndexedAccessType { + fn into(self) -> TsTypeDef { + let indexed_access_def = TsIndexedAccessDef { + readonly: self.readonly, + obj_type: Box::new((&*self.obj_type).into()), + index_type: Box::new((&*self.index_type).into()), + }; + + TsTypeDef { + indexed_access: Some(indexed_access_def), + kind: Some(TsTypeDefKind::IndexedAccess), + ..Default::default() + } + } +} + +impl Into for &TsTypeLit { + fn into(self) -> TsTypeDef { + let mut methods = vec![]; + let mut properties = vec![]; + let mut call_signatures = vec![]; + + for type_element in &self.members { + use swc_ecma_ast::TsTypeElement::*; + + match &type_element { + TsMethodSignature(ts_method_sig) => { + let mut params = vec![]; + + for param in &ts_method_sig.params { + use swc_ecma_ast::TsFnParam::*; + + let param_def = match param { + Ident(ident) => { + let ts_type = + ident.type_ann.as_ref().map(|rt| (&*rt.type_ann).into()); + + ParamDef { + name: ident.sym.to_string(), + ts_type, + } + } + _ => ParamDef { + name: "".to_string(), + ts_type: None, + }, + }; + + params.push(param_def); + } + + let maybe_return_type = ts_method_sig + .type_ann + .as_ref() + .map(|rt| (&*rt.type_ann).into()); + + let method_def = LiteralMethodDef { + name: "".to_string(), + params, + return_type: maybe_return_type, + }; + methods.push(method_def); + } + TsPropertySignature(ts_prop_sig) => { + let name = match &*ts_prop_sig.key { + swc_ecma_ast::Expr::Ident(ident) => ident.sym.to_string(), + _ => "TODO".to_string(), + }; + + let mut params = vec![]; + + for param in &ts_prop_sig.params { + use swc_ecma_ast::TsFnParam::*; + + let param_def = match param { + Ident(ident) => { + let ts_type = + ident.type_ann.as_ref().map(|rt| (&*rt.type_ann).into()); + + ParamDef { + name: ident.sym.to_string(), + ts_type, + } + } + _ => ParamDef { + name: "".to_string(), + ts_type: None, + }, + }; + + params.push(param_def); + } + + let ts_type = ts_prop_sig + .type_ann + .as_ref() + .map(|rt| (&*rt.type_ann).into()); + + let prop_def = LiteralPropertyDef { + name, + params, + ts_type, + computed: ts_prop_sig.computed, + optional: ts_prop_sig.optional, + }; + properties.push(prop_def); + } + TsCallSignatureDecl(ts_call_sig) => { + let mut params = vec![]; + for param in &ts_call_sig.params { + use swc_ecma_ast::TsFnParam::*; + + let param_def = match param { + Ident(ident) => { + let ts_type = + ident.type_ann.as_ref().map(|rt| (&*rt.type_ann).into()); + + ParamDef { + name: ident.sym.to_string(), + ts_type, + } + } + _ => ParamDef { + name: "".to_string(), + ts_type: None, + }, + }; + + params.push(param_def); + } + + let ts_type = ts_call_sig + .type_ann + .as_ref() + .map(|rt| (&*rt.type_ann).into()); + + let call_sig_def = LiteralCallSignatureDef { params, ts_type }; + call_signatures.push(call_sig_def); + } + // TODO: + TsConstructSignatureDecl(_) => {} + TsIndexSignature(_) => {} + } + } + + let type_literal = TsTypeLiteralDef { + methods, + properties, + call_signatures, + }; + + TsTypeDef { + kind: Some(TsTypeDefKind::TypeLiteral), + type_literal: Some(type_literal), + ..Default::default() + } + } +} + +impl Into for &TsConditionalType { + fn into(self) -> TsTypeDef { + let conditional_type_def = TsConditionalDef { + check_type: Box::new((&*self.check_type).into()), + extends_type: Box::new((&*self.extends_type).into()), + true_type: Box::new((&*self.true_type).into()), + false_type: Box::new((&*self.false_type).into()), + }; + + TsTypeDef { + kind: Some(TsTypeDefKind::Conditional), + conditional_type: Some(conditional_type_def), + ..Default::default() + } + } +} + +impl Into for &TsFnOrConstructorType { + fn into(self) -> TsTypeDef { + use swc_ecma_ast::TsFnOrConstructorType::*; + + let fn_def = match self { + TsFnType(ts_fn_type) => { + let mut params = vec![]; + + for param in &ts_fn_type.params { + use swc_ecma_ast::TsFnParam::*; + + let param_def = match param { + Ident(ident) => { + let ts_type: Option = + ident.type_ann.as_ref().map(|rt| { + let type_box = &*rt.type_ann; + (&*type_box).into() + }); + + ParamDef { + name: ident.sym.to_string(), + ts_type, + } + } + _ => ParamDef { + name: "".to_string(), + ts_type: None, + }, + }; + + params.push(param_def); + } + + TsFnOrConstructorDef { + constructor: false, + ts_type: (&*ts_fn_type.type_ann.type_ann).into(), + params, + } + } + TsConstructorType(ctor_type) => { + let mut params = vec![]; + + for param in &ctor_type.params { + use swc_ecma_ast::TsFnParam::*; + + let param_def = match param { + Ident(ident) => { + let ts_type: Option = + ident.type_ann.as_ref().map(|rt| { + let type_box = &*rt.type_ann; + (&*type_box).into() + }); + + ParamDef { + name: ident.sym.to_string(), + ts_type, + } + } + _ => ParamDef { + name: "".to_string(), + ts_type: None, + }, + }; + + params.push(param_def); + } + + TsFnOrConstructorDef { + constructor: true, + ts_type: (&*ctor_type.type_ann.type_ann).into(), + params: vec![], + } + } + }; + + TsTypeDef { + kind: Some(TsTypeDefKind::FnOrConstructor), + fn_or_constructor: Some(Box::new(fn_def)), + ..Default::default() + } + } +} + +impl Into for &TsType { + fn into(self) -> TsTypeDef { + use swc_ecma_ast::TsType::*; + + match self { + TsKeywordType(ref keyword_type) => keyword_type.into(), + TsLitType(ref lit_type) => lit_type.into(), + TsTypeRef(ref type_ref) => type_ref.into(), + TsUnionOrIntersectionType(union_or_inter) => union_or_inter.into(), + TsArrayType(array_type) => array_type.into(), + TsTupleType(tuple_type) => tuple_type.into(), + TsTypeOperator(type_op_type) => type_op_type.into(), + TsParenthesizedType(paren_type) => paren_type.into(), + TsRestType(rest_type) => rest_type.into(), + TsOptionalType(optional_type) => optional_type.into(), + TsTypeQuery(type_query) => type_query.into(), + TsThisType(this_type) => this_type.into(), + TsFnOrConstructorType(fn_or_con_type) => fn_or_con_type.into(), + TsConditionalType(conditional_type) => conditional_type.into(), + TsIndexedAccessType(indexed_access_type) => indexed_access_type.into(), + TsTypeLit(type_literal) => type_literal.into(), + _ => TsTypeDef { + repr: "".to_string(), + ..Default::default() + }, + } + } +} + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct TsTypeRefDef { + pub type_params: Option>, + pub type_name: String, +} + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub enum LiteralDefKind { + Number, + String, + Boolean, +} + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct LiteralDef { + pub kind: LiteralDefKind, + + #[serde(skip_serializing_if = "Option::is_none")] + pub number: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub string: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub boolean: Option, +} + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct TsTypeOperatorDef { + pub operator: String, + pub ts_type: TsTypeDef, +} + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct TsFnOrConstructorDef { + // TODO: type_params + pub constructor: bool, + pub ts_type: TsTypeDef, + pub params: Vec, +} + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct TsConditionalDef { + pub check_type: Box, + pub extends_type: Box, + pub true_type: Box, + pub false_type: Box, +} + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct TsIndexedAccessDef { + pub readonly: bool, + pub obj_type: Box, + pub index_type: Box, +} + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct LiteralMethodDef { + // TODO: type_params + pub name: String, + // pub location: Location, + // pub js_doc: Option, + pub params: Vec, + pub return_type: Option, +} + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct LiteralPropertyDef { + // TODO: type_params + pub name: String, + // pub location: Location, + // pub js_doc: Option, + pub params: Vec, + pub computed: bool, + pub optional: bool, + pub ts_type: Option, +} + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct LiteralCallSignatureDef { + // TODO: type_params + // pub location: Location, + // pub js_doc: Option, + pub params: Vec, + pub ts_type: Option, +} + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct TsTypeLiteralDef { + pub methods: Vec, + pub properties: Vec, + pub call_signatures: Vec, +} + +#[derive(Debug, PartialEq, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub enum TsTypeDefKind { + Keyword, + Literal, + TypeRef, + Union, + Intersection, + Array, + Tuple, + TypeOperator, + Parenthesized, + Rest, + Optional, + TypeQuery, + This, + FnOrConstructor, + Conditional, + IndexedAccess, + TypeLiteral, +} + +#[derive(Debug, Default, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct TsTypeDef { + pub repr: String, + + pub kind: Option, + + // TODO: make this struct more conrete + #[serde(skip_serializing_if = "Option::is_none")] + pub keyword: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub literal: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub type_ref: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub union: Option>, + + #[serde(skip_serializing_if = "Option::is_none")] + pub intersection: Option>, + + #[serde(skip_serializing_if = "Option::is_none")] + pub array: Option>, + + #[serde(skip_serializing_if = "Option::is_none")] + pub tuple: Option>, + + #[serde(skip_serializing_if = "Option::is_none")] + pub type_operator: Option>, + + #[serde(skip_serializing_if = "Option::is_none")] + pub parenthesized: Option>, + + #[serde(skip_serializing_if = "Option::is_none")] + pub rest: Option>, + + #[serde(skip_serializing_if = "Option::is_none")] + pub optional: Option>, + + #[serde(skip_serializing_if = "Option::is_none")] + pub type_query: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub this: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub fn_or_constructor: Option>, + + #[serde(skip_serializing_if = "Option::is_none")] + pub conditional_type: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub indexed_access: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub type_literal: Option, +} + +pub fn ts_type_ann_to_def( + source_map: &SourceMap, + type_ann: &TsTypeAnn, +) -> TsTypeDef { + use swc_ecma_ast::TsType::*; + + match &*type_ann.type_ann { + TsKeywordType(keyword_type) => keyword_type.into(), + TsLitType(lit_type) => lit_type.into(), + TsTypeRef(type_ref) => type_ref.into(), + TsUnionOrIntersectionType(union_or_inter) => union_or_inter.into(), + TsArrayType(array_type) => array_type.into(), + TsTupleType(tuple_type) => tuple_type.into(), + TsTypeOperator(type_op_type) => type_op_type.into(), + TsParenthesizedType(paren_type) => paren_type.into(), + TsRestType(rest_type) => rest_type.into(), + TsOptionalType(optional_type) => optional_type.into(), + TsTypeQuery(type_query) => type_query.into(), + TsThisType(this_type) => this_type.into(), + TsFnOrConstructorType(fn_or_con_type) => fn_or_con_type.into(), + TsConditionalType(conditional_type) => conditional_type.into(), + TsIndexedAccessType(indexed_access_type) => indexed_access_type.into(), + TsTypeLit(type_literal) => type_literal.into(), + _ => { + let repr = source_map + .span_to_snippet(type_ann.span) + .expect("Class prop type not found"); + let repr = repr.trim_start_matches(':').trim_start().to_string(); + + TsTypeDef { + repr, + ..Default::default() + } + } + } +} diff --git a/cli/doc/type_alias.rs b/cli/doc/type_alias.rs new file mode 100644 index 00000000000000..3740aee8429fbe --- /dev/null +++ b/cli/doc/type_alias.rs @@ -0,0 +1,25 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +use serde::Serialize; +use swc_ecma_ast; + +use super::parser::DocParser; +use super::ts_type::TsTypeDef; + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct TypeAliasDef { + pub ts_type: TsTypeDef, + // TODO: type_params +} + +pub fn get_doc_for_ts_type_alias_decl( + _doc_parser: &DocParser, + type_alias_decl: &swc_ecma_ast::TsTypeAliasDecl, +) -> (String, TypeAliasDef) { + let alias_name = type_alias_decl.id.sym.to_string(); + let ts_type = type_alias_decl.type_ann.as_ref().into(); + + let type_alias_def = TypeAliasDef { ts_type }; + + (alias_name, type_alias_def) +} diff --git a/cli/doc/variable.rs b/cli/doc/variable.rs new file mode 100644 index 00000000000000..16bf26d25b8aec --- /dev/null +++ b/cli/doc/variable.rs @@ -0,0 +1,43 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +use serde::Serialize; +use swc_ecma_ast; + +use super::parser::DocParser; +use super::ts_type::ts_type_ann_to_def; +use super::ts_type::TsTypeDef; + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct VariableDef { + pub ts_type: Option, + pub kind: swc_ecma_ast::VarDeclKind, +} + +pub fn get_doc_for_var_decl( + doc_parser: &DocParser, + var_decl: &swc_ecma_ast::VarDecl, +) -> (String, VariableDef) { + assert!(!var_decl.decls.is_empty()); + // TODO: support multiple declarators + let var_declarator = var_decl.decls.get(0).unwrap(); + + let var_name = match &var_declarator.name { + swc_ecma_ast::Pat::Ident(ident) => ident.sym.to_string(), + _ => "".to_string(), + }; + + let maybe_ts_type = match &var_declarator.name { + swc_ecma_ast::Pat::Ident(ident) => ident + .type_ann + .as_ref() + .map(|rt| ts_type_ann_to_def(&doc_parser.source_map, rt)), + _ => None, + }; + + let variable_def = VariableDef { + ts_type: maybe_ts_type, + kind: var_decl.kind, + }; + + (var_name, variable_def) +} diff --git a/cli/flags.rs b/cli/flags.rs index 9e1fbf5dfa2673..d90f1f3b9ca4fc 100644 --- a/cli/flags.rs +++ b/cli/flags.rs @@ -31,6 +31,11 @@ pub enum DenoSubcommand { Completions { buf: Box<[u8]>, }, + Doc { + json: bool, + source_file: String, + filter: Option, + }, Eval { code: String, as_typescript: bool, @@ -63,6 +68,10 @@ pub enum DenoSubcommand { include: Option>, }, Types, + Upgrade { + dry_run: bool, + force: bool, + }, } impl Default for DenoSubcommand { @@ -97,6 +106,8 @@ pub struct Flags { pub no_prompts: bool, pub no_remote: bool, pub cached_only: bool, + pub inspect: Option, + pub inspect_brk: Option, pub seed: Option, pub v8_flags: Option>, @@ -250,6 +261,10 @@ pub fn flags_from_vec_safe(args: Vec) -> clap::Result { completions_parse(&mut flags, m); } else if let Some(m) = matches.subcommand_matches("test") { test_parse(&mut flags, m); + } else if let Some(m) = matches.subcommand_matches("upgrade") { + upgrade_parse(&mut flags, m); + } else if let Some(m) = matches.subcommand_matches("doc") { + doc_parse(&mut flags, m); } else { unimplemented!(); } @@ -302,6 +317,8 @@ If the flag is set, restrict these messages to errors.", .subcommand(run_subcommand()) .subcommand(test_subcommand()) .subcommand(types_subcommand()) + .subcommand(upgrade_subcommand()) + .subcommand(doc_subcommand()) .long_about(DENO_HELP) .after_help(ENV_VARIABLES_HELP) } @@ -467,6 +484,7 @@ fn run_test_args_parse(flags: &mut Flags, matches: &clap::ArgMatches) { no_remote_arg_parse(flags, matches); permission_args_parse(flags, matches); ca_file_arg_parse(flags, matches); + inspect_arg_parse(flags, matches); if matches.is_present("cached-only") { flags.cached_only = true; @@ -534,6 +552,28 @@ fn test_parse(flags: &mut Flags, matches: &clap::ArgMatches) { }; } +fn upgrade_parse(flags: &mut Flags, matches: &clap::ArgMatches) { + let dry_run = matches.is_present("dry-run"); + let force = matches.is_present("force"); + flags.subcommand = DenoSubcommand::Upgrade { dry_run, force }; +} + +fn doc_parse(flags: &mut Flags, matches: &clap::ArgMatches) { + reload_arg_parse(flags, matches); + let source_file = matches.value_of("source_file").map(String::from).unwrap(); + let json = matches.is_present("json"); + let filter = if matches.is_present("filter") { + Some(matches.value_of("filter").unwrap().to_string()) + } else { + None + }; + flags.subcommand = DenoSubcommand::Doc { + source_file, + json, + filter, + }; +} + fn types_subcommand<'a, 'b>() -> App<'a, 'b> { SubCommand::with_name("types") .about("Print runtime TypeScript declarations") @@ -731,6 +771,66 @@ Future runs of this module will trigger no downloads or compilation unless ) } +fn upgrade_subcommand<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name("upgrade") + .about("Upgrade deno executable to newest version") + .long_about( + "Upgrade deno executable to newest available version. + +The latest version is downloaded from +https://github.com/denoland/deno/releases +and is used to replace the current executable.", + ) + .arg( + Arg::with_name("dry-run") + .long("dry-run") + .help("Perform all checks without replacing old exe"), + ) + .arg( + Arg::with_name("force") + .long("force") + .short("f") + .help("Replace current exe even if not out-of-date"), + ) +} + +fn doc_subcommand<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name("doc") + .about("Show documentation for module") + .long_about( + "Show documentation for module. + +Output documentation to terminal: + deno doc ./path/to/module.ts + +Show detail of symbol: + deno doc ./path/to/module.ts MyClass.someField + +Output documentation in JSON format: + deno doc --json ./path/to/module.ts", + ) + .arg(reload_arg()) + .arg( + Arg::with_name("json") + .long("json") + .help("Output documentation in JSON format.") + .takes_value(false), + ) + .arg( + Arg::with_name("source_file") + .takes_value(true) + .required(true), + ) + .arg( + Arg::with_name("filter") + .help("Dot separated path to symbol.") + .takes_value(true) + .required(false) + .conflicts_with("json") + .conflicts_with("pretty"), + ) +} + fn permission_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { app .arg( @@ -789,7 +889,7 @@ fn permission_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { } fn run_test_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { - permission_args(app) + permission_args(inspect_args(app)) .arg(importmap_arg()) .arg(reload_arg()) .arg(config_arg()) @@ -920,6 +1020,54 @@ fn ca_file_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) { flags.ca_file = matches.value_of("cert").map(ToOwned::to_owned); } +fn inspect_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { + app + .arg( + Arg::with_name("inspect") + .long("inspect") + .value_name("HOST:PORT") + .help("activate inspector on host:port (default: 127.0.0.1:9229)") + .min_values(0) + .max_values(1) + .require_equals(true) + .takes_value(true), + ) + .arg( + Arg::with_name("inspect-brk") + .long("inspect-brk") + .value_name("HOST:PORT") + .help( + "activate inspector on host:port and break at start of user script", + ) + .min_values(0) + .max_values(1) + .require_equals(true) + .takes_value(true), + ) +} + +fn inspect_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) { + const DEFAULT: &str = "127.0.0.1:9229"; + flags.inspect = if matches.is_present("inspect") { + if let Some(host) = matches.value_of("inspect") { + Some(host.to_string()) + } else { + Some(DEFAULT.to_string()) + } + } else { + None + }; + flags.inspect_brk = if matches.is_present("inspect-brk") { + if let Some(host) = matches.value_of("inspect-brk") { + Some(host.to_string()) + } else { + Some(DEFAULT.to_string()) + } + } else { + None + }; +} + fn reload_arg<'a, 'b>() -> Arg<'a, 'b> { Arg::with_name("reload") .short("r") @@ -1132,6 +1280,7 @@ fn arg_hacks(mut args: Vec) -> Vec { let subcommands = sset![ "bundle", "completions", + "doc", "eval", "fetch", "fmt", @@ -1142,7 +1291,8 @@ fn arg_hacks(mut args: Vec) -> Vec { "types", "install", "help", - "version" + "version", + "upgrade" ]; let modifier_flags = sset!["-h", "--help", "-V", "--version"]; // deno [subcommand|behavior modifier flags] -> do nothing @@ -1188,6 +1338,23 @@ mod tests { assert_eq!(args4, ["deno", "run", "-A", "script.js", "-L=info"]); } + #[test] + fn upgrade() { + let r = + flags_from_vec_safe(svec!["deno", "upgrade", "--dry-run", "--force"]); + let flags = r.unwrap(); + assert_eq!( + flags, + Flags { + subcommand: DenoSubcommand::Upgrade { + force: true, + dry_run: true, + }, + ..Flags::default() + } + ); + } + #[test] fn version() { let r = flags_from_vec_safe(svec!["deno", "--version"]); @@ -2273,3 +2440,73 @@ fn repl_with_cafile() { } ); } + +#[test] +fn doc() { + let r = + flags_from_vec_safe(svec!["deno", "doc", "--json", "path/to/module.ts"]); + assert_eq!( + r.unwrap(), + Flags { + subcommand: DenoSubcommand::Doc { + json: true, + source_file: "path/to/module.ts".to_string(), + filter: None, + }, + ..Flags::default() + } + ); + + let r = flags_from_vec_safe(svec![ + "deno", + "doc", + "path/to/module.ts", + "SomeClass.someField" + ]); + assert_eq!( + r.unwrap(), + Flags { + subcommand: DenoSubcommand::Doc { + json: false, + source_file: "path/to/module.ts".to_string(), + filter: Some("SomeClass.someField".to_string()), + }, + ..Flags::default() + } + ); +} + +#[test] +fn inspect_default_host() { + let r = flags_from_vec_safe(svec!["deno", "run", "--inspect", "foo.js"]); + assert_eq!( + r.unwrap(), + Flags { + subcommand: DenoSubcommand::Run { + script: "foo.js".to_string(), + }, + inspect: Some("127.0.0.1:9229".to_string()), + ..Flags::default() + } + ); +} + +#[test] +fn inspect_custom_host() { + let r = flags_from_vec_safe(svec![ + "deno", + "run", + "--inspect=deno.land:80", + "foo.js" + ]); + assert_eq!( + r.unwrap(), + Flags { + subcommand: DenoSubcommand::Run { + script: "foo.js".to_string(), + }, + inspect: Some("deno.land:80".to_string()), + ..Flags::default() + } + ); +} diff --git a/cli/fmt.rs b/cli/fmt.rs index 8d2f982df90db6..edfc277305c45d 100644 --- a/cli/fmt.rs +++ b/cli/fmt.rs @@ -37,15 +37,23 @@ fn is_supported(path: &Path) -> bool { fn get_config() -> dprint::configuration::Configuration { use dprint::configuration::*; - ConfigurationBuilder::new() - .line_width(80) - .indent_width(2) - .next_control_flow_position(NextControlFlowPosition::SameLine) - .binary_expression_operator_position(OperatorPosition::SameLine) - .brace_position(BracePosition::SameLine) // default is NextLineIfHanging - .comment_line_force_space_after_slashes(false) - .construct_signature_space_after_new_keyword(true) - .build() + ConfigurationBuilder::new().prettier().build() +} + +// TODO(ry) dprint seems to panic unnecessarally sometimes. Until it matures +// we'll use a catch_unwind to avoid passing it on to our users. +fn format_text_ignore_panic( + file_path_str: &str, + file_contents: &str, + config: &dprint::configuration::Configuration, +) -> Result, String> { + let catch_result = std::panic::catch_unwind(|| { + dprint::format_text(file_path_str, file_contents, config) + }); + match catch_result { + Ok(dprint_result) => dprint_result, + Err(e) => Err(format!("dprint panic '{}' {:?}", file_path_str, e)), + } } fn check_source_files( @@ -57,7 +65,7 @@ fn check_source_files( for file_path in paths { let file_path_str = file_path.to_string_lossy(); let file_contents = fs::read_to_string(&file_path).unwrap(); - match dprint::format_text(&file_path_str, &file_contents, &config) { + match format_text_ignore_panic(&file_path_str, &file_contents, &config) { Ok(None) => { // nothing to format, pass } @@ -101,30 +109,23 @@ fn format_source_files( for file_path in paths { let file_path_str = file_path.to_string_lossy(); let file_contents = fs::read_to_string(&file_path)?; - // TODO(ry) dprint seems to panic unnecessarally sometimes. Until it matures - // we'll use a catch_unwind to avoid passing it on to our users. - let catch_unwind_result = std::panic::catch_unwind(|| { - dprint::format_text(&file_path_str, &file_contents, &config) - }); - if let Ok(dprint_result) = catch_unwind_result { - match dprint_result { - Ok(None) => { - // nothing to format, pass - } - Ok(Some(formatted_text)) => { - if formatted_text != file_contents { - println!("{}", file_path_str); - fs::write(&file_path, formatted_text)?; - not_formatted_files.push(file_path); - } - } - Err(e) => { - eprintln!("Error formatting: {}", &file_path_str); - eprintln!(" {}", e); + let dprint_result = + format_text_ignore_panic(&file_path_str, &file_contents, &config); + match dprint_result { + Ok(None) => { + // nothing to format, pass + } + Ok(Some(formatted_text)) => { + if formatted_text != file_contents { + println!("{}", file_path_str); + fs::write(&file_path, formatted_text)?; + not_formatted_files.push(file_path); } } - } else { - eprintln!("dprint panic {}", file_path_str); + Err(e) => { + eprintln!("Error formatting: {}", &file_path_str); + eprintln!(" {}", e); + } } } diff --git a/cli/fmt_errors.rs b/cli/fmt_errors.rs index 73d6bb2d231d42..0a22b4625fbc26 100644 --- a/cli/fmt_errors.rs +++ b/cli/fmt_errors.rs @@ -10,6 +10,8 @@ use std::error::Error; use std::fmt; use std::ops::Deref; +const SOURCE_ABBREV_THRESHOLD: usize = 150; + /// A trait which specifies parts of a diagnostic like item needs to be able to /// generate to conform its display to other diagnostic like items pub trait DisplayFormatter { @@ -74,8 +76,9 @@ pub fn format_maybe_source_line( let source_line = source_line.as_ref().unwrap(); // sometimes source_line gets set with an empty string, which then outputs - // an empty source line when displayed, so need just short circuit here - if source_line.is_empty() { + // an empty source line when displayed, so need just short circuit here. + // Also short-circuit on error line too long. + if source_line.is_empty() || source_line.len() > SOURCE_ABBREV_THRESHOLD { return "".to_string(); } diff --git a/cli/global_state.rs b/cli/global_state.rs index 45a31406cbeb03..001c3f55fb96e6 100644 --- a/cli/global_state.rs +++ b/cli/global_state.rs @@ -9,6 +9,7 @@ use crate::deno_dir; use crate::file_fetcher::SourceFileFetcher; use crate::flags; use crate::http_cache; +use crate::inspector::InspectorServer; use crate::lockfile::Lockfile; use crate::msg; use crate::permissions::DenoPermissions; @@ -42,6 +43,7 @@ pub struct GlobalStateInner { pub wasm_compiler: WasmCompiler, pub lockfile: Option>, pub compiler_starts: AtomicUsize, + pub inspector_server: Option, compile_lock: AsyncMutex<()>, } @@ -82,7 +84,16 @@ impl GlobalState { None }; + let inspector_server = if let Some(ref host) = flags.inspect { + Some(InspectorServer::new(host, false)) + } else if let Some(ref host) = flags.inspect_brk { + Some(InspectorServer::new(host, true)) + } else { + None + }; + let inner = GlobalStateInner { + inspector_server, dir, permissions: DenoPermissions::from_flags(&flags), flags, diff --git a/cli/inspector.rs b/cli/inspector.rs new file mode 100644 index 00000000000000..203551f6fcd8be --- /dev/null +++ b/cli/inspector.rs @@ -0,0 +1,554 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + +// The documentation for the inspector API is sparse, but these are helpful: +// https://chromedevtools.github.io/devtools-protocol/ +// https://hyperandroid.com/2020/02/12/v8-inspector-from-an-embedder-standpoint/ + +use deno_core::v8; +use futures; +use futures::executor; +use futures::future; +use futures::FutureExt; +use futures::SinkExt; +use futures::StreamExt; +use std::collections::HashMap; +use std::ffi::c_void; +use std::future::Future; +use std::mem::MaybeUninit; +use std::net::SocketAddrV4; +use std::pin::Pin; +use std::ptr; +use std::sync::atomic::AtomicBool; +use std::sync::atomic::Ordering; +use std::sync::Arc; +use std::task::Context; +use std::task::Poll; +use tokio; +use tokio::sync::mpsc; +use tokio::sync::mpsc::error::TryRecvError; +use uuid::Uuid; +use warp; +use warp::filters::ws; +use warp::Filter; + +const CONTEXT_GROUP_ID: i32 = 1; + +/// Owned by GloalState, this channel end can be used by any isolate thread +/// to register it's inspector with the inspector server. +type ServerMsgTx = mpsc::UnboundedSender; +/// Owned by the inspector server thread, used to to receive information about +/// new isolates. +type ServerMsgRx = mpsc::UnboundedReceiver; +/// These messages can be sent from any thread to the server thread. +enum ServerMsg { + AddInspector(InspectorInfo), +} + +/// Owned by the web socket server. Relays incoming websocket connections and +/// messages to the isolate/inspector thread. +type FrontendToInspectorTx = mpsc::UnboundedSender; +/// Owned by the isolate/worker. Receives incoming websocket connections and +/// messages from the inspector server thread. +type FrontendToInspectorRx = mpsc::UnboundedReceiver; +/// Messages sent over the FrontendToInspectorTx/FrontendToInspectorRx channel. +pub enum FrontendToInspectorMsg { + WsConnection { + session_uuid: Uuid, + session_to_frontend_tx: SessionToFrontendTx, + }, + WsIncoming { + session_uuid: Uuid, + msg: ws::Message, + }, +} + +/// Owned by the deno inspector session, used to forward messages from the +/// inspector channel on the isolate thread to the websocket that is owned by +/// the inspector server. +type SessionToFrontendTx = mpsc::UnboundedSender; +/// Owned by the inspector server. Messages arriving on this channel, coming +/// from the inspector session on the isolate thread are forwarded over the +/// websocket to the devtools frontend. +type SessionToFrontendRx = mpsc::UnboundedReceiver; + +/// Stored in a UUID hashmap, used by WS server. Clonable. +#[derive(Clone)] +struct InspectorInfo { + uuid: Uuid, + frontend_to_inspector_tx: FrontendToInspectorTx, + inspector_handle: DenoInspectorHandle, +} + +/// Owned by GlobalState. +pub struct InspectorServer { + address: SocketAddrV4, + thread_handle: Option>, + server_msg_tx: Option, +} + +impl InspectorServer { + pub fn new(host: &str, brk: bool) -> Self { + if brk { + todo!("--inspect-brk not yet supported"); + } + let address = host.parse::().unwrap(); + let (server_msg_tx, server_msg_rx) = mpsc::unbounded_channel::(); + let thread_handle = std::thread::spawn(move || { + crate::tokio_util::run_basic(server(address, server_msg_rx)); + }); + Self { + address, + thread_handle: Some(thread_handle), + server_msg_tx: Some(server_msg_tx), + } + } + + /// Each worker/isolate to be debugged should call this exactly one. + /// Called from worker's thread + pub fn add_inspector( + &self, + isolate: &mut deno_core::Isolate, + ) -> Box { + let deno_core::Isolate { + v8_isolate, + global_context, + .. + } = isolate; + let v8_isolate = v8_isolate.as_mut().unwrap(); + + let mut hs = v8::HandleScope::new(v8_isolate); + let scope = hs.enter(); + let context = global_context.get(scope).unwrap(); + + let server_msg_tx = self.server_msg_tx.as_ref().unwrap().clone(); + let address = self.address; + let (frontend_to_inspector_tx, frontend_to_inspector_rx) = + mpsc::unbounded_channel::(); + let uuid = Uuid::new_v4(); + + let inspector = crate::inspector::DenoInspector::new( + scope, + context, + frontend_to_inspector_rx, + ); + + info!( + "Debugger listening on {}", + websocket_debugger_url(address, &uuid) + ); + + server_msg_tx + .send(ServerMsg::AddInspector(InspectorInfo { + uuid, + frontend_to_inspector_tx, + inspector_handle: DenoInspectorHandle::new( + &inspector, + v8_isolate.thread_safe_handle(), + ), + })) + .unwrap_or_else(|_| { + panic!("sending message to inspector server thread failed"); + }); + + inspector + } +} + +impl Drop for InspectorServer { + fn drop(&mut self) { + self.server_msg_tx.take(); + self.thread_handle.take().unwrap().join().unwrap(); + panic!("TODO: this drop is never called"); + } +} + +fn websocket_debugger_url(address: SocketAddrV4, uuid: &Uuid) -> String { + format!("ws://{}:{}/ws/{}", address.ip(), address.port(), uuid) +} + +async fn server(address: SocketAddrV4, mut server_msg_rx: ServerMsgRx) { + let inspector_map = HashMap::::new(); + let inspector_map = Arc::new(std::sync::Mutex::new(inspector_map)); + + let inspector_map_ = inspector_map.clone(); + let msg_handler = async move { + while let Some(msg) = server_msg_rx.next().await { + match msg { + ServerMsg::AddInspector(inspector_info) => { + let existing = inspector_map_ + .lock() + .unwrap() + .insert(inspector_info.uuid, inspector_info); + if existing.is_some() { + panic!("UUID already in map"); + } + } + }; + } + }; + + let inspector_map_ = inspector_map.clone(); + let websocket = warp::path("ws") + .and(warp::path::param()) + .and(warp::ws()) + .map(move |uuid: String, ws: warp::ws::Ws| { + let inspector_map__ = inspector_map_.clone(); + ws.on_upgrade(move |socket| async move { + let inspector_info = { + if let Ok(uuid) = Uuid::parse_str(&uuid) { + let g = inspector_map__.lock().unwrap(); + if let Some(inspector_info) = g.get(&uuid) { + inspector_info.clone() + } else { + return; + } + } else { + return; + } + }; + + // send a message back so register_worker can return... + let (mut ws_tx, mut ws_rx) = socket.split(); + + let (session_to_frontend_tx, mut session_to_frontend_rx): ( + SessionToFrontendTx, + SessionToFrontendRx, + ) = mpsc::unbounded_channel(); + + // Not to be confused with the WS's uuid... + let session_uuid = Uuid::new_v4(); + + inspector_info + .frontend_to_inspector_tx + .send(FrontendToInspectorMsg::WsConnection { + session_to_frontend_tx, + session_uuid, + }) + .unwrap_or_else(|_| { + panic!("sending message to frontend_to_inspector_tx failed"); + }); + + inspector_info.inspector_handle.interrupt(); + + let pump_to_inspector = async { + while let Some(Ok(msg)) = ws_rx.next().await { + inspector_info + .frontend_to_inspector_tx + .send(FrontendToInspectorMsg::WsIncoming { msg, session_uuid }) + .unwrap_or_else(|_| { + panic!("sending message to frontend_to_inspector_tx failed"); + }); + + inspector_info.inspector_handle.interrupt(); + } + }; + + let pump_from_session = async { + while let Some(msg) = session_to_frontend_rx.next().await { + ws_tx.send(msg).await.ok(); + } + }; + + future::join(pump_to_inspector, pump_from_session).await; + }) + }); + + let inspector_map_ = inspector_map.clone(); + let json_list = + warp::path("json") + .map(move || { + let g = inspector_map_.lock().unwrap(); + let json_values: Vec = g.iter().map(|(uuid, _)| { + let url = websocket_debugger_url(address, uuid); + json!({ + "description": "deno", + "devtoolsFrontendUrl": format!("chrome-devtools://devtools/bundled/js_app.html?experiments=true&v8only=true&ws={}", url), + "faviconUrl": "https://deno.land/favicon.ico", + "id": uuid.to_string(), + "title": format!("deno[{}]", std::process::id()), + "type": "deno", + "url": "file://", + "webSocketDebuggerUrl": url, + }) + }).collect(); + warp::reply::json(&json!(json_values)) + }); + + let version = warp::path!("json" / "version").map(|| { + warp::reply::json(&json!({ + "Browser": format!("Deno/{}", crate::version::DENO), + "Protocol-Version": "1.3", + "V8-Version": crate::version::v8(), + })) + }); + + let routes = websocket.or(version).or(json_list); + let (_, web_handler) = warp::serve(routes) + .try_bind_ephemeral(address) + .unwrap_or_else(|e| { + eprintln!("Cannot start inspector server: {}", e); + std::process::exit(1); + }); + + future::join(msg_handler, web_handler).await; +} + +pub struct DenoInspector { + client: v8::inspector::V8InspectorClientBase, + inspector: v8::UniqueRef, + pub sessions: HashMap>, + frontend_to_inspector_rx: FrontendToInspectorRx, + paused: bool, + interrupted: Arc, +} + +impl DenoInspector { + pub fn new

( + scope: &mut P, + context: v8::Local, + frontend_to_inspector_rx: FrontendToInspectorRx, + ) -> Box + where + P: v8::InIsolate, + { + let mut deno_inspector = new_box_with(|address| Self { + client: v8::inspector::V8InspectorClientBase::new::(), + // TODO(piscisaureus): V8Inspector::create() should require that + // the 'client' argument cannot move. + inspector: v8::inspector::V8Inspector::create(scope, unsafe { + &mut *address + }), + sessions: HashMap::new(), + frontend_to_inspector_rx, + paused: false, + interrupted: Arc::new(AtomicBool::new(false)), + }); + + let empty_view = v8::inspector::StringView::empty(); + deno_inspector.inspector.context_created( + context, + CONTEXT_GROUP_ID, + &empty_view, + ); + + deno_inspector + } + + pub fn connect( + &mut self, + session_uuid: Uuid, + session_to_frontend_tx: SessionToFrontendTx, + ) { + let session = + DenoInspectorSession::new(&mut self.inspector, session_to_frontend_tx); + self.sessions.insert(session_uuid, session); + } + + fn dispatch_frontend_to_inspector_msg( + &mut self, + msg: FrontendToInspectorMsg, + ) { + match msg { + FrontendToInspectorMsg::WsConnection { + session_uuid, + session_to_frontend_tx, + } => { + self.connect(session_uuid, session_to_frontend_tx); + } + FrontendToInspectorMsg::WsIncoming { session_uuid, msg } => { + if let Some(deno_session) = self.sessions.get_mut(&session_uuid) { + deno_session.dispatch_protocol_message(msg) + } else { + info!("Unknown inspector session {}. msg {:?}", session_uuid, msg); + } + } + }; + } + + extern "C" fn poll_interrupt( + _isolate: &mut v8::Isolate, + self_ptr: *mut c_void, + ) { + let self_ = unsafe { &mut *(self_ptr as *mut Self) }; + let _ = self_.poll_without_waker(); + } + + fn poll_without_waker(&mut self) -> Poll<::Output> { + loop { + match self.frontend_to_inspector_rx.try_recv() { + Ok(msg) => self.dispatch_frontend_to_inspector_msg(msg), + Err(TryRecvError::Closed) => break Poll::Ready(()), + Err(TryRecvError::Empty) + if self.interrupted.swap(false, Ordering::AcqRel) => {} + Err(TryRecvError::Empty) => break Poll::Pending, + } + } + } +} + +/// DenoInspector implements a Future so that it can poll for incoming messages +/// from the WebSocket server. Since a Worker ownes a DenoInspector, and because +/// a Worker is a Future too, Worker::poll will call this. +impl Future for DenoInspector { + type Output = (); + + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { + let self_ = self.get_mut(); + loop { + match self_.frontend_to_inspector_rx.poll_recv(cx) { + Poll::Ready(Some(msg)) => self_.dispatch_frontend_to_inspector_msg(msg), + Poll::Ready(None) => break Poll::Ready(()), + Poll::Pending if self_.interrupted.swap(false, Ordering::AcqRel) => {} + Poll::Pending => break Poll::Pending, + } + } + } +} + +impl v8::inspector::V8InspectorClientImpl for DenoInspector { + fn base(&self) -> &v8::inspector::V8InspectorClientBase { + &self.client + } + + fn base_mut(&mut self) -> &mut v8::inspector::V8InspectorClientBase { + &mut self.client + } + + fn run_message_loop_on_pause(&mut self, context_group_id: i32) { + assert_eq!(context_group_id, CONTEXT_GROUP_ID); + assert!(!self.paused); + self.paused = true; + + // Creating a new executor and calling block_on generally causes a panic. + // In this case it works because the outer executor is provided by tokio + // and the one created here comes from the 'futures' crate, and they don't + // see each other. + let dispatch_messages_while_paused = + future::poll_fn(|cx| match self.poll_unpin(cx) { + Poll::Pending if self.paused => Poll::Pending, + _ => Poll::Ready(()), + }); + executor::block_on(dispatch_messages_while_paused); + } + + fn quit_message_loop_on_pause(&mut self) { + self.paused = false; + } + + fn run_if_waiting_for_debugger(&mut self, context_group_id: i32) { + assert_eq!(context_group_id, CONTEXT_GROUP_ID); + } +} + +#[derive(Clone)] +struct DenoInspectorHandle { + deno_inspector_ptr: *mut c_void, + isolate_handle: v8::IsolateHandle, + interrupted: Arc, +} + +impl DenoInspectorHandle { + pub fn new( + deno_inspector: &DenoInspector, + isolate_handle: v8::IsolateHandle, + ) -> Self { + Self { + deno_inspector_ptr: deno_inspector as *const DenoInspector + as *const c_void as *mut c_void, + isolate_handle, + interrupted: deno_inspector.interrupted.clone(), + } + } + + pub fn interrupt(&self) { + if !self.interrupted.swap(true, Ordering::AcqRel) { + self.isolate_handle.request_interrupt( + DenoInspector::poll_interrupt, + self.deno_inspector_ptr, + ); + } + } +} + +unsafe impl Send for DenoInspectorHandle {} +unsafe impl Sync for DenoInspectorHandle {} + +/// sub-class of v8::inspector::Channel +pub struct DenoInspectorSession { + channel: v8::inspector::ChannelBase, + session: v8::UniqueRef, + session_to_frontend_tx: SessionToFrontendTx, +} + +impl DenoInspectorSession { + pub fn new( + inspector: &mut v8::inspector::V8Inspector, + session_to_frontend_tx: SessionToFrontendTx, + ) -> Box { + new_box_with(|address| { + let empty_view = v8::inspector::StringView::empty(); + Self { + channel: v8::inspector::ChannelBase::new::(), + session: inspector.connect( + CONTEXT_GROUP_ID, + // Todo(piscisaureus): V8Inspector::connect() should require that + // the 'channel' argument cannot move. + unsafe { &mut *address }, + &empty_view, + ), + session_to_frontend_tx, + } + }) + } + + pub fn dispatch_protocol_message(&mut self, ws_msg: ws::Message) { + let bytes = ws_msg.as_bytes(); + let string_view = v8::inspector::StringView::from(bytes); + self.session.dispatch_protocol_message(&string_view); + } +} + +impl v8::inspector::ChannelImpl for DenoInspectorSession { + fn base(&self) -> &v8::inspector::ChannelBase { + &self.channel + } + + fn base_mut(&mut self) -> &mut v8::inspector::ChannelBase { + &mut self.channel + } + + fn send_response( + &mut self, + _call_id: i32, + message: v8::UniquePtr, + ) { + let ws_msg = v8_to_ws_msg(message); + self.session_to_frontend_tx.send(ws_msg).unwrap(); + } + + fn send_notification( + &mut self, + message: v8::UniquePtr, + ) { + let ws_msg = v8_to_ws_msg(message); + self.session_to_frontend_tx.send(ws_msg).unwrap(); + } + + fn flush_protocol_notifications(&mut self) {} +} + +// TODO impl From or Into +fn v8_to_ws_msg( + message: v8::UniquePtr, +) -> ws::Message { + let mut x = message.unwrap(); + let s = x.string().to_string(); + ws::Message::text(s) +} + +fn new_box_with(new_fn: impl FnOnce(*mut T) -> T) -> Box { + let b = Box::new(MaybeUninit::::uninit()); + let p = Box::into_raw(b) as *mut T; + unsafe { ptr::write(p, new_fn(p)) }; + unsafe { Box::from_raw(p) } +} diff --git a/cli/js/buffer.ts b/cli/js/buffer.ts index db2bb22e4d0738..fcb688b9bc1d44 100644 --- a/cli/js/buffer.ts +++ b/cli/js/buffer.ts @@ -28,37 +28,37 @@ function copyBytes(dst: Uint8Array, src: Uint8Array, off = 0): number { } export class Buffer implements Reader, SyncReader, Writer, SyncWriter { - private buf: Uint8Array; // contents are the bytes buf[off : len(buf)] - private off = 0; // read at buf[off], write at buf[buf.byteLength] + #buf: Uint8Array; // contents are the bytes buf[off : len(buf)] + #off = 0; // read at buf[off], write at buf[buf.byteLength] constructor(ab?: ArrayBuffer) { if (ab == null) { - this.buf = new Uint8Array(0); + this.#buf = new Uint8Array(0); return; } - this.buf = new Uint8Array(ab); + this.#buf = new Uint8Array(ab); } bytes(): Uint8Array { - return this.buf.subarray(this.off); + return this.#buf.subarray(this.#off); } toString(): string { const decoder = new TextDecoder(); - return decoder.decode(this.buf.subarray(this.off)); + return decoder.decode(this.#buf.subarray(this.#off)); } empty(): boolean { - return this.buf.byteLength <= this.off; + return this.#buf.byteLength <= this.#off; } get length(): number { - return this.buf.byteLength - this.off; + return this.#buf.byteLength - this.#off; } get capacity(): number { - return this.buf.buffer.byteLength; + return this.#buf.buffer.byteLength; } truncate(n: number): void { @@ -69,27 +69,27 @@ export class Buffer implements Reader, SyncReader, Writer, SyncWriter { if (n < 0 || n > this.length) { throw Error("bytes.Buffer: truncation out of range"); } - this._reslice(this.off + n); + this.#reslice(this.#off + n); } reset(): void { - this._reslice(0); - this.off = 0; + this.#reslice(0); + this.#off = 0; } - private _tryGrowByReslice(n: number): number { - const l = this.buf.byteLength; + #tryGrowByReslice = (n: number): number => { + const l = this.#buf.byteLength; if (n <= this.capacity - l) { - this._reslice(l + n); + this.#reslice(l + n); return l; } return -1; - } + }; - private _reslice(len: number): void { - assert(len <= this.buf.buffer.byteLength); - this.buf = new Uint8Array(this.buf.buffer, 0, len); - } + #reslice = (len: number): void => { + assert(len <= this.#buf.buffer.byteLength); + this.#buf = new Uint8Array(this.#buf.buffer, 0, len); + }; readSync(p: Uint8Array): number | EOF { if (this.empty()) { @@ -101,8 +101,8 @@ export class Buffer implements Reader, SyncReader, Writer, SyncWriter { } return EOF; } - const nread = copyBytes(p, this.buf.subarray(this.off)); - this.off += nread; + const nread = copyBytes(p, this.#buf.subarray(this.#off)); + this.#off += nread; return nread; } @@ -112,8 +112,8 @@ export class Buffer implements Reader, SyncReader, Writer, SyncWriter { } writeSync(p: Uint8Array): number { - const m = this._grow(p.byteLength); - return copyBytes(this.buf, p, m); + const m = this.#grow(p.byteLength); + return copyBytes(this.#buf, p, m); } write(p: Uint8Array): Promise { @@ -121,14 +121,14 @@ export class Buffer implements Reader, SyncReader, Writer, SyncWriter { return Promise.resolve(n); } - private _grow(n: number): number { + #grow = (n: number): number => { const m = this.length; // If buffer is empty, reset to recover space. - if (m === 0 && this.off !== 0) { + if (m === 0 && this.#off !== 0) { this.reset(); } // Fast: Try to grow by means of a reslice. - const i = this._tryGrowByReslice(n); + const i = this.#tryGrowByReslice(n); if (i >= 0) { return i; } @@ -138,41 +138,41 @@ export class Buffer implements Reader, SyncReader, Writer, SyncWriter { // ArrayBuffer. We only need m+n <= c to slide, but // we instead let capacity get twice as large so we // don't spend all our time copying. - copyBytes(this.buf, this.buf.subarray(this.off)); + copyBytes(this.#buf, this.#buf.subarray(this.#off)); } else if (c > MAX_SIZE - c - n) { throw new Error("The buffer cannot be grown beyond the maximum size."); } else { // Not enough space anywhere, we need to allocate. const buf = new Uint8Array(2 * c + n); - copyBytes(buf, this.buf.subarray(this.off)); - this.buf = buf; + copyBytes(buf, this.#buf.subarray(this.#off)); + this.#buf = buf; } - // Restore this.off and len(this.buf). - this.off = 0; - this._reslice(m + n); + // Restore this.#off and len(this.#buf). + this.#off = 0; + this.#reslice(m + n); return m; - } + }; grow(n: number): void { if (n < 0) { throw Error("Buffer.grow: negative count"); } - const m = this._grow(n); - this._reslice(m); + const m = this.#grow(n); + this.#reslice(m); } async readFrom(r: Reader): Promise { let n = 0; while (true) { try { - const i = this._grow(MIN_READ); - this._reslice(i); - const fub = new Uint8Array(this.buf.buffer, i); + const i = this.#grow(MIN_READ); + this.#reslice(i); + const fub = new Uint8Array(this.#buf.buffer, i); const nread = await r.read(fub); if (nread === EOF) { return n; } - this._reslice(i + nread); + this.#reslice(i + nread); n += nread; } catch (e) { return n; @@ -184,14 +184,14 @@ export class Buffer implements Reader, SyncReader, Writer, SyncWriter { let n = 0; while (true) { try { - const i = this._grow(MIN_READ); - this._reslice(i); - const fub = new Uint8Array(this.buf.buffer, i); + const i = this.#grow(MIN_READ); + this.#reslice(i); + const fub = new Uint8Array(this.#buf.buffer, i); const nread = r.readSync(fub); if (nread === EOF) { return n; } - this._reslice(i + nread); + this.#reslice(i + nread); n += nread; } catch (e) { return n; diff --git a/cli/js/build.ts b/cli/js/build.ts index c34706139062bb..f00c5b463abf7f 100644 --- a/cli/js/build.ts +++ b/cli/js/build.ts @@ -13,7 +13,7 @@ export interface BuildInfo { export const build: BuildInfo = { arch: "" as Arch, - os: "" as OperatingSystem + os: "" as OperatingSystem, }; export function setBuildInfo(os: OperatingSystem, arch: Arch): void { diff --git a/cli/js/colors.ts b/cli/js/colors.ts index 372e90ba51be40..d0ecdd13962fc7 100644 --- a/cli/js/colors.ts +++ b/cli/js/colors.ts @@ -17,7 +17,7 @@ function code(open: number, close: number): Code { return { open: `\x1b[${open}m`, close: `\x1b[${close}m`, - regexp: new RegExp(`\\x1b\\[${close}m`, "g") + regexp: new RegExp(`\\x1b\\[${close}m`, "g"), }; } diff --git a/cli/js/compiler.ts b/cli/js/compiler.ts index 419f07063aadeb..b3cd3a481e5865 100644 --- a/cli/js/compiler.ts +++ b/cli/js/compiler.ts @@ -21,12 +21,12 @@ import { defaultBundlerOptions, defaultRuntimeCompileOptions, defaultTranspileOptions, - Host + Host, } from "./compiler/host.ts"; import { processImports, processLocalImports, - resolveModules + resolveModules, } from "./compiler/imports.ts"; import { createWriteFile, @@ -35,7 +35,7 @@ import { ignoredDiagnostics, WriteFileState, processConfigureResponse, - base64ToUint8Array + base64ToUint8Array, } from "./compiler/util.ts"; import { Diagnostic, DiagnosticItem } from "./diagnostics.ts"; import { fromTypeScriptDiagnostic } from "./diagnostics_util.ts"; @@ -93,7 +93,7 @@ async function compile( const { bundle, config, configPath, outFile, rootNames, target } = request; util.log(">>> compile start", { rootNames, - type: CompilerRequestType[request.type] + type: CompilerRequestType[request.type], }); // When a programme is emitted, TypeScript will call `writeFile` with @@ -108,14 +108,14 @@ async function compile( bundle, host: undefined, outFile, - rootNames + rootNames, }; const writeFile = createWriteFile(state); const host = (state.host = new Host({ bundle, target, - writeFile + writeFile, })); let diagnostics: readonly ts.Diagnostic[] | undefined; @@ -129,7 +129,7 @@ async function compile( // requesting those from the privileged side, populating the in memory // cache which will be used by the host, before resolving. const resolvedRootModules = await processImports( - rootNames.map(rootName => [rootName, rootName]), + rootNames.map((rootName) => [rootName, rootName]), undefined, bundle || host.getCompilationSettings().checkJs ); @@ -143,7 +143,7 @@ async function compile( rootNames, options, host, - oldProgram: TS_SNAPSHOT_PROGRAM + oldProgram: TS_SNAPSHOT_PROGRAM, }); diagnostics = ts @@ -171,12 +171,12 @@ async function compile( emitSkipped, diagnostics: diagnostics.length ? fromTypeScriptDiagnostic(diagnostics) - : undefined + : undefined, }; util.log("<<< compile end", { rootNames, - type: CompilerRequestType[request.type] + type: CompilerRequestType[request.type], }); return result; @@ -190,7 +190,7 @@ async function runtimeCompile( util.log(">>> runtime compile start", { rootName, bundle, - sources: sources ? Object.keys(sources) : undefined + sources: sources ? Object.keys(sources) : undefined, }); // resolve the root name, if there are sources, the root name does not @@ -232,7 +232,7 @@ async function runtimeCompile( const resolvedNames = resolveModules(additionalFiles); rootNames.push( ...(await processImports( - resolvedNames.map(rn => [rn, rn]), + resolvedNames.map((rn) => [rn, rn]), undefined, checkJsImports )) @@ -246,14 +246,14 @@ async function runtimeCompile( rootNames, sources, emitMap: {}, - emitBundle: undefined + emitBundle: undefined, }; const writeFile = createWriteFile(state); const host = (state.host = new Host({ bundle, target, - writeFile + writeFile, })); const compilerOptions = [defaultRuntimeCompileOptions]; if (convertedOptions) { @@ -268,7 +268,7 @@ async function runtimeCompile( rootNames, options: host.getCompilationSettings(), host, - oldProgram: TS_SNAPSHOT_PROGRAM + oldProgram: TS_SNAPSHOT_PROGRAM, }); if (bundle) { @@ -288,7 +288,7 @@ async function runtimeCompile( rootName, sources: sources ? Object.keys(sources) : undefined, bundle, - emitMap: Object.keys(state.emitMap) + emitMap: Object.keys(state.emitMap), }); const maybeDiagnostics = diagnostics.length @@ -320,7 +320,7 @@ function runtimeTranspile( inputText, { fileName, - compilerOptions + compilerOptions, } ); result[fileName] = { source, map }; @@ -329,7 +329,7 @@ function runtimeTranspile( } async function tsCompilerOnMessage({ - data: request + data: request, }: { data: CompilerRequest; }): Promise { @@ -364,7 +364,7 @@ async function tsCompilerOnMessage({ } async function wasmCompilerOnMessage({ - data: binary + data: binary, }: { data: string; }): Promise { @@ -411,12 +411,12 @@ Object.defineProperties(globalThis, { value: bootstrapWasmCompilerRuntime, enumerable: false, writable: false, - configurable: false + configurable: false, }, bootstrapTsCompilerRuntime: { value: bootstrapTsCompilerRuntime, enumerable: false, writable: false, - configurable: false - } + configurable: false, + }, }); diff --git a/cli/js/compiler/api.ts b/cli/js/compiler/api.ts index 409ad94db2b3b7..b7c57b528f58cc 100644 --- a/cli/js/compiler/api.ts +++ b/cli/js/compiler/api.ts @@ -157,7 +157,7 @@ export async function transpileOnly( util.log("Deno.transpileOnly", { sources: Object.keys(sources), options }); const payload = { sources, - options: JSON.stringify(options) + options: JSON.stringify(options), }; const result = await runtimeCompilerOps.transpile(payload); return JSON.parse(result); @@ -172,12 +172,12 @@ export async function compile( rootName: sources ? rootName : checkRelative(rootName), sources, options: JSON.stringify(options), - bundle: false + bundle: false, }; util.log("Deno.compile", { rootName: payload.rootName, sources: !!sources, - options + options, }); const result = await runtimeCompilerOps.compile(payload); return JSON.parse(result); @@ -192,12 +192,12 @@ export async function bundle( rootName: sources ? rootName : checkRelative(rootName), sources, options: JSON.stringify(options), - bundle: true + bundle: true, }; util.log("Deno.bundle", { rootName: payload.rootName, sources: !!sources, - options + options, }); const result = await runtimeCompilerOps.compile(payload); return JSON.parse(result); diff --git a/cli/js/compiler/bootstrap.ts b/cli/js/compiler/bootstrap.ts index 978ddbaf89f89c..63de783cf38806 100644 --- a/cli/js/compiler/bootstrap.ts +++ b/cli/js/compiler/bootstrap.ts @@ -9,7 +9,7 @@ import { getAsset } from "./util.ts"; // load all type definitions and snapshot them. const host = new Host({ target: CompilerHostTarget.Main, - writeFile(): void {} + writeFile(): void {}, }); const options = host.getCompilationSettings(); @@ -34,7 +34,7 @@ host.getSourceFile( export const TS_SNAPSHOT_PROGRAM = ts.createProgram({ rootNames: [`${ASSETS}/bootstrap.ts`], options, - host + host, }); export const SYSTEM_LOADER = getAsset("system_loader.js"); diff --git a/cli/js/compiler/bundler.ts b/cli/js/compiler/bundler.ts index 8e35befc822171..c9578fe207dfe5 100644 --- a/cli/js/compiler/bundler.ts +++ b/cli/js/compiler/bundler.ts @@ -14,7 +14,7 @@ function normalizeUrl(rootName: string): string { path, false, "/", - code => code === CHAR_FORWARD_SLASH + (code) => code === CHAR_FORWARD_SLASH )}`; } else { return rootName; @@ -29,7 +29,7 @@ export function buildBundle( // when outputting to AMD and a single outfile, TypeScript makes up the module // specifiers which are used to define the modules, and doesn't expose them // publicly, so we have to try to replicate - const sources = sourceFiles.map(sf => sf.fileName); + const sources = sourceFiles.map((sf) => sf.fileName); const sharedPath = commonPath(sources); rootName = normalizeUrl(rootName) .replace(sharedPath, "") @@ -79,7 +79,7 @@ export function setRootExports(program: ts.Program, rootModule: string): void { // that when there isn't. There appears to be no clean way of figuring that // out, so inspecting SymbolFlags that might be present that are type only .filter( - sym => + (sym) => sym.flags & ts.SymbolFlags.Class || !( sym.flags & ts.SymbolFlags.Interface || @@ -94,5 +94,5 @@ export function setRootExports(program: ts.Program, rootModule: string): void { sym.flags & ts.SymbolFlags.TypeAliasExcludes ) ) - .map(sym => sym.getName()); + .map((sym) => sym.getName()); } diff --git a/cli/js/compiler/host.ts b/cli/js/compiler/host.ts index 457388bd9a4a6b..70e712ffe1d45a 100644 --- a/cli/js/compiler/host.ts +++ b/cli/js/compiler/host.ts @@ -9,7 +9,7 @@ import * as util from "../util.ts"; export enum CompilerHostTarget { Main = "main", Runtime = "runtime", - Worker = "worker" + Worker = "worker", } export interface CompilerHostOptions { @@ -32,7 +32,7 @@ export const defaultBundlerOptions: ts.CompilerOptions = { outDir: undefined, outFile: `${OUT_DIR}/bundle.js`, // disabled until we have effective way to modify source maps - sourceMap: false + sourceMap: false, }; export const defaultCompileOptions: ts.CompilerOptions = { @@ -47,11 +47,11 @@ export const defaultCompileOptions: ts.CompilerOptions = { sourceMap: true, strict: true, stripComments: true, - target: ts.ScriptTarget.ESNext + target: ts.ScriptTarget.ESNext, }; export const defaultRuntimeCompileOptions: ts.CompilerOptions = { - outDir: undefined + outDir: undefined, }; export const defaultTranspileOptions: ts.CompilerOptions = { @@ -59,7 +59,7 @@ export const defaultTranspileOptions: ts.CompilerOptions = { module: ts.ModuleKind.ESNext, sourceMap: true, scriptComments: true, - target: ts.ScriptTarget.ESNext + target: ts.ScriptTarget.ESNext, }; const ignoredCompilerOptions: readonly string[] = [ @@ -117,43 +117,41 @@ const ignoredCompilerOptions: readonly string[] = [ "types", "typeRoots", "version", - "watch" + "watch", ]; -export class Host implements ts.CompilerHost { - private readonly _options = defaultCompileOptions; - - private _target: CompilerHostTarget; - - private _writeFile: WriteFileCallback; - - private _getAsset(filename: string): SourceFile { - const lastSegment = filename.split("/").pop()!; - const url = ts.libMap.has(lastSegment) - ? ts.libMap.get(lastSegment)! - : lastSegment; - const sourceFile = SourceFile.get(url); - if (sourceFile) { - return sourceFile; - } - const name = url.includes(".") ? url : `${url}.d.ts`; - const sourceCode = getAsset(name); - return new SourceFile({ - url, - filename: `${ASSETS}/${name}`, - mediaType: MediaType.TypeScript, - sourceCode - }); +function getAssetInternal(filename: string): SourceFile { + const lastSegment = filename.split("/").pop()!; + const url = ts.libMap.has(lastSegment) + ? ts.libMap.get(lastSegment)! + : lastSegment; + const sourceFile = SourceFile.get(url); + if (sourceFile) { + return sourceFile; } + const name = url.includes(".") ? url : `${url}.d.ts`; + const sourceCode = getAsset(name); + return new SourceFile({ + url, + filename: `${ASSETS}/${name}`, + mediaType: MediaType.TypeScript, + sourceCode, + }); +} + +export class Host implements ts.CompilerHost { + readonly #options = defaultCompileOptions; + #target: CompilerHostTarget; + #writeFile: WriteFileCallback; /* Deno specific APIs */ constructor({ bundle = false, target, writeFile }: CompilerHostOptions) { - this._target = target; - this._writeFile = writeFile; + this.#target = target; + this.#writeFile = writeFile; if (bundle) { // options we need to change when we are generating a bundle - Object.assign(this._options, defaultBundlerOptions); + Object.assign(this.#options, defaultBundlerOptions); } } @@ -175,22 +173,22 @@ export class Host implements ts.CompilerHost { for (const key of Object.keys(options)) { if ( ignoredCompilerOptions.includes(key) && - (!(key in this._options) || options[key] !== this._options[key]) + (!(key in this.#options) || options[key] !== this.#options[key]) ) { ignoredOptions.push(key); delete options[key]; } } - Object.assign(this._options, options); + Object.assign(this.#options, options); return { ignoredOptions: ignoredOptions.length ? ignoredOptions : undefined, - diagnostics: errors.length ? errors : undefined + diagnostics: errors.length ? errors : undefined, }; } mergeOptions(...options: ts.CompilerOptions[]): ts.CompilerOptions { - Object.assign(this._options, ...options); - return Object.assign({}, this._options); + Object.assign(this.#options, ...options); + return Object.assign({}, this.#options); } /* TypeScript CompilerHost APIs */ @@ -205,7 +203,7 @@ export class Host implements ts.CompilerHost { getCompilationSettings(): ts.CompilerOptions { util.log("compiler::host.getCompilationSettings()"); - return this._options; + return this.#options; } getCurrentDirectory(): string { @@ -214,7 +212,7 @@ export class Host implements ts.CompilerHost { getDefaultLibFileName(_options: ts.CompilerOptions): string { util.log("compiler::host.getDefaultLibFileName()"); - switch (this._target) { + switch (this.#target) { case CompilerHostTarget.Main: case CompilerHostTarget.Runtime: return `${ASSETS}/lib.deno.window.d.ts`; @@ -237,7 +235,7 @@ export class Host implements ts.CompilerHost { try { assert(!shouldCreateNewSourceFile); const sourceFile = fileName.startsWith(ASSETS) - ? this._getAsset(fileName) + ? getAssetInternal(fileName) : SourceFile.get(fileName); assert(sourceFile != null); if (!sourceFile.tsSourceFile) { @@ -278,12 +276,12 @@ export class Host implements ts.CompilerHost { ): Array { util.log("compiler::host.resolveModuleNames", { moduleNames, - containingFile + containingFile, }); - return moduleNames.map(specifier => { + return moduleNames.map((specifier) => { const url = SourceFile.getUrl(specifier, containingFile); const sourceFile = specifier.startsWith(ASSETS) - ? this._getAsset(specifier) + ? getAssetInternal(specifier) : url ? SourceFile.get(url) : undefined; @@ -293,7 +291,7 @@ export class Host implements ts.CompilerHost { return { resolvedFileName: sourceFile.url, isExternalLibraryImport: specifier.startsWith(ASSETS), - extension: sourceFile.extension + extension: sourceFile.extension, }; }); } @@ -310,6 +308,6 @@ export class Host implements ts.CompilerHost { sourceFiles?: readonly ts.SourceFile[] ): void { util.log("compiler::host.writeFile", fileName); - this._writeFile(fileName, data, sourceFiles); + this.#writeFile(fileName, data, sourceFiles); } } diff --git a/cli/js/compiler/imports.ts b/cli/js/compiler/imports.ts index a3246c32f79bf7..6b48ec945cdef4 100644 --- a/cli/js/compiler/imports.ts +++ b/cli/js/compiler/imports.ts @@ -34,7 +34,7 @@ function resolvePath(...pathSegments: string[]): string { resolvedPath, !resolvedAbsolute, "/", - code => code === CHAR_FORWARD_SLASH + (code) => code === CHAR_FORWARD_SLASH ); if (resolvedAbsolute) { @@ -120,7 +120,7 @@ export function processLocalImports( url: moduleName, filename: moduleName, sourceCode: sources[moduleName], - mediaType: getMediaType(moduleName) + mediaType: getMediaType(moduleName), }); sourceFile.cache(specifiers[i][0], referrer); if (!sourceFile.processed) { diff --git a/cli/js/compiler/sourcefile.ts b/cli/js/compiler/sourcefile.ts index e400acbf568c1f..a55de080b3ea7d 100644 --- a/cli/js/compiler/sourcefile.ts +++ b/cli/js/compiler/sourcefile.ts @@ -12,7 +12,7 @@ export enum MediaType { TSX = 3, Json = 4, Wasm = 5, - Unknown = 6 + Unknown = 6, } export interface SourceFileJson { @@ -50,6 +50,11 @@ function getExtension(fileName: string, mediaType: MediaType): ts.Extension { } } +/** A global cache of module source files that have been loaded. */ +const moduleCache: Map = new Map(); +/** A map of maps which cache source files for quicker modules resolution. */ +const specifierCache: Map> = new Map(); + export class SourceFile { extension!: ts.Extension; filename!: string; @@ -63,20 +68,20 @@ export class SourceFile { url!: string; constructor(json: SourceFileJson) { - if (SourceFile._moduleCache.has(json.url)) { + if (moduleCache.has(json.url)) { throw new TypeError("SourceFile already exists"); } Object.assign(this, json); this.extension = getExtension(this.url, this.mediaType); - SourceFile._moduleCache.set(this.url, this); + moduleCache.set(this.url, this); } cache(moduleSpecifier: string, containingFile?: string): void { containingFile = containingFile || ""; - let innerCache = SourceFile._specifierCache.get(containingFile); + let innerCache = specifierCache.get(containingFile); if (!innerCache) { innerCache = new Map(); - SourceFile._specifierCache.set(containingFile, innerCache); + specifierCache.set(containingFile, innerCache); } innerCache.set(moduleSpecifier, this); } @@ -112,14 +117,14 @@ export class SourceFile { importedFiles, referencedFiles, libReferenceDirectives, - typeReferenceDirectives + typeReferenceDirectives, } = preProcessedFileInfo; const typeDirectives = parseTypeDirectives(this.sourceCode); if (typeDirectives) { for (const importedFile of importedFiles) { files.push([ importedFile.fileName, - getMappedModuleName(importedFile, typeDirectives) + getMappedModuleName(importedFile, typeDirectives), ]); } } else if ( @@ -145,18 +150,11 @@ export class SourceFile { return files; } - private static _moduleCache: Map = new Map(); - - private static _specifierCache: Map< - string, - Map - > = new Map(); - static getUrl( moduleSpecifier: string, containingFile: string ): string | undefined { - const containingCache = this._specifierCache.get(containingFile); + const containingCache = specifierCache.get(containingFile); if (containingCache) { const sourceFile = containingCache.get(moduleSpecifier); return sourceFile && sourceFile.url; @@ -165,10 +163,10 @@ export class SourceFile { } static get(url: string): SourceFile | undefined { - return this._moduleCache.get(url); + return moduleCache.get(url); } static has(url: string): boolean { - return this._moduleCache.has(url); + return moduleCache.has(url); } } diff --git a/cli/js/compiler/type_directives.ts b/cli/js/compiler/type_directives.ts index 299532f9836666..5f33f4b3320631 100644 --- a/cli/js/compiler/type_directives.ts +++ b/cli/js/compiler/type_directives.ts @@ -39,7 +39,7 @@ export function parseTypeDirectives( directives.push({ fileName, pos, - end: pos + matchString.length + end: pos + matchString.length, }); } if (!directives.length) { @@ -60,7 +60,7 @@ export function parseTypeDirectives( const target: FileReference = { fileName: targetFileName, pos: targetPos, - end: targetPos + targetFileName.length + end: targetPos + targetFileName.length, }; results.set(target, fileName); } diff --git a/cli/js/compiler/util.ts b/cli/js/compiler/util.ts index 8acc83a2d94ca5..170dff30f107bc 100644 --- a/cli/js/compiler/util.ts +++ b/cli/js/compiler/util.ts @@ -33,7 +33,7 @@ export interface WriteFileState { export enum CompilerRequestType { Compile = 0, RuntimeCompile = 1, - RuntimeTranspile = 2 + RuntimeTranspile = 2, } export const OUT_DIR = "$deno$"; @@ -255,7 +255,7 @@ export function convertCompilerOptions( } return { options: out as ts.CompilerOptions, - files: files.length ? files : undefined + files: files.length ? files : undefined, }; } @@ -287,7 +287,7 @@ export const ignoredDiagnostics = [ // TS7016: Could not find a declaration file for module '...'. '...' // implicitly has an 'any' type. This is due to `allowJs` being off by // default but importing of a JavaScript module. - 7016 + 7016, ]; export function processConfigureResponse( diff --git a/cli/js/deno.ts b/cli/js/deno.ts index ebd64d9154a36d..09e3622b15526d 100644 --- a/cli/js/deno.ts +++ b/cli/js/deno.ts @@ -6,7 +6,7 @@ export { readAll, readAllSync, writeAll, - writeAllSync + writeAllSync, } from "./buffer.ts"; export { build, OperatingSystem, Arch } from "./build.ts"; export { chmodSync, chmod } from "./ops/fs/chmod.ts"; @@ -18,7 +18,7 @@ export { Diagnostic, DiagnosticCategory, DiagnosticItem, - DiagnosticMessageChain + DiagnosticMessageChain, } from "./diagnostics.ts"; export { chdir, cwd } from "./ops/fs/dir.ts"; export { applySourceMap, formatDiagnostics } from "./ops/errors.ts"; @@ -36,7 +36,7 @@ export { seek, seekSync, OpenOptions, - OpenMode + OpenMode, } from "./files.ts"; export { read, readSync, write, writeSync } from "./ops/io.ts"; export { FsEvent, fsEvents } from "./ops/fs_events.ts"; @@ -57,7 +57,7 @@ export { ReadSeeker, WriteSeeker, ReadWriteCloser, - ReadWriteSeeker + ReadWriteSeeker, } from "./io.ts"; export { linkSync, link } from "./ops/fs/link.ts"; export { @@ -65,21 +65,18 @@ export { makeTempDir, makeTempFileSync, makeTempFile, - MakeTempOptions + MakeTempOptions, } from "./ops/fs/make_temp.ts"; export { metrics, Metrics } from "./ops/runtime.ts"; export { mkdirSync, mkdir, MkdirOptions } from "./ops/fs/mkdir.ts"; export { - Addr, connect, listen, - recvfrom, - UDPConn, - UDPAddr, + DatagramConn, Listener, Conn, ShutdownMode, - shutdown + shutdown, } from "./net.ts"; export { dir, @@ -88,14 +85,14 @@ export { execPath, hostname, loadavg, - osRelease + osRelease, } from "./ops/os.ts"; export { permissions, PermissionName, PermissionState, PermissionStatus, - Permissions + Permissions, } from "./permissions.ts"; export { openPlugin } from "./plugins.ts"; export { kill } from "./ops/process.ts"; diff --git a/cli/js/diagnostics.ts b/cli/js/diagnostics.ts index 41a8ea8b213386..d8a3f2a3c0ca62 100644 --- a/cli/js/diagnostics.ts +++ b/cli/js/diagnostics.ts @@ -10,7 +10,7 @@ export enum DiagnosticCategory { Info = 2, Error = 3, Warning = 4, - Suggestion = 5 + Suggestion = 5, } export interface DiagnosticMessageChain { diff --git a/cli/js/diagnostics_util.ts b/cli/js/diagnostics_util.ts index 24a8936789cd0d..17e73e377da212 100644 --- a/cli/js/diagnostics_util.ts +++ b/cli/js/diagnostics_util.ts @@ -7,7 +7,7 @@ import { Diagnostic, DiagnosticCategory, DiagnosticMessageChain, - DiagnosticItem + DiagnosticItem, } from "./diagnostics.ts"; interface SourceInformation { @@ -45,7 +45,7 @@ function getSourceInformation( const scriptResourceName = sourceFile.fileName; const { line: lineNumber, - character: startColumn + character: startColumn, } = sourceFile.getLineAndCharacterOfPosition(start); const endPosition = sourceFile.getLineAndCharacterOfPosition(start + length); const endColumn = @@ -67,7 +67,7 @@ function getSourceInformation( lineNumber, scriptResourceName, startColumn, - endColumn + endColumn, }; } @@ -83,7 +83,7 @@ function fromDiagnosticMessageChain( message, code, category: fromDiagnosticCategory(category), - next: fromDiagnosticMessageChain(next) + next: fromDiagnosticMessageChain(next), }; }); } @@ -97,7 +97,7 @@ function parseDiagnostic( code, file, start: startPosition, - length + length, } = item; const sourceInfo = file && startPosition && length @@ -122,7 +122,7 @@ function parseDiagnostic( code, category, startPosition, - endPosition + endPosition, }; return sourceInfo ? { ...base, ...sourceInfo } : base; diff --git a/cli/js/error_stack.ts b/cli/js/error_stack.ts index 6ec8752e6eef40..97e9f68deb6865 100644 --- a/cli/js/error_stack.ts +++ b/cli/js/error_stack.ts @@ -54,7 +54,7 @@ function patchCallSite(callSite: CallSite, location: Location): CallSite { }, getPromiseIndex(): number | null { return callSite.getPromiseIndex(); - } + }, }; } @@ -181,7 +181,7 @@ function prepareStackTrace( applySourceMap({ filename, line, - column + column, }) ); } diff --git a/cli/js/errors.ts b/cli/js/errors.ts index 6aced228a3f3b3..fc402132153ced 100644 --- a/cli/js/errors.ts +++ b/cli/js/errors.ts @@ -22,7 +22,7 @@ export enum ErrorKind { Http = 19, URIError = 20, TypeError = 21, - Other = 22 + Other = 22, } export function getErrorClass(kind: ErrorKind): { new (msg: string): Error } { @@ -190,5 +190,5 @@ export const errors = { WriteZero: WriteZero, UnexpectedEof: UnexpectedEof, BadResource: BadResource, - Http: Http + Http: Http, }; diff --git a/cli/js/file_info.ts b/cli/js/file_info.ts index 986de8206db39d..6e16583a71e7e0 100644 --- a/cli/js/file_info.ts +++ b/cli/js/file_info.ts @@ -55,26 +55,19 @@ export class FileInfoImpl implements FileInfo { blocks: number | null; /* @internal */ - constructor(private _res: StatResponse) { + constructor(res: StatResponse) { const isUnix = build.os === "mac" || build.os === "linux"; - const modified = this._res.modified; - const accessed = this._res.accessed; - const created = this._res.created; - const name = this._res.name; + const modified = res.modified; + const accessed = res.accessed; + const created = res.created; + const name = res.name; // Unix only - const { - dev, - ino, - mode, - nlink, - uid, - gid, - rdev, - blksize, - blocks - } = this._res; + const { dev, ino, mode, nlink, uid, gid, rdev, blksize, blocks } = res; - this.size = this._res.size; + this.#isFile = res.isFile; + this.#isDir = res.isDir; + this.#isSymlink = res.isSymlink; + this.size = res.size; this.modified = modified ? modified : null; this.accessed = accessed ? accessed : null; this.created = created ? created : null; @@ -85,12 +78,12 @@ export class FileInfoImpl implements FileInfo { this.mode = isUnix ? mode & 0o7777 : null; this.type = isUnix ? mode & ~0o7777 - : this._res.isFile + : res.isFile ? FileType.TYPE_REGULAR - : this._res.isSymlink - ? FileType.TYPE_SYMLINK - : this._res.isDir + : res.isDir ? FileType.TYPE_DIRECTORY + : res.isSymlink + ? FileType.TYPE_SYMLINK : null; this.nlink = isUnix ? nlink : null; this.uid = isUnix ? uid : null; @@ -101,14 +94,14 @@ export class FileInfoImpl implements FileInfo { } isFile(): boolean { - return this.type == FileType.TYPE_REGULAR; // this._res.isFile; + return this.#isFile; } isDirectory(): boolean { - return this.type == FileType.TYPE_DIRECTORY; // this._res.isDir; + return this.#isDir; } isSymlink(): boolean { - return this.type == FileType.TYPE_SYMLINK; // this._res.isSymlink; + return this.#isSymlink; } } diff --git a/cli/js/files.ts b/cli/js/files.ts index 99ae1987971f8a..d09fcf8db56e2b 100644 --- a/cli/js/files.ts +++ b/cli/js/files.ts @@ -8,7 +8,7 @@ import { SeekMode, SyncReader, SyncWriter, - SyncSeeker + SyncSeeker, } from "./io.ts"; import { close } from "./ops/resources.ts"; import { read, readSync, write, writeSync } from "./ops/io.ts"; @@ -18,7 +18,7 @@ import { open as opOpen, openSync as opOpenSync, OpenOptions, - OpenMode + OpenMode, } from "./ops/fs/open.ts"; export { OpenOptions, OpenMode } from "./ops/fs/open.ts"; @@ -119,7 +119,7 @@ export const stdout = new File(1); export const stderr = new File(2); function checkOpenOptions(options: OpenOptions): void { - if (Object.values(options).filter(val => val === true).length === 0) { + if (Object.values(options).filter((val) => val === true).length === 0) { throw new Error("OpenOptions requires at least one option to be true"); } diff --git a/cli/js/globals.ts b/cli/js/globals.ts index ada491bde44155..87ff13b22616c7 100644 --- a/cli/js/globals.ts +++ b/cli/js/globals.ts @@ -160,7 +160,7 @@ export function writable(value: unknown): PropertyDescriptor { value, writable: true, enumerable: true, - configurable: true + configurable: true, }; } @@ -168,14 +168,22 @@ export function nonEnumerable(value: unknown): PropertyDescriptor { return { value, writable: true, - configurable: true + configurable: true, }; } export function readOnly(value: unknown): PropertyDescriptor { return { value, - enumerable: true + enumerable: true, + }; +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function getterOnly(getter: () => any): PropertyDescriptor { + return { + get: getter, + enumerable: true, }; } @@ -188,7 +196,7 @@ export const windowOrWorkerGlobalScopeMethods = { fetch: writable(fetchTypes.fetch), // queueMicrotask is bound in Rust setInterval: writable(timers.setInterval), - setTimeout: writable(timers.setTimeout) + setTimeout: writable(timers.setTimeout), }; // Other properties shared between WindowScope and WorkerGlobalScope @@ -208,7 +216,7 @@ export const windowOrWorkerGlobalScopeProperties = { Request: nonEnumerable(request.Request), Response: nonEnumerable(fetchTypes.Response), performance: writable(new performanceUtil.Performance()), - Worker: nonEnumerable(workers.WorkerImpl) + Worker: nonEnumerable(workers.WorkerImpl), }; export const eventTargetProperties = { @@ -225,5 +233,5 @@ export const eventTargetProperties = { dispatchEvent: readOnly(eventTarget.EventTarget.prototype.dispatchEvent), removeEventListener: readOnly( eventTarget.EventTarget.prototype.removeEventListener - ) + ), }; diff --git a/cli/js/internals.ts b/cli/js/internals.ts index 6aae1be489064f..174e9a0d413c58 100644 --- a/cli/js/internals.ts +++ b/cli/js/internals.ts @@ -11,6 +11,6 @@ export const internalObject: { [key: string]: any } = {}; export function exposeForTest(name: string, value: any): void { Object.defineProperty(internalObject, name, { value, - enumerable: false + enumerable: false, }); } diff --git a/cli/js/io.ts b/cli/js/io.ts index 5e0ee790356993..b5af34224a69b5 100644 --- a/cli/js/io.ts +++ b/cli/js/io.ts @@ -11,7 +11,7 @@ export type EOF = typeof EOF; export enum SeekMode { SEEK_START = 0, SEEK_CURRENT = 1, - SEEK_END = 2 + SEEK_END = 2, } // Reader is the interface that wraps the basic read() method. @@ -99,8 +99,8 @@ export function toAsyncIterator(r: Reader): AsyncIterableIterator { return { value: b.subarray(0, result), - done: false + done: false, }; - } + }, }; } diff --git a/cli/js/lib.deno.ns.d.ts b/cli/js/lib.deno.ns.d.ts index acbd5e6504e744..9c1c9aab086320 100644 --- a/cli/js/lib.deno.ns.d.ts +++ b/cli/js/lib.deno.ns.d.ts @@ -134,9 +134,11 @@ declare namespace Deno { */ export function loadavg(): number[]; - /** Get the `hostname`. Requires `allow-env` permission. + /** Get the `hostname` of the machine the Deno process is running on. * * console.log(Deno.hostname()); + * + * Requires `allow-env` permission. */ export function hostname(): string; @@ -146,34 +148,35 @@ declare namespace Deno { */ export function osRelease(): string; - /** Exit the Deno process with optional exit code. */ + /** Exit the Deno process with optional exit code. If no exit code is supplied + * then Deno will exit with return code of 0. + * + * Deno.exit(5); + */ export function exit(code?: number): never; - /** Returns a snapshot of the environment variables at invocation. Mutating a - * property in the object will set that variable in the environment for the - * process. The environment object will only accept `string`s as values. + /** Without any parameters, this will return a snapshot of the environment + * variables at invocation. Changing a property in the object will set that + * variable in the environment for the process. The environment object will + * only accept `string`s as values. + * + * Passing in a `string` key parameter will return the value for that environment + * variable, or undefined if that key doesn't exist. * * const myEnv = Deno.env(); * console.log(myEnv.SHELL); * myEnv.TEST_VAR = "HELLO"; * const newEnv = Deno.env(); - * console.log(myEnv.TEST_VAR == newEnv.TEST_VAR); + * console.log(myEnv.TEST_VAR === newEnv.TEST_VAR); //outputs "true" + * console.log(Deno.env("TEST_VAR")); //outputs "HELLO" + * console.log(Deno.env("MADE_UP_VAR")); //outputs "Undefined" * * Requires `allow-env` permission. */ export function env(): { [index: string]: string; }; - /** Returns the value of an environment variable at invocation. If the - * variable is not present, `undefined` will be returned. - * - * const myEnv = Deno.env(); - * console.log(myEnv.SHELL); - * myEnv.TEST_VAR = "HELLO"; - * const newEnv = Deno.env(); - * console.log(myEnv.TEST_VAR == newEnv.TEST_VAR); - * - * Requires `allow-env` permission. */ + /** See overloaded parent function Deno.env() */ export function env(key: string): string | undefined; /** **UNSTABLE** */ @@ -195,12 +198,14 @@ declare namespace Deno { | "tmp" | "video"; - // TODO(ry) markdown in jsdoc broken https://deno.land/typedoc/index.html#dir /** - * **UNSTABLE**: Might rename method `dir` and type alias `DirKind`. + * **UNSTABLE**: Currently under evaluation to decide if method name `dir` and + * parameter type alias name `DirKind` should be renamed. * * Returns the user and platform specific directories. * + * const homeDirectory = Deno.dir("home"); + * * Requires `allow-env` permission. * * Returns `null` if there is no applicable directory or if any other error @@ -210,6 +215,14 @@ declare namespace Deno { * `"data_local"`, `"audio"`, `"desktop"`, `"document"`, `"download"`, * `"font"`, `"picture"`, `"public"`, `"template"`, `"tmp"`, `"video"` * + * `"home"` + * + * |Platform | Value | Example | + * | ------- | -----------------------------------------| -----------------------| + * | Linux | `$HOME` | /home/alice | + * | macOS | `$HOME` | /Users/alice | + * | Windows | `{FOLDERID_Profile}` | C:\Users\Alice | + * * `"cache"` * * |Platform | Value | Example | @@ -336,20 +349,23 @@ declare namespace Deno { /** * Returns the path to the current deno executable. * + * console.log(Deno.execPath()); //e.g. "/home/alice/.local/bin/deno" + * * Requires `allow-env` permission. */ export function execPath(): string; - // @url js/dir.d.ts - /** - * **UNSTABLE**: maybe needs permissions. + * **UNSTABLE**: Currently under evaluation to decide if explicit permission is + * required to get the value of the current working directory. * * Return a string representing the current working directory. * * If the current directory can be reached via multiple paths (due to symbolic * links), `cwd()` may return any one of them. * + * const currentWorkingDirectory = Deno.cwd(); + * * Throws `Deno.errors.NotFound` if directory not available. */ export function cwd(): string; @@ -382,8 +398,6 @@ declare namespace Deno { export const EOF: unique symbol; export type EOF = typeof EOF; - // @url js/io.d.ts - /** **UNSTABLE**: might remove `"SEEK_"` prefix. Might not use all-caps. */ export enum SeekMode { SEEK_START = 0, @@ -505,8 +519,16 @@ declare namespace Deno { * error occurs. It resolves to the number of bytes copied or rejects with * the first error encountered while copying. * + * const source = await Deno.open("my_file.txt"); + * const buffer = new Deno.Buffer() + * const bytesCopied1 = await Deno.copy(Deno.stdout, source); + * const bytesCopied2 = await Deno.copy(buffer, source); + * * Because `copy()` is defined to read from `src` until `EOF`, it does not * treat an `EOF` from `read()` as an error to be reported. + * + * @param dst The destination to copy to + * @param src The source to copy from */ export function copy(dst: Writer, src: Reader): Promise; @@ -518,8 +540,6 @@ declare namespace Deno { */ export function toAsyncIterator(r: Reader): AsyncIterableIterator; - // @url js/files.d.ts - /** Synchronously open a file and return an instance of the `File` object. * * const file = Deno.openSync("/foo/bar.txt", { read: true, write: true }); @@ -636,7 +656,14 @@ declare namespace Deno { whence: SeekMode ): Promise; - /** Close the given resource ID. */ + /** Close the given resource ID (rid) which has been previously opened, such + * as via opening or creating a file. Closing a file when you are finished + * with it is important to avoid leaking resources. + * + * const file = await Deno.open("my_file.txt"); + * // do work with "file" object + * Deno.close(file.rid); + */ export function close(rid: number): void; /** The Deno abstraction for reading and writing files. */ @@ -716,30 +743,29 @@ declare namespace Deno { */ export type OpenMode = "r" | "r+" | "w" | "w+" | "a" | "a+" | "x" | "x+"; - // @url js/tty.d.ts - - /** **UNSTABLE**: newly added API + /** **UNSTABLE**: new API, yet to be vetted + * + * Check if a given resource id (`rid`) is a TTY. * - * Check if a given resource is TTY. */ + * //This example is system and context specific + * const nonTTYRid = Deno.openSync("my_file.txt").rid; + * const ttyRid = Deno.openSync("/dev/tty6").rid; + * console.log(Deno.isatty(nonTTYRid)); // false + * console.log(Deno.isatty(ttyRid)); // true + * Deno.close(nonTTYRid); + * Deno.close(ttyRid); + */ export function isatty(rid: number): boolean; - /** **UNSTABLE**: newly added API + /** **UNSTABLE**: new API, yet to be vetted * * Set TTY to be under raw mode or not. */ export function setRaw(rid: number, mode: boolean): void; - // @url js/buffer.d.ts - /** A variable-sized buffer of bytes with `read()` and `write()` methods. * * Based on [Go Buffer](https://golang.org/pkg/bytes/#Buffer). */ export class Buffer implements Reader, SyncReader, Writer, SyncWriter { - private buf; - private off; - private _tryGrowByReslice; - private _reslice; - private _grow; - constructor(ab?: ArrayBuffer); /** Returns a slice holding the unread portion of the buffer. * @@ -816,8 +842,6 @@ declare namespace Deno { /** Synchronously write all the content of `arr` to `w`. */ export function writeAllSync(w: SyncWriter, arr: Uint8Array): void; - // @url js/mkdir.d.ts - export interface MkdirOptions { /** Defaults to `false`. If set to `true`, means that any intermediate * directories will also be created (as with the shell command `mkdir -p`). @@ -861,8 +885,6 @@ declare namespace Deno { mode?: number ): Promise; - // @url js/make_temp.d.ts - export interface MakeTempOptions { /** Directory where the temporary directory should be created (defaults to * the env variable TMPDIR, or the system's default, usually /tmp). */ @@ -941,8 +963,6 @@ declare namespace Deno { * Requires `allow-write` permission. */ export function makeTempFile(options?: MakeTempOptions): Promise; - // @url js/chmod.d.ts - /** Synchronously changes the permission of a specific file/directory of * specified path. Ignores the process's umask. * @@ -983,32 +1003,36 @@ declare namespace Deno { * Requires `allow-write` permission. */ export function chmod(path: string, mode: number): Promise; - // @url js/chown.d.ts - - /** Synchronously change owner of a regular file or directory. Linux/Mac OS - * only at the moment. + /** Synchronously change owner of a regular file or directory. This functionality + * is not available on Windows. + * + * Deno.chownSync("myFile.txt", 1000, 1002); * * Requires `allow-write` permission. * + * Throws Error (not implemented) if executed on Windows + * * @param path path to the file - * @param uid user id of the new owner - * @param gid group id of the new owner + * @param uid user id (UID) of the new owner + * @param gid group id (GID) of the new owner */ export function chownSync(path: string, uid: number, gid: number): void; - /** Change owner of a regular file or directory. Linux/Mac OS only at the - * moment. + /** Change owner of a regular file or directory. This functionality + * is not available on Windows. + * + * await Deno.chown("myFile.txt", 1000, 1002); * * Requires `allow-write` permission. * + * Throws Error (not implemented) if executed on Windows + * * @param path path to the file - * @param uid user id of the new owner - * @param gid group id of the new owner + * @param uid user id (UID) of the new owner + * @param gid group id (GID) of the new owner */ export function chown(path: string, uid: number, gid: number): Promise; - // @url js/utime.d.ts - /** **UNSTABLE**: needs investigation into high precision time. * * Synchronously changes the access and modification times of a file system @@ -1039,8 +1063,6 @@ declare namespace Deno { mtime: number | Date ): Promise; - // @url js/remove.d.ts - export interface RemoveOptions { /** Defaults to `false`. If set to `true`, path will be removed even if * it's a non-empty directory. */ @@ -1065,8 +1087,6 @@ declare namespace Deno { * Requires `allow-write` permission. */ export function remove(path: string, options?: RemoveOptions): Promise; - // @url js/rename.d.ts - /** Synchronously renames (moves) `oldpath` to `newpath`. If `newpath` already * exists and is not a directory, `renameSync()` replaces it. OS-specific * restrictions may apply when `oldpath` and `newpath` are in different @@ -1086,8 +1106,6 @@ declare namespace Deno { * Requires `allow-read` and `allow-write`. */ export function rename(oldpath: string, newpath: string): Promise; - // @url js/read_file.d.ts - /** Reads and returns the entire contents of a file. * * const decoder = new TextDecoder("utf-8"); @@ -1106,8 +1124,6 @@ declare namespace Deno { * Requires `allow-read` permission. */ export function readFile(path: string): Promise; - // @url js/file_info.d.ts - /** A FileInfo describes a file and is returned by `stat`, `lstat`, * `statSync`, `lstatSync`. A list of FileInfo is returned by `readdir`, * `readdirSync`. */ @@ -1190,8 +1206,6 @@ declare namespace Deno { TYPE_SOCKET = 12 << 12 } - // @url js/realpath.d.ts - /** Returns absolute normalized path with, symbolic links resolved. * * const realPath = Deno.realpathSync("./some/path"); @@ -1206,8 +1220,6 @@ declare namespace Deno { * Requires `allow-read` permission. */ export function realpath(path: string): Promise; - // @url js/read_dir.d.ts - /** UNSTABLE: need to consider streaming case * * Synchronously reads the directory given by `path` and returns an array of @@ -1227,8 +1239,6 @@ declare namespace Deno { * Requires `allow-read` permission. */ export function readdir(path: string): Promise; - // @url js/copy_file.d.ts - /** Synchronously copies the contents and permissions of one file to another * specified path, by default creating a new file if needed, else overwriting. * Fails if target path is a directory or is unwritable. @@ -1249,8 +1259,6 @@ declare namespace Deno { * Requires `allow-write` permission on toPath. */ export function copyFile(fromPath: string, toPath: string): Promise; - // @url js/read_link.d.ts - /** Returns the destination of the named symbolic link. * * const targetPath = Deno.readlinkSync("symlink/path"); @@ -1265,8 +1273,6 @@ declare namespace Deno { * Requires `allow-read` permission. */ export function readlink(path: string): Promise; - // @url js/stat.d.ts - /** Resolves to a `Deno.FileInfo` for the specified `path`. If `path` is a * symlink, information for the symlink will be returned. * @@ -1303,8 +1309,6 @@ declare namespace Deno { * Requires `allow-read` permission. */ export function statSync(path: string): FileInfo; - // @url js/link.d.ts - /** Creates `newpath` as a hard link to `oldpath`. * * Deno.linkSync("old/name", "new/name"); @@ -1319,8 +1323,6 @@ declare namespace Deno { * Requires `allow-read` and `allow-write` permissions. */ export function link(oldpath: string, newpath: string): Promise; - // @url js/symlink.d.ts - /** **UNSTABLE**: `type` argument type may be changed to `"dir" | "file"`. * * Creates `newpath` as a symbolic link to `oldpath`. The type argument can be @@ -1351,8 +1353,6 @@ declare namespace Deno { type?: string ): Promise; - // @url js/write_file.d.ts - /** Options for writing to a file. */ export interface WriteFileOptions { /** Defaults to `false`. If set to `true`, will append to a file instead of @@ -1547,8 +1547,6 @@ declare namespace Deno { constructor(state: PermissionState); } - // @url js/truncate.d.ts - /** Synchronously truncates or extends the specified file, to reach the * specified `len`. * @@ -1593,21 +1591,18 @@ declare namespace Deno { * * Requires `allow-plugin` permission. */ export function openPlugin(filename: string): Plugin; - - export type Transport = "tcp" | "udp"; - - export interface Addr { - transport: Transport; + export interface NetAddr { + transport: "tcp" | "udp"; hostname: string; port: number; } - export interface UDPAddr { - port: number; - transport?: Transport; - hostname?: string; + export interface UnixAddr { + transport: "unix" | "unixpacket"; + address: string; } + export type Addr = NetAddr | UnixAddr; /** **UNSTABLE**: Maybe remove `ShutdownMode` entirely. * * Corresponds to `SHUT_RD`, `SHUT_WR`, `SHUT_RDWR` on POSIX-like systems. @@ -1632,18 +1627,10 @@ declare namespace Deno { */ export function shutdown(rid: number, how: ShutdownMode): void; - /** **UNSTABLE**: new API, yet to be vetted. - * - * Waits for the next message to the passed `rid` and writes it on the passed - * `Uint8Array`. - * - * Resolves to the number of bytes written and the remote address. */ - export function recvfrom(rid: number, p: Uint8Array): Promise<[number, Addr]>; - /** **UNSTABLE**: new API, yet to be vetted. * * A generic transport listener for message-oriented protocols. */ - export interface UDPConn extends AsyncIterable<[Uint8Array, Addr]> { + export interface DatagramConn extends AsyncIterable<[Uint8Array, Addr]> { /** **UNSTABLE**: new API, yet to be vetted. * * Waits for and resolves to the next message to the `UDPConn`. */ @@ -1651,7 +1638,7 @@ declare namespace Deno { /** UNSTABLE: new API, yet to be vetted. * * Sends a message to the target. */ - send(p: Uint8Array, addr: UDPAddr): Promise; + send(p: Uint8Array, addr: Addr): Promise; /** UNSTABLE: new API, yet to be vetted. * * Close closes the socket. Any pending message promises will be rejected @@ -1671,6 +1658,7 @@ declare namespace Deno { close(): void; /** Return the address of the `Listener`. */ readonly addr: Addr; + [Symbol.asyncIterator](): AsyncIterator; } @@ -1695,13 +1683,12 @@ declare namespace Deno { /** A literal IP address or host name that can be resolved to an IP address. * If not specified, defaults to `0.0.0.0`. */ hostname?: string; - /** Either `"tcp"` or `"udp"`. Defaults to `"tcp"`. - * - * In the future: `"tcp4"`, `"tcp6"`, `"udp4"`, `"udp6"`, `"ip"`, `"ip4"`, - * `"ip6"`, `"unix"`, `"unixgram"`, and `"unixpacket"`. */ - transport?: Transport; } + export interface UnixListenOptions { + /** A Path to the Unix Socket. */ + address: string; + } /** **UNSTABLE**: new API * * Listen announces on the local transport address. @@ -1719,32 +1706,41 @@ declare namespace Deno { * * Listen announces on the local transport address. * - * Deno.listen({ port: 80 }) - * Deno.listen({ hostname: "192.0.2.1", port: 80 }) - * Deno.listen({ hostname: "[2001:db8::1]", port: 80 }); - * Deno.listen({ hostname: "golang.org", port: 80, transport: "tcp" }); + * Deno.listen({ address: "/foo/bar.sock", transport: "unix" }) + * + * Requires `allow-read` permission. */ + export function listen( + options: UnixListenOptions & { transport: "unix" } + ): Listener; + /** **UNSTABLE**: new API + * + * Listen announces on the local transport address. + * + * Deno.listen({ port: 80, transport: "udp" }) + * Deno.listen({ hostname: "golang.org", port: 80, transport: "udp" }); * * Requires `allow-net` permission. */ export function listen( options: ListenOptions & { transport: "udp" } - ): UDPConn; + ): DatagramConn; /** **UNSTABLE**: new API * * Listen announces on the local transport address. * - * Deno.listen({ port: 80 }) - * Deno.listen({ hostname: "192.0.2.1", port: 80 }) - * Deno.listen({ hostname: "[2001:db8::1]", port: 80 }); - * Deno.listen({ hostname: "golang.org", port: 80, transport: "tcp" }); + * Deno.listen({ address: "/foo/bar.sock", transport: "unixpacket" }) * - * Requires `allow-net` permission. */ - export function listen(options: ListenOptions): Listener | UDPConn; + * Requires `allow-read` permission. */ + export function listen( + options: UnixListenOptions & { transport: "unixpacket" } + ): DatagramConn; export interface ListenTLSOptions extends ListenOptions { /** Server certificate file. */ certFile: string; /** Server public key file. */ keyFile: string; + + transport?: "tcp"; } /** Listen announces on the local transport address over TLS (transport layer @@ -1761,23 +1757,28 @@ declare namespace Deno { /** A literal IP address or host name that can be resolved to an IP address. * If not specified, defaults to `127.0.0.1`. */ hostname?: string; - /** Either `"tcp"` or `"udp"`. Defaults to `"tcp"`. - * - * In the future: `"tcp4"`, `"tcp6"`, `"udp4"`, `"udp6"`, `"ip"`, `"ip4"`, - * `"ip6"`, `"unix"`, `"unixgram"`, and `"unixpacket"`. */ - transport?: Transport; + transport?: "tcp"; + } + + export interface UnixConnectOptions { + transport: "unix"; + address: string; } /** - * Connects to the address on the named transport. + * Connects to the hostname (default is "127.0.0.1") and port on the named + * transport (default is "tcp"). * - * Deno.connect({ port: 80 }) - * Deno.connect({ hostname: "192.0.2.1", port: 80 }) - * Deno.connect({ hostname: "[2001:db8::1]", port: 80 }); - * Deno.connect({ hostname: "golang.org", port: 80, transport: "tcp" }) + * const conn1 = await Deno.connect({ port: 80 }); + * const conn2 = await Deno.connect({ hostname: "192.0.2.1", port: 80 }); + * const conn3 = await Deno.connect({ hostname: "[2001:db8::1]", port: 80 }); + * const conn4 = await Deno.connect({ hostname: "golang.org", port: 80, transport: "tcp" }); + * const conn5 = await Deno.connect({ address: "/foo/bar.sock", transport: "unix" }); * - * Requires `allow-net` permission. */ - export function connect(options: ConnectOptions): Promise; + * Requires `allow-net` permission for "tcp" and `allow-read` for unix. */ + export function connect( + options: ConnectOptions | UnixConnectOptions + ): Promise; export interface ConnectTLSOptions { /** The port to connect to. */ @@ -1789,9 +1790,18 @@ declare namespace Deno { certFile?: string; } - /** Establishes a secure connection over TLS (transport layer security). + /** Establishes a secure connection over TLS (transport layer security) using + * an optional cert file, hostname (default is "127.0.0.1") and port. The + * cert file is optional and if not included Mozilla's root certificates will + * be used (see also https://github.com/ctz/webpki-roots for specifics) * - * Requires `allow-net` permission. */ + * const conn1 = await Deno.connectTLS({ port: 80 }); + * const conn2 = await Deno.connectTLS({ certFile: "./certs/my_custom_root_CA.pem", hostname: "192.0.2.1", port: 80 }); + * const conn3 = await Deno.connectTLS({ hostname: "[2001:db8::1]", port: 80 }); + * const conn4 = await Deno.connectTLS({ certFile: "./certs/my_custom_root_CA.pem", hostname: "golang.org", port: 80}); + * + * Requires `allow-net` permission. + */ export function connectTLS(options: ConnectTLSOptions): Promise; /** **UNSTABLE**: not sure if broken or not */ @@ -1849,9 +1859,23 @@ declare namespace Deno { paths: string[]; } - /** **UNSTABLE**: new API. Needs docs. + /** **UNSTABLE**: new API, yet to be vetted. + * + * Watch for file system events against one or more `paths`, which can be files + * or directories. These paths must exist already. One user action (e.g. + * `touch test.file`) can generate multiple file system events. Likewise, + * one user action can result in multiple file paths in one event (e.g. `mv + * old_name.txt new_name.txt`). Recursive option is `true` by default and, + * for directories, will watch the specified directory and all sub directories. + * Note that the exact ordering of the events can vary between operating systems. + * + * const iter = Deno.fsEvents("/"); + * for await (const event of iter) { + * console.log(">>>> event", event); //e.g. { kind: "create", paths: [ "/foo.txt" ] } + * } * - * Recursive option is `true` by default. */ + * Requires `allow-read` permission. + */ export function fsEvents( paths: string | string[], options?: { recursive: boolean } @@ -1869,15 +1893,22 @@ declare namespace Deno { * the stream to `/dev/null`. */ type ProcessStdio = "inherit" | "piped" | "null"; - /** **UNSTABLE**: the `signo` argument maybe shouldn't be number. Should throw - * on Windows instead of silently succeeding. + /** **UNSTABLE**: The `signo` argument may change to require the Deno.Signal + * enum. * - * Send a signal to process under given `pid`. Linux/Mac OS only currently. + * Send a signal to process under given `pid`. This functionality currently + * only works on Linux and Mac OS. * * If `pid` is negative, the signal will be sent to the process group * identified by `pid`. * - * Currently no-op on Windows. + * const p = Deno.run({ + * cmd: ["python", "-c", "from time import sleep; sleep(10000)"] + * }); + * + * Deno.kill(p.pid, Deno.Signal.SIGINT); + * + * Throws Error (not yet implemented) on Windows * * Requires `allow-run` permission. */ export function kill(pid: number, signo: number): void; @@ -1914,12 +1945,12 @@ declare namespace Deno { signal?: number; } - /** **UNSTABLE**: Maybe rename `args` to `argv` to differentiate from + /** **UNSTABLE**: `args` has been recently renamed to `cmd` to differentiate from * `Deno.args`. */ export interface RunOptions { /** Arguments to pass. Note, the first element needs to be a path to the * binary */ - args: string[]; + cmd: string[]; cwd?: string; env?: { [key: string]: string; @@ -2016,20 +2047,45 @@ declare namespace Deno { * Signals numbers. This is platform dependent. */ export const Signal: typeof MacOSSignal | typeof LinuxSignal; - /** **UNSTABLE**: rename to `InspectOptions`. */ - interface ConsoleOptions { + interface InspectOptions { showHidden?: boolean; depth?: number; colors?: boolean; indentLevel?: number; } - /** **UNSTABLE**: `ConsoleOptions` rename to `InspectOptions`. Also the exact - * form of string output subject to change. + /** **UNSTABLE**: The exact form of the string output is under consideration + * and may change. + * + * Converts the input into a string that has the same format as printed by + * `console.log()`. + * + * const obj = {}; + * obj.propA = 10; + * obj.propB = "hello" + * const objAsString = Deno.inspect(obj); //{ propA: 10, propB: "hello" } + * console.log(obj); //prints same value as objAsString, e.g. { propA: 10, propB: "hello" } + * + * You can also register custom inspect functions, via the `customInspect` Deno + * symbol on objects, to control and customize the output. + * + * class A { + * x = 10; + * y = "hello"; + * [Deno.symbols.customInspect](): string { + * return "x=" + this.x + ", y=" + this.y; + * } + * } + * + * const inStringFormat = Deno.inspect(new A()); //"x=10, y=hello" + * console.log(inStringFormat); //prints "x=10, y=hello" * - * Converts input into string that has the same format as printed by - * `console.log()`. */ - export function inspect(value: unknown, options?: ConsoleOptions): string; + * Finally, a number of output options are also available. + * + * const out = Deno.inspect(obj, {showHidden: true, depth: 4, colors: true, indentLevel: 2}); + * + */ + export function inspect(value: unknown, options?: InspectOptions): string; export type OperatingSystem = "mac" | "win" | "linux"; @@ -2105,7 +2161,13 @@ declare namespace Deno { /** **UNSTABLE**: new API, yet to be vetted. * - * Format an array of diagnostic items and return them as a single string. + * Format an array of diagnostic items and return them as a single string in a + * user friendly format. + * + * const [diagnostics, result] = Deno.compile("file_with_compile_issues.ts"); + * console.table(diagnostics); //Prints raw diagnostic data + * console.log(Deno.formatDiagnostics(diagnostics)); //User friendly output of diagnostics + * * @param items An array of diagnostic items to format */ export function formatDiagnostics(items: DiagnosticItem[]): string; @@ -2351,8 +2413,9 @@ declare namespace Deno { /** **UNSTABLE**: new API, yet to be vetted. * - * Takes a root module name, any optionally a record set of sources. Resolves - * with a compiled set of modules. If just a root name is provided, the modules + * Takes a root module name, and optionally a record set of sources. Resolves + * with a compiled set of modules and possibly diagnostics if the compiler + * encountered any issues. If just a root name is provided, the modules * will be resolved as if the root module had been passed on the command line. * * If sources are passed, all modules will be resolved out of this object, where diff --git a/cli/js/lib.deno.shared_globals.d.ts b/cli/js/lib.deno.shared_globals.d.ts index ea8bf08ecc18e9..565121beab6954 100644 --- a/cli/js/lib.deno.shared_globals.d.ts +++ b/cli/js/lib.deno.shared_globals.d.ts @@ -18,8 +18,8 @@ declare interface WindowOrWorkerGlobalScope { clearInterval: typeof __timers.clearInterval; clearTimeout: typeof __timers.clearTimeout; fetch: typeof __fetch.fetch; - queueMicrotask: (task: () => void) => void; setInterval: typeof __timers.setInterval; + queueMicrotask: typeof __timers.queueMicrotask; setTimeout: typeof __timers.setTimeout; // properties console: __console.Console; @@ -232,6 +232,7 @@ declare const clearTimeout: typeof __timers.clearTimeout; declare const fetch: typeof __fetch.fetch; declare const setInterval: typeof __timers.setInterval; declare const setTimeout: typeof __timers.setTimeout; +declare const queueMicrotask: typeof __timers.queueMicrotask; declare const console: __console.Console; declare const Blob: typeof __blob.DenoBlob; @@ -291,8 +292,6 @@ declare interface ImportMeta { } declare namespace __domTypes { - // @url js/dom_types.d.ts - export type BufferSource = ArrayBufferView | ArrayBuffer; export type HeadersInit = | Headers @@ -340,12 +339,8 @@ declare namespace __domTypes { export enum NodeType { ELEMENT_NODE = 1, TEXT_NODE = 3, - DOCUMENT_FRAGMENT_NODE = 11 + DOCUMENT_FRAGMENT_NODE = 11, } - export const eventTargetHost: unique symbol; - export const eventTargetListeners: unique symbol; - export const eventTargetMode: unique symbol; - export const eventTargetNodeType: unique symbol; export interface EventListener { (evt: Event): void | Promise; } @@ -359,11 +354,11 @@ declare namespace __domTypes { callback: EventListenerOrEventListenerObject; options: AddEventListenerOptions; } + export const eventTargetHost: unique symbol; + export const eventTargetListeners: unique symbol; + export const eventTargetMode: unique symbol; + export const eventTargetNodeType: unique symbol; export interface EventTarget { - [eventTargetHost]: EventTarget | null; - [eventTargetListeners]: { [type in string]: EventListener[] }; - [eventTargetMode]: string; - [eventTargetNodeType]: NodeType; addEventListener( type: string, callback: EventListenerOrEventListenerObject | null, @@ -439,7 +434,7 @@ declare namespace __domTypes { NONE = 0, CAPTURING_PHASE = 1, AT_TARGET = 2, - BUBBLING_PHASE = 3 + BUBBLING_PHASE = 3, } export interface EventPath { item: EventTarget; @@ -533,17 +528,79 @@ declare namespace __domTypes { options?: boolean | EventListenerOptions ): void; } - export interface ReadableStream { + export interface ReadableStreamReadDoneResult { + done: true; + value?: T; + } + export interface ReadableStreamReadValueResult { + done: false; + value: T; + } + export type ReadableStreamReadResult = + | ReadableStreamReadValueResult + | ReadableStreamReadDoneResult; + export interface ReadableStreamDefaultReader { + readonly closed: Promise; + cancel(reason?: any): Promise; + read(): Promise>; + releaseLock(): void; + } + export interface PipeOptions { + preventAbort?: boolean; + preventCancel?: boolean; + preventClose?: boolean; + signal?: AbortSignal; + } + /** This Streams API interface represents a readable stream of byte data. The + * Fetch API offers a concrete instance of a ReadableStream through the body + * property of a Response object. */ + export interface ReadableStream { readonly locked: boolean; - cancel(): Promise; - getReader(): ReadableStreamReader; - tee(): [ReadableStream, ReadableStream]; + cancel(reason?: any): Promise; + getReader(options: { mode: "byob" }): ReadableStreamBYOBReader; + getReader(): ReadableStreamDefaultReader; + /* disabled for now + pipeThrough( + { + writable, + readable + }: { + writable: WritableStream; + readable: ReadableStream; + }, + options?: PipeOptions + ): ReadableStream; + pipeTo(dest: WritableStream, options?: PipeOptions): Promise; + */ + tee(): [ReadableStream, ReadableStream]; + } + export interface ReadableStreamReader { + cancel(reason: any): Promise; + read(): Promise>; + releaseLock(): void; } - export interface ReadableStreamReader { - cancel(): Promise; - read(): Promise; + export interface ReadableStreamBYOBReader { + readonly closed: Promise; + cancel(reason?: any): Promise; + read( + view: T + ): Promise>; releaseLock(): void; } + export interface WritableStream { + readonly locked: boolean; + abort(reason?: any): Promise; + getWriter(): WritableStreamDefaultWriter; + } + export interface WritableStreamDefaultWriter { + readonly closed: Promise; + readonly desiredSize: number | null; + readonly ready: Promise; + abort(reason?: any): Promise; + close(): Promise; + releaseLock(): void; + write(chunk: W): Promise; + } export interface FormData extends DomIterable { append(name: string, value: string | Blob, fileName?: string): void; delete(name: string): void; @@ -571,7 +628,7 @@ declare namespace __domTypes { } export interface Body { /** A simple getter used to expose a `ReadableStream` of the body contents. */ - readonly body: ReadableStream | null; + readonly body: ReadableStream | null; /** Stores a `Boolean` that declares whether the body has been used in a * response yet. */ @@ -800,58 +857,63 @@ declare namespace __domTypes { /** Creates a clone of a `Response` object. */ clone(): Response; } + export interface DOMStringList { + /** Returns the number of strings in strings. */ + readonly length: number; + /** Returns true if strings contains string, and false otherwise. */ + contains(string: string): boolean; + /** Returns the string with index index from strings. */ + item(index: number): string | null; + [index: number]: string; + } + /** The location (URL) of the object it is linked to. Changes done on it are + * reflected on the object it relates to. Both the Document and Window + * interface have such a linked Location, accessible via Document.location and + * Window.location respectively. */ export interface Location { - /** - * Returns a DOMStringList object listing the origins of the ancestor browsing - * contexts, from the parent browsing context to the top-level browsing - * context. - */ - readonly ancestorOrigins: string[]; - /** - * Returns the Location object's URL's fragment (includes leading "#" if + /** Returns a DOMStringList object listing the origins of the ancestor + * browsing contexts, from the parent browsing context to the top-level + * browsing context. */ + readonly ancestorOrigins: DOMStringList; + /** Returns the Location object's URL's fragment (includes leading "#" if * non-empty). + * * Can be set, to navigate to the same URL with a changed fragment (ignores - * leading "#"). - */ + * leading "#"). */ hash: string; - /** - * Returns the Location object's URL's host and port (if different from the - * default port for the scheme). Can be set, to navigate to the same URL with - * a changed host and port. - */ + /** Returns the Location object's URL's host and port (if different from the + * default port for the scheme). + * + * Can be set, to navigate to the same URL with a changed host and port. */ host: string; - /** - * Returns the Location object's URL's host. Can be set, to navigate to the - * same URL with a changed host. - */ + /** Returns the Location object's URL's host. + * + * Can be set, to navigate to the same URL with a changed host. */ hostname: string; - /** - * Returns the Location object's URL. Can be set, to navigate to the given - * URL. - */ + /** Returns the Location object's URL. + * + * Can be set, to navigate to the given URL. */ href: string; + toString(): string; /** Returns the Location object's URL's origin. */ readonly origin: string; - /** - * Returns the Location object's URL's path. - * Can be set, to navigate to the same URL with a changed path. - */ + /** Returns the Location object's URL's path. + * + * Can be set, to navigate to the same URL with a changed path. */ pathname: string; - /** - * Returns the Location object's URL's port. - * Can be set, to navigate to the same URL with a changed port. - */ + /** Returns the Location object's URL's port. + * + * Can be set, to navigate to the same URL with a changed port. */ port: string; - /** - * Returns the Location object's URL's scheme. - * Can be set, to navigate to the same URL with a changed scheme. - */ + /** Returns the Location object's URL's scheme. + * + * Can be set, to navigate to the same URL with a changed scheme. */ protocol: string; - /** - * Returns the Location object's URL's query (includes leading "?" if - * non-empty). Can be set, to navigate to the same URL with a changed query - * (ignores leading "?"). - */ + /** Returns the Location object's URL's query (includes leading "?" if + * non-empty). + * + * Can be set, to navigate to the same URL with a changed query (ignores + * leading "?"). */ search: string; /** * Navigates to the given URL. @@ -861,23 +923,14 @@ declare namespace __domTypes { * Reloads the current page. */ reload(): void; - /** @deprecated */ - reload(forcedReload: boolean): void; - /** - * Removes the current page from the session history and navigates to the - * given URL. - */ + /** Removes the current page from the session history and navigates to the + * given URL. */ replace(url: string): void; } } declare namespace __blob { - // @url js/blob.d.ts - - export const bytesSymbol: unique symbol; - export const blobBytesWeakMap: WeakMap<__domTypes.Blob, Uint8Array>; export class DenoBlob implements __domTypes.Blob { - private readonly [bytesSymbol]; readonly size: number; readonly type: string; /** A blob object represents a file-like object of immutable, raw data. */ @@ -890,9 +943,7 @@ declare namespace __blob { } declare namespace __console { - // @url js/console.d.ts - - type ConsoleOptions = Partial<{ + type InspectOptions = Partial<{ showHidden: boolean; depth: number; colors: boolean; @@ -904,7 +955,6 @@ declare namespace __console { } const isConsoleInstance: unique symbol; export class Console { - private printFunc; indentLevel: number; [isConsoleInstance]: boolean; /** Writes the arguments to stdout */ @@ -975,12 +1025,10 @@ declare namespace __console { * `inspect()` converts input into string that has the same format * as printed by `console.log(...)`; */ - export function inspect(value: unknown, options?: ConsoleOptions): string; + export function inspect(value: unknown, options?: InspectOptions): string; } declare namespace __event { - // @url js/event.d.ts - export const eventAttributes: WeakMap; export class EventInit implements __domTypes.EventInit { bubbles: boolean; @@ -989,7 +1037,7 @@ declare namespace __event { constructor({ bubbles, cancelable, - composed + composed, }?: { bubbles?: boolean | undefined; cancelable?: boolean | undefined; @@ -1052,8 +1100,6 @@ declare namespace __event { } declare namespace __customEvent { - // @url js/custom_event.d.ts - export const customEventAttributes: WeakMap; export class CustomEventInit extends __event.EventInit implements __domTypes.CustomEventInit { @@ -1062,7 +1108,7 @@ declare namespace __customEvent { bubbles, cancelable, composed, - detail + detail, }: __domTypes.CustomEventInit); } export class CustomEvent extends __event.Event @@ -1080,8 +1126,6 @@ declare namespace __customEvent { } declare namespace __eventTarget { - // @url js/event_target.d.ts - export class EventListenerOptions implements __domTypes.EventListenerOptions { _capture: boolean; constructor({ capture }?: { capture?: boolean | undefined }); @@ -1094,7 +1138,7 @@ declare namespace __eventTarget { constructor({ capture, passive, - once + once, }?: { capture?: boolean | undefined; passive?: boolean | undefined; @@ -1134,7 +1178,7 @@ declare namespace __io { export enum SeekMode { SEEK_START = 0, SEEK_CURRENT = 1, - SEEK_END = 2 + SEEK_END = 2, } export interface Reader { /** Reads up to p.byteLength bytes into `p`. It resolves to the number @@ -1223,19 +1267,16 @@ declare namespace __io { } declare namespace __fetch { - // @url js/fetch.d.ts - class Body - implements __domTypes.Body, __domTypes.ReadableStream, __io.ReadCloser { - private rid; + implements + __domTypes.Body, + __domTypes.ReadableStream, + __io.ReadCloser { readonly contentType: string; bodyUsed: boolean; - private _bodyPromise; - private _data; readonly locked: boolean; - readonly body: null | Body; + readonly body: __domTypes.ReadableStream; constructor(rid: number, contentType: string); - private _bodyBuffer; arrayBuffer(): Promise; blob(): Promise<__domTypes.Blob>; formData(): Promise<__domTypes.FormData>; @@ -1244,7 +1285,9 @@ declare namespace __fetch { read(p: Uint8Array): Promise; close(): void; cancel(): Promise; - getReader(): __domTypes.ReadableStreamReader; + getReader(options: { mode: "byob" }): __domTypes.ReadableStreamBYOBReader; + getReader(): __domTypes.ReadableStreamDefaultReader; + getReader(): __domTypes.ReadableStreamBYOBReader; tee(): [__domTypes.ReadableStream, __domTypes.ReadableStream]; [Symbol.asyncIterator](): AsyncIterableIterator; } @@ -1285,8 +1328,6 @@ declare namespace __fetch { } declare namespace __textEncoding { - // @url js/text_encoding.d.ts - export function atob(s: string): string; /** Creates a base-64 ASCII string from the input string. */ export function btoa(s: string): string; @@ -1298,7 +1339,6 @@ declare namespace __textEncoding { ignoreBOM?: boolean; } export class TextDecoder { - private _encoding; /** Returns encoding's name, lowercased. */ readonly encoding: string; /** Returns `true` if error mode is "fatal", and `false` otherwise. */ @@ -1328,8 +1368,6 @@ declare namespace __textEncoding { } declare namespace __timers { - // @url js/timers.d.ts - export type Args = unknown[]; /** Sets a timer which executes a function once after the timer expires. */ export function setTimeout( @@ -1345,16 +1383,12 @@ declare namespace __timers { ): number; export function clearTimeout(id?: number): void; export function clearInterval(id?: number): void; + export function queueMicrotask(func: Function): void; } declare namespace __urlSearchParams { - // @url js/url_search_params.d.ts - export class URLSearchParams { - private params; - private url; constructor(init?: string | string[][] | Record); - private updateSteps; /** Appends a specified key/value pair as a new search parameter. * * searchParams.append('name', 'first'); @@ -1449,13 +1483,10 @@ declare namespace __urlSearchParams { * searchParams.toString(); */ toString(): string; - private _handleStringInitialization; - private _handleArrayInitialization; } } declare namespace __url { - // @url js/url.d.ts export interface URL { hash: string; host: string; @@ -1482,7 +1513,6 @@ declare namespace __url { } declare namespace __workers { - // @url js/workers.d.ts export interface Worker { onerror?: (e: Event) => void; onmessage?: (e: { data: any }) => void; @@ -1495,22 +1525,16 @@ declare namespace __workers { name?: string; } export class WorkerImpl implements Worker { - private readonly id; - private isClosing; - private readonly isClosedPromise; onerror?: (e: Event) => void; onmessage?: (data: any) => void; onmessageerror?: () => void; constructor(specifier: string, options?: WorkerOptions); postMessage(data: any): void; terminate(): void; - private run; } } declare namespace __performanceUtil { - // @url js/performance.d.ts - export class Performance { /** Returns a current time from Deno's start in milliseconds. * diff --git a/cli/js/lib.deno.window.d.ts b/cli/js/lib.deno.window.d.ts index 737971d942641d..e4ab6b70dce766 100644 --- a/cli/js/lib.deno.window.d.ts +++ b/cli/js/lib.deno.window.d.ts @@ -13,6 +13,8 @@ declare interface Window extends WindowOrWorkerGlobalScope { onload: Function | undefined; onunload: Function | undefined; crypto: Crypto; + close: () => void; + closed: boolean; Deno: typeof Deno; } diff --git a/cli/js/main.ts b/cli/js/main.ts index 881d3ad4a0f061..bd30d33f79f397 100644 --- a/cli/js/main.ts +++ b/cli/js/main.ts @@ -13,12 +13,12 @@ Object.defineProperties(globalThis, { value: bootstrapMainRuntime, enumerable: false, writable: false, - configurable: false + configurable: false, }, bootstrapWorkerRuntime: { value: bootstrapWorkerRuntime, enumerable: false, writable: false, - configurable: false - } + configurable: false, + }, }); diff --git a/cli/js/net.ts b/cli/js/net.ts index 570bada49d8c49..7c0edf1f304eb9 100644 --- a/cli/js/net.ts +++ b/cli/js/net.ts @@ -4,25 +4,13 @@ import { EOF, Reader, Writer, Closer } from "./io.ts"; import { read, write } from "./ops/io.ts"; import { close } from "./ops/resources.ts"; import * as netOps from "./ops/net.ts"; -import { Transport } from "./ops/net.ts"; -export { ShutdownMode, shutdown, Transport } from "./ops/net.ts"; +import { Addr } from "./ops/net.ts"; +export { ShutdownMode, shutdown, NetAddr, UnixAddr } from "./ops/net.ts"; -export interface Addr { - transport: Transport; - hostname: string; - port: number; -} - -export interface UDPAddr { - transport?: Transport; - hostname?: string; - port: number; -} - -export interface UDPConn extends AsyncIterable<[Uint8Array, Addr]> { +export interface DatagramConn extends AsyncIterable<[Uint8Array, Addr]> { receive(p?: Uint8Array): Promise<[Uint8Array, Addr]>; - send(p: Uint8Array, addr: UDPAddr): Promise; + send(p: Uint8Array, addr: Addr): Promise; close(): void; @@ -73,7 +61,7 @@ export class ListenerImpl implements Listener { constructor(readonly rid: number, readonly addr: Addr) {} async accept(): Promise { - const res = await netOps.accept(this.rid); + const res = await netOps.accept(this.rid, this.addr.transport); return new ConnImpl(res.rid, res.remoteAddr, res.localAddr); } @@ -95,15 +83,7 @@ export class ListenerImpl implements Listener { } } -export async function recvfrom( - rid: number, - p: Uint8Array -): Promise<[number, Addr]> { - const { size, remoteAddr } = await netOps.receive(rid, p); - return [size, remoteAddr]; -} - -export class UDPConnImpl implements UDPConn { +export class DatagramImpl implements DatagramConn { constructor( readonly rid: number, readonly addr: Addr, @@ -112,14 +92,18 @@ export class UDPConnImpl implements UDPConn { async receive(p?: Uint8Array): Promise<[Uint8Array, Addr]> { const buf = p || new Uint8Array(this.bufSize); - const [size, remoteAddr] = await recvfrom(this.rid, buf); + const { size, remoteAddr } = await netOps.receive( + this.rid, + this.addr.transport, + buf + ); const sub = buf.subarray(0, size); return [sub, remoteAddr]; } - async send(p: Uint8Array, addr: UDPAddr): Promise { + async send(p: Uint8Array, addr: Addr): Promise { const remote = { hostname: "127.0.0.1", transport: "udp", ...addr }; - if (remote.transport !== "udp") throw Error("Remote transport must be UDP"); + const args = { ...remote, rid: this.rid }; await netOps.send(args as netOps.SendRequest, p); } @@ -153,38 +137,77 @@ export interface Conn extends Reader, Writer, Closer { export interface ListenOptions { port: number; hostname?: string; - transport?: Transport; + transport?: "tcp" | "udp"; +} + +export interface UnixListenOptions { + transport: "unix" | "unixpacket"; + address: string; } export function listen( options: ListenOptions & { transport?: "tcp" } ): Listener; -export function listen(options: ListenOptions & { transport: "udp" }): UDPConn; -export function listen({ - port, - hostname = "0.0.0.0", - transport = "tcp" -}: ListenOptions): Listener | UDPConn { - const res = netOps.listen({ port, hostname, transport }); - - if (transport === "tcp") { +export function listen( + options: UnixListenOptions & { transport: "unix" } +): Listener; +export function listen( + options: ListenOptions & { transport: "udp" } +): DatagramConn; +export function listen( + options: UnixListenOptions & { transport: "unixpacket" } +): DatagramConn; +export function listen( + options: ListenOptions | UnixListenOptions +): Listener | DatagramConn { + let res; + + if (options.transport === "unix" || options.transport === "unixpacket") { + res = netOps.listen(options); + } else { + res = netOps.listen({ + transport: "tcp", + hostname: "127.0.0.1", + ...(options as ListenOptions), + }); + } + + if ( + !options.transport || + options.transport === "tcp" || + options.transport === "unix" + ) { return new ListenerImpl(res.rid, res.localAddr); } else { - return new UDPConnImpl(res.rid, res.localAddr); + return new DatagramImpl(res.rid, res.localAddr); } } export interface ConnectOptions { port: number; hostname?: string; - transport?: Transport; + transport?: "tcp"; } +export interface UnixConnectOptions { + transport: "unix"; + address: string; +} +export async function connect(options: UnixConnectOptions): Promise; +export async function connect(options: ConnectOptions): Promise; +export async function connect( + options: ConnectOptions | UnixConnectOptions +): Promise { + let res; + + if (options.transport === "unix") { + res = await netOps.connect(options); + } else { + res = await netOps.connect({ + transport: "tcp", + hostname: "127.0.0.1", + ...options, + }); + } -export async function connect({ - port, - hostname = "127.0.0.1", - transport = "tcp" -}: ConnectOptions): Promise { - const res = await netOps.connect({ port, hostname, transport }); return new ConnImpl(res.rid, res.remoteAddr!, res.localAddr!); } diff --git a/cli/js/ops/compiler.ts b/cli/js/ops/compiler.ts index 0cbde6543a720b..825cadc16b6388 100644 --- a/cli/js/ops/compiler.ts +++ b/cli/js/ops/compiler.ts @@ -24,7 +24,7 @@ export function fetchSourceFiles( > { return sendAsync("op_fetch_source_files", { specifiers, - referrer + referrer, }); } @@ -47,6 +47,6 @@ export function cache( sendSync("op_cache", { extension, moduleId, - contents + contents, }); } diff --git a/cli/js/ops/dispatch_minimal.ts b/cli/js/ops/dispatch_minimal.ts index 61d630240ec527..570463583f0627 100644 --- a/cli/js/ops/dispatch_minimal.ts +++ b/cli/js/ops/dispatch_minimal.ts @@ -54,7 +54,7 @@ export function recordFromBufMinimal(ui8: Uint8Array): RecordMinimal { promiseId, arg, result, - err + err, }; } diff --git a/cli/js/ops/errors.ts b/cli/js/ops/errors.ts index 39793a85d1b9fa..5b65d102afbeb1 100644 --- a/cli/js/ops/errors.ts +++ b/cli/js/ops/errors.ts @@ -21,11 +21,11 @@ export function applySourceMap(location: Location): Location { const res = sendSync("op_apply_source_map", { filename, line: line - 1, - column: column - 1 + column: column - 1, }); return { filename: res.filename, line: res.line + 1, - column: res.column + 1 + column: res.column + 1, }; } diff --git a/cli/js/ops/fs/open.ts b/cli/js/ops/fs/open.ts index 87696935f32e9f..b587f491dd90f5 100644 --- a/cli/js/ops/fs/open.ts +++ b/cli/js/ops/fs/open.ts @@ -36,6 +36,6 @@ export function open( path, options, openMode, - mode + mode, }); } diff --git a/cli/js/ops/fs/stat.ts b/cli/js/ops/fs/stat.ts index a22d35310593fe..2d591e342e55d1 100644 --- a/cli/js/ops/fs/stat.ts +++ b/cli/js/ops/fs/stat.ts @@ -26,7 +26,7 @@ export interface StatResponse { export async function lstat(path: string): Promise { const res = (await sendAsync("op_stat", { path, - lstat: true + lstat: true, })) as StatResponse; return new FileInfoImpl(res); } @@ -34,7 +34,7 @@ export async function lstat(path: string): Promise { export function lstatSync(path: string): FileInfo { const res = sendSync("op_stat", { path, - lstat: true + lstat: true, }) as StatResponse; return new FileInfoImpl(res); } @@ -42,7 +42,7 @@ export function lstatSync(path: string): FileInfo { export async function stat(path: string): Promise { const res = (await sendAsync("op_stat", { path, - lstat: false + lstat: false, })) as StatResponse; return new FileInfoImpl(res); } @@ -50,7 +50,7 @@ export async function stat(path: string): Promise { export function statSync(path: string): FileInfo { const res = sendSync("op_stat", { path, - lstat: false + lstat: false, }) as StatResponse; return new FileInfoImpl(res); } diff --git a/cli/js/ops/fs/utime.ts b/cli/js/ops/fs/utime.ts index 13cac8cb63bd60..cd195531c8f8d3 100644 --- a/cli/js/ops/fs/utime.ts +++ b/cli/js/ops/fs/utime.ts @@ -14,7 +14,7 @@ export function utimeSync( path, // TODO(ry) split atime, mtime into [seconds, nanoseconds] tuple atime: toSecondsFromEpoch(atime), - mtime: toSecondsFromEpoch(mtime) + mtime: toSecondsFromEpoch(mtime), }); } @@ -27,6 +27,6 @@ export async function utime( path, // TODO(ry) split atime, mtime into [seconds, nanoseconds] tuple atime: toSecondsFromEpoch(atime), - mtime: toSecondsFromEpoch(mtime) + mtime: toSecondsFromEpoch(mtime), }); } diff --git a/cli/js/ops/fs_events.ts b/cli/js/ops/fs_events.ts index 4c08995b85636a..30a74f291ec1d7 100644 --- a/cli/js/ops/fs_events.ts +++ b/cli/js/ops/fs_events.ts @@ -17,7 +17,7 @@ class FsEvents implements AsyncIterableIterator { next(): Promise> { return sendAsync("op_fs_events_poll", { - rid: this.rid + rid: this.rid, }); } diff --git a/cli/js/ops/net.ts b/cli/js/ops/net.ts index 25f3a832296018..369f2ca3cfba74 100644 --- a/cli/js/ops/net.ts +++ b/cli/js/ops/net.ts @@ -1,16 +1,25 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. import { sendSync, sendAsync } from "./dispatch_json.ts"; -export type Transport = "tcp" | "udp"; -// TODO support other types: -// export type Transport = "tcp" | "tcp4" | "tcp6" | "unix" | "unixpacket"; +export interface NetAddr { + transport: "tcp" | "udp"; + hostname: string; + port: number; +} + +export interface UnixAddr { + transport: "unix" | "unixpacket"; + address: string; +} + +export type Addr = NetAddr | UnixAddr; export enum ShutdownMode { // See http://man7.org/linux/man-pages/man2/shutdown.2.html // Corresponding to SHUT_RD, SHUT_WR, SHUT_RDWR Read = 0, Write, - ReadWrite // unused + ReadWrite, // unused } export function shutdown(rid: number, how: ShutdownMode): void { @@ -19,35 +28,22 @@ export function shutdown(rid: number, how: ShutdownMode): void { interface AcceptResponse { rid: number; - localAddr: { - hostname: string; - port: number; - transport: Transport; - }; - remoteAddr: { - hostname: string; - port: number; - transport: Transport; - }; + localAddr: Addr; + remoteAddr: Addr; } -export function accept(rid: number): Promise { - return sendAsync("op_accept", { rid }); +export function accept( + rid: number, + transport: string +): Promise { + return sendAsync("op_accept", { rid, transport }); } -export interface ListenRequest { - transport: Transport; - hostname: string; - port: number; -} +export type ListenRequest = Addr; interface ListenResponse { rid: number; - localAddr: { - hostname: string; - port: number; - transport: Transport; - }; + localAddr: Addr; } export function listen(args: ListenRequest): ListenResponse { @@ -56,23 +52,11 @@ export function listen(args: ListenRequest): ListenResponse { interface ConnectResponse { rid: number; - localAddr: { - hostname: string; - port: number; - transport: Transport; - }; - remoteAddr: { - hostname: string; - port: number; - transport: Transport; - }; + localAddr: Addr; + remoteAddr: Addr; } -export interface ConnectRequest { - transport: Transport; - hostname: string; - port: number; -} +export type ConnectRequest = Addr; export function connect(args: ConnectRequest): Promise { return sendAsync("op_connect", args); @@ -80,26 +64,20 @@ export function connect(args: ConnectRequest): Promise { interface ReceiveResponse { size: number; - remoteAddr: { - hostname: string; - port: number; - transport: Transport; - }; + remoteAddr: Addr; } export function receive( rid: number, + transport: string, zeroCopy: Uint8Array ): Promise { - return sendAsync("op_receive", { rid }, zeroCopy); + return sendAsync("op_receive", { rid, transport }, zeroCopy); } -export interface SendRequest { +export type SendRequest = { rid: number; - hostname: string; - port: number; - transport: Transport; -} +} & Addr; export async function send( args: SendRequest, diff --git a/cli/js/ops/os.ts b/cli/js/ops/os.ts index d2fa4f2bbe977f..e01718c8c78832 100644 --- a/cli/js/ops/os.ts +++ b/cli/js/ops/os.ts @@ -40,7 +40,7 @@ export function env( set(obj, prop: string, value: string): boolean { setEnv(prop, value); return Reflect.set(obj, prop, value); - } + }, }); } diff --git a/cli/js/ops/process.ts b/cli/js/ops/process.ts index 384718cefa4180..fcfa7b9f5aa362 100644 --- a/cli/js/ops/process.ts +++ b/cli/js/ops/process.ts @@ -1,8 +1,12 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. import { sendSync, sendAsync } from "./dispatch_json.ts"; import { assert } from "../util.ts"; +import { build } from "../build.ts"; export function kill(pid: number, signo: number): void { + if (build.os === "win") { + throw new Error("Not yet implemented"); + } sendSync("op_kill", { pid, signo }); } @@ -17,7 +21,7 @@ export function runStatus(rid: number): Promise { } interface RunRequest { - args: string[]; + cmd: string[]; cwd?: string; env?: Array<[string, string]>; stdin: string; @@ -37,6 +41,6 @@ interface RunResponse { } export function run(request: RunRequest): RunResponse { - assert(request.args.length > 0); + assert(request.cmd.length > 0); return sendSync("op_run", request); } diff --git a/cli/js/ops/tls.ts b/cli/js/ops/tls.ts index e52143cb073a0e..234e569dd526dd 100644 --- a/cli/js/ops/tls.ts +++ b/cli/js/ops/tls.ts @@ -1,9 +1,8 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. import { sendAsync, sendSync } from "./dispatch_json.ts"; -import { Transport } from "./net.ts"; export interface ConnectTLSRequest { - transport: Transport; + transport: "tcp"; hostname: string; port: number; certFile?: string; @@ -14,12 +13,12 @@ interface ConnectTLSResponse { localAddr: { hostname: string; port: number; - transport: Transport; + transport: "tcp"; }; remoteAddr: { hostname: string; port: number; - transport: Transport; + transport: "tcp"; }; } @@ -34,12 +33,12 @@ interface AcceptTLSResponse { localAddr: { hostname: string; port: number; - transport: Transport; + transport: "tcp"; }; remoteAddr: { hostname: string; port: number; - transport: Transport; + transport: "tcp"; }; } @@ -50,7 +49,7 @@ export function acceptTLS(rid: number): Promise { export interface ListenTLSRequest { port: number; hostname: string; - transport: Transport; + transport: "tcp"; certFile: string; keyFile: string; } @@ -60,7 +59,7 @@ interface ListenTLSResponse { localAddr: { hostname: string; port: number; - transport: Transport; + transport: "tcp"; }; } diff --git a/cli/js/ops/tty.ts b/cli/js/ops/tty.ts index 2d5649623181ef..f848d277410151 100644 --- a/cli/js/ops/tty.ts +++ b/cli/js/ops/tty.ts @@ -7,6 +7,6 @@ export function isatty(rid: number): boolean { export function setRaw(rid: number, mode: boolean): void { sendSync("op_set_raw", { rid, - mode + mode, }); } diff --git a/cli/js/ops/worker_host.ts b/cli/js/ops/worker_host.ts index 0b9f81795a9b30..d483a5313a40c9 100644 --- a/cli/js/ops/worker_host.ts +++ b/cli/js/ops/worker_host.ts @@ -12,7 +12,7 @@ export function createWorker( specifier, hasSourceCode, sourceCode, - name + name, }); } diff --git a/cli/js/plugins.ts b/cli/js/plugins.ts index 061193b4f9fbfc..3fe0574cacc743 100644 --- a/cli/js/plugins.ts +++ b/cli/js/plugins.ts @@ -14,17 +14,21 @@ interface PluginOp { } class PluginOpImpl implements PluginOp { - constructor(private readonly opId: number) {} + readonly #opId: number; + + constructor(opId: number) { + this.#opId = opId; + } dispatch( control: Uint8Array, zeroCopy?: ArrayBufferView | null ): Uint8Array | null { - return core.dispatch(this.opId, control, zeroCopy); + return core.dispatch(this.#opId, control, zeroCopy); } setAsyncHandler(handler: AsyncHandler): void { - core.setAsyncHandler(this.opId, handler); + core.setAsyncHandler(this.#opId, handler); } } @@ -37,16 +41,16 @@ interface Plugin { } class PluginImpl implements Plugin { - private _ops: { [name: string]: PluginOp } = {}; + #ops: { [name: string]: PluginOp } = {}; - constructor(private readonly rid: number, ops: { [name: string]: number }) { + constructor(_rid: number, ops: { [name: string]: number }) { for (const op in ops) { - this._ops[op] = new PluginOpImpl(ops[op]); + this.#ops[op] = new PluginOpImpl(ops[op]); } } get ops(): { [name: string]: PluginOp } { - return Object.assign({}, this._ops); + return Object.assign({}, this.#ops); } } diff --git a/cli/js/process.ts b/cli/js/process.ts index ded1458a2155ff..c72fdef30d37d1 100644 --- a/cli/js/process.ts +++ b/cli/js/process.ts @@ -10,7 +10,7 @@ export type ProcessStdio = "inherit" | "piped" | "null"; // TODO Maybe extend VSCode's 'CommandOptions'? // See https://code.visualstudio.com/docs/editor/tasks-appendix#_schema-for-tasksjson export interface RunOptions { - args: string[]; + cmd: string[]; cwd?: string; env?: { [key: string]: string }; stdout?: ProcessStdio | number; @@ -108,15 +108,15 @@ interface RunResponse { stderrRid: number | null; } export function run({ - args, + cmd, cwd = undefined, env = {}, stdout = "inherit", stderr = "inherit", - stdin = "inherit" + stdin = "inherit", }: RunOptions): Process { const res = runOp({ - args: args.map(String), + cmd: cmd.map(String), cwd, env: Object.entries(env), stdin: isRid(stdin) ? "" : stdin, @@ -124,7 +124,7 @@ export function run({ stderr: isRid(stderr) ? "" : stderr, stdinRid: isRid(stdin) ? stdin : 0, stdoutRid: isRid(stdout) ? stdout : 0, - stderrRid: isRid(stderr) ? stderr : 0 + stderrRid: isRid(stderr) ? stderr : 0, }) as RunResponse; return new Process(res); } diff --git a/cli/js/rbtree.ts b/cli/js/rbtree.ts index 5de9f125d01c04..7b01024f7831f3 100644 --- a/cli/js/rbtree.ts +++ b/cli/js/rbtree.ts @@ -1,5 +1,7 @@ // Derived from https://github.com/vadimg/js_bintrees. MIT Licensed. +import { assert } from "./util.ts"; + class RBNode { public left: this | null; public right: this | null; @@ -24,16 +26,18 @@ class RBNode { } } -class RBTree { - private root: RBNode | null; +export class RBTree { + #comparator: (a: T, b: T) => number; + #root: RBNode | null; - constructor(private comparator: (a: T, b: T) => number) { - this.root = null; + constructor(comparator: (a: T, b: T) => number) { + this.#comparator = comparator; + this.#root = null; } - // returns null if tree is empty + /** Returns `null` if tree is empty. */ min(): T | null { - let res = this.root; + let res = this.#root; if (res === null) { return null; } @@ -43,11 +47,11 @@ class RBTree { return res.data; } - // returns node data if found, null otherwise + /** Returns node `data` if found, `null` otherwise. */ find(data: T): T | null { - let res = this.root; + let res = this.#root; while (res !== null) { - const c = this.comparator(data, res.data!); + const c = this.#comparator(data, res.data); if (c === 0) { return res.data; } else { @@ -57,13 +61,13 @@ class RBTree { return null; } - // returns true if inserted, false if duplicate + /** returns `true` if inserted, `false` if duplicate. */ insert(data: T): boolean { let ret = false; - if (this.root === null) { + if (this.#root === null) { // empty tree - this.root = new RBNode(data); + this.#root = new RBNode(data); ret = true; } else { const head = new RBNode((null as unknown) as T); // fake tree root @@ -75,8 +79,8 @@ class RBTree { let gp = null; // grandparent let ggp = head; // grand-grand-parent let p: RBNode | null = null; // parent - let node: RBNode | null = this.root; - ggp.right = this.root; + let node: RBNode | null = this.#root; + ggp.right = this.#root; // search down while (true) { @@ -96,14 +100,15 @@ class RBTree { if (isRed(node) && isRed(p)) { const dir2 = ggp.right === gp; + assert(gp); if (node === p!.getChild(last)) { - ggp.setChild(dir2, singleRotate(gp!, !last)); + ggp.setChild(dir2, singleRotate(gp, !last)); } else { - ggp.setChild(dir2, doubleRotate(gp!, !last)); + ggp.setChild(dir2, doubleRotate(gp, !last)); } } - const cmp = this.comparator(node.data!, data); + const cmp = this.#comparator(node.data, data); // stop if found if (cmp === 0) { @@ -123,24 +128,24 @@ class RBTree { } // update root - this.root = head.right; + this.#root = head.right; } // make root black - this.root!.red = false; + this.#root!.red = false; return ret; } - // returns true if removed, false if not found + /** Returns `true` if removed, `false` if not found. */ remove(data: T): boolean { - if (this.root === null) { + if (this.#root === null) { return false; } const head = new RBNode((null as unknown) as T); // fake tree root let node = head; - node.right = this.root; + node.right = this.#root; let p = null; // parent let gp = null; // grand parent let found = null; // found item @@ -154,7 +159,7 @@ class RBTree { p = node; node = node.getChild(dir)!; - const cmp = this.comparator(data, node.data); + const cmp = this.#comparator(data, node.data); dir = cmp > 0; @@ -181,7 +186,8 @@ class RBTree { sibling.red = true; node.red = true; } else { - const dir2 = gp!.right === p; + assert(gp); + const dir2 = gp.right === p; if (isRed(sibling.getChild(last))) { gp!.setChild(dir2, doubleRotate(p, last)); @@ -190,11 +196,14 @@ class RBTree { } // ensure correct coloring - const gpc = gp!.getChild(dir2)!; + const gpc = gp.getChild(dir2); + assert(gpc); gpc.red = true; node.red = true; - gpc.left!.red = false; - gpc.right!.red = false; + assert(gpc.left); + gpc.left.red = false; + assert(gpc.right); + gpc.right.red = false; } } } @@ -204,13 +213,14 @@ class RBTree { // replace and remove if found if (found !== null) { found.data = node.data; - p!.setChild(p!.right === node, node.getChild(node.left === null)); + assert(p); + p.setChild(p.right === node, node.getChild(node.left === null)); } // update root and make it black - this.root = head.right; - if (this.root !== null) { - this.root.red = false; + this.#root = head.right; + if (this.#root !== null) { + this.#root.red = false; } return found !== null; @@ -222,7 +232,8 @@ function isRed(node: RBNode | null): boolean { } function singleRotate(root: RBNode, dir: boolean | number): RBNode { - const save = root.getChild(!dir)!; + const save = root.getChild(!dir); + assert(save); root.setChild(!dir, save.getChild(dir)); save.setChild(dir, root); @@ -237,5 +248,3 @@ function doubleRotate(root: RBNode, dir: boolean | number): RBNode { root.setChild(!dir, singleRotate(root.getChild(!dir)!, !dir)); return singleRotate(root, dir); } - -export { RBTree }; diff --git a/cli/js/repl.ts b/cli/js/repl.ts index f1b0723c8737e8..04471367878391 100644 --- a/cli/js/repl.ts +++ b/cli/js/repl.ts @@ -17,20 +17,20 @@ const helpMsg = [ "_ Get last evaluation result", "_error Get last thrown error", "exit Exit the REPL", - "help Print this help message" + "help Print this help message", ].join("\n"); const replCommands = { exit: { get(): void { exit(0); - } + }, }, help: { get(): string { return helpMsg; - } - } + }, + }, }; // Error messages that allow users to continue input @@ -42,7 +42,7 @@ const recoverableErrorMessages = [ "Missing initializer in const declaration", // const a "Missing catch or finally after try", // try {} "missing ) after argument list", // console.log(1 - "Unterminated template literal" // `template + "Unterminated template literal", // `template // TODO(kevinkassimo): need a parser to handling errors such as: // "Missing } in template expression" // `${ or `${ a 123 }` ]; @@ -105,10 +105,10 @@ export async function replLoop(): Promise { value: value, writable: true, enumerable: true, - configurable: true + configurable: true, }); console.log("Last evaluation result is no longer saved to _."); - } + }, }); // Configure globalThis._error to give the last thrown error. @@ -120,10 +120,10 @@ export async function replLoop(): Promise { value: value, writable: true, enumerable: true, - configurable: true + configurable: true, }); console.log("Last thrown error is no longer saved to _error."); - } + }, }); while (true) { diff --git a/cli/js/runtime_main.ts b/cli/js/runtime_main.ts index a59e7513bfb7fd..edb02d2d6544f7 100644 --- a/cli/js/runtime_main.ts +++ b/cli/js/runtime_main.ts @@ -10,17 +10,20 @@ import * as Deno from "./deno.ts"; import * as domTypes from "./web/dom_types.ts"; import * as csprng from "./ops/get_random_values.ts"; +import { exit } from "./ops/os.ts"; import { readOnly, + getterOnly, writable, windowOrWorkerGlobalScopeMethods, windowOrWorkerGlobalScopeProperties, - eventTargetProperties + eventTargetProperties, } from "./globals.ts"; import { internalObject } from "./internals.ts"; import { setSignals } from "./signals.ts"; import { replLoop } from "./repl.ts"; import { LocationImpl } from "./web/location.ts"; +import { setTimeout } from "./web/timers.ts"; import * as runtime from "./runtime.ts"; import { symbols } from "./symbols.ts"; import { log, immutableDefine } from "./util.ts"; @@ -31,6 +34,26 @@ import { log, immutableDefine } from "./util.ts"; // @ts-ignore Deno[symbols.internal] = internalObject; +let windowIsClosing = false; + +function windowClose(): void { + if (!windowIsClosing) { + windowIsClosing = true; + // Push a macrotask to exit after a promise resolve. + // This is not perfect, but should be fine for first pass. + Promise.resolve().then(() => + setTimeout.call( + null, + () => { + // This should be fine, since only Window/MainWorker has .close() + exit(0); + }, + 0 + ) + ); + } +} + export const mainRuntimeGlobalProperties = { window: readOnly(globalThis), self: readOnly(globalThis), @@ -38,7 +61,9 @@ export const mainRuntimeGlobalProperties = { // TODO(bartlomieju): from MDN docs (https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope) // it seems those two properties should be availble to workers as well onload: writable(undefined), - onunload: writable(undefined) + onunload: writable(undefined), + close: writable(windowClose), + closed: getterOnly(() => windowIsClosing), }; let hasBootstrapped = false; @@ -77,7 +102,7 @@ export function bootstrapMainRuntime(): void { Object.defineProperties(Deno, { pid: readOnly(s.pid), noColor: readOnly(s.noColor), - args: readOnly(Object.freeze(s.args)) + args: readOnly(Object.freeze(s.args)), }); // Setup `Deno` global - we're actually overriding already // existing global `Deno` with `Deno` namespace from "./deno.ts". diff --git a/cli/js/runtime_worker.ts b/cli/js/runtime_worker.ts index bd051dbf2569ff..c7742cf31dd362 100644 --- a/cli/js/runtime_worker.ts +++ b/cli/js/runtime_worker.ts @@ -14,7 +14,7 @@ import { nonEnumerable, windowOrWorkerGlobalScopeMethods, windowOrWorkerGlobalScopeProperties, - eventTargetProperties + eventTargetProperties, } from "./globals.ts"; import * as webWorkerOps from "./ops/web_worker.ts"; import { LocationImpl } from "./web/location.ts"; @@ -85,7 +85,7 @@ export const workerRuntimeGlobalProperties = { // TODO: should be readonly? close: nonEnumerable(close), postMessage: writable(postMessage), - workerMessageRecvCallback: nonEnumerable(workerMessageRecvCallback) + workerMessageRecvCallback: nonEnumerable(workerMessageRecvCallback), }; export function bootstrapWorkerRuntime(name: string): void { diff --git a/cli/js/signals.ts b/cli/js/signals.ts index 28bc271c41685c..e7fd8c04d12bd3 100644 --- a/cli/js/signals.ts +++ b/cli/js/signals.ts @@ -34,7 +34,7 @@ enum LinuxSignal { SIGWINCH = 28, SIGIO = 29, SIGPWR = 30, - SIGSYS = 31 + SIGSYS = 31, } // From `kill -l` @@ -69,7 +69,7 @@ enum MacOSSignal { SIGWINCH = 28, SIGINFO = 29, SIGUSR1 = 30, - SIGUSR2 = 31 + SIGUSR2 = 31, } export const Signal: { [key: string]: number } = {}; @@ -122,39 +122,40 @@ export const signals = { }, windowChange(): SignalStream { return signal(Signal.SIGWINCH); - } + }, }; export class SignalStream implements AsyncIterableIterator, PromiseLike { - private rid: number; - private pollingPromise: Promise = Promise.resolve(false); - private disposed = false; + #disposed = false; + #pollingPromise: Promise = Promise.resolve(false); + #rid: number; + constructor(signo: number) { - this.rid = bindSignal(signo).rid; - this.loop(); + this.#rid = bindSignal(signo).rid; + this.#loop(); } - private async pollSignal(): Promise { - const res = await pollSignal(this.rid); + #pollSignal = async (): Promise => { + const res = await pollSignal(this.#rid); return res.done; - } + }; - private async loop(): Promise { + #loop = async (): Promise => { do { - this.pollingPromise = this.pollSignal(); - } while (!(await this.pollingPromise) && !this.disposed); - } + this.#pollingPromise = this.#pollSignal(); + } while (!(await this.#pollingPromise) && !this.#disposed); + }; then( f: (v: void) => T | Promise, g?: (v: Error) => S | Promise ): Promise { - return this.pollingPromise.then((_): void => {}).then(f, g); + return this.#pollingPromise.then(() => {}).then(f, g); } async next(): Promise> { - return { done: await this.pollingPromise, value: undefined }; + return { done: await this.#pollingPromise, value: undefined }; } [Symbol.asyncIterator](): AsyncIterableIterator { @@ -162,10 +163,10 @@ export class SignalStream } dispose(): void { - if (this.disposed) { + if (this.#disposed) { throw new Error("The stream has already been disposed."); } - this.disposed = true; - unbindSignal(this.rid); + this.#disposed = true; + unbindSignal(this.#rid); } } diff --git a/cli/js/symbols.ts b/cli/js/symbols.ts index 785b47357f132e..59d0751c009825 100644 --- a/cli/js/symbols.ts +++ b/cli/js/symbols.ts @@ -4,5 +4,5 @@ import { customInspect } from "./web/console.ts"; export const symbols = { internal: internalSymbol, - customInspect + customInspect, }; diff --git a/cli/js/testing.ts b/cli/js/testing.ts index 22e719719fb94f..94a4cc7026bd74 100644 --- a/cli/js/testing.ts +++ b/cli/js/testing.ts @@ -11,7 +11,7 @@ import { assert } from "./util.ts"; const RED_FAILED = red("FAILED"); const GREEN_OK = green("ok"); const YELLOW_IGNORED = yellow("ignored"); -const disabledConsole = new Console((_x: string, _isErr?: boolean): void => {}); +const disabledConsole = new Console((): void => {}); function formatDuration(time = 0): string { const timeStr = `(${time}ms)`; @@ -140,7 +140,7 @@ export interface RunTestsOptions { enum TestStatus { Passed = "passed", Failed = "failed", - Ignored = "ignored" + Ignored = "ignored", } interface TestResult { @@ -154,7 +154,7 @@ export enum TestEvent { Start = "start", TestStart = "testStart", TestEnd = "testEnd", - End = "end" + End = "end", } interface TestEventStart { @@ -188,7 +188,7 @@ class TestApi { ignored: 0, measured: 0, passed: 0, - failed: 0 + failed: 0, }; constructor( @@ -205,7 +205,7 @@ class TestApi { > { yield { kind: TestEvent.Start, - tests: this.testsToRun.length + tests: this.testsToRun.length, }; const results: TestResult[] = []; @@ -243,7 +243,7 @@ class TestApi { kind: TestEvent.End, stats: this.stats, results, - duration + duration, }; } } @@ -283,33 +283,15 @@ interface TestReporter { } export class ConsoleTestReporter implements TestReporter { - private encoder: TextEncoder; - - constructor() { - this.encoder = new TextEncoder(); - } - - private log(msg: string, noNewLine = false): Promise { - if (!noNewLine) { - msg += "\n"; - } - - // Using `stdout` here because it doesn't force new lines - // compared to `console.log`; `core.print` on the other hand - // is line-buffered and doesn't output message without newline - stdout.writeSync(this.encoder.encode(msg)); - return Promise.resolve(); - } - start(event: TestEventStart): Promise { - this.log(`running ${event.tests} tests`); + ConsoleTestReporter.log(`running ${event.tests} tests`); return Promise.resolve(); } testStart(event: TestEventTestStart): Promise { const { name } = event; - this.log(`test ${name} ... `, true); + ConsoleTestReporter.log(`test ${name} ... `, true); return Promise.resolve(); } @@ -318,13 +300,19 @@ export class ConsoleTestReporter implements TestReporter { switch (result.status) { case TestStatus.Passed: - this.log(`${GREEN_OK} ${formatDuration(result.duration)}`); + ConsoleTestReporter.log( + `${GREEN_OK} ${formatDuration(result.duration)}` + ); break; case TestStatus.Failed: - this.log(`${RED_FAILED} ${formatDuration(result.duration)}`); + ConsoleTestReporter.log( + `${RED_FAILED} ${formatDuration(result.duration)}` + ); break; case TestStatus.Ignored: - this.log(`${YELLOW_IGNORED} ${formatDuration(result.duration)}`); + ConsoleTestReporter.log( + `${YELLOW_IGNORED} ${formatDuration(result.duration)}` + ); break; } @@ -334,25 +322,25 @@ export class ConsoleTestReporter implements TestReporter { end(event: TestEventEnd): Promise { const { stats, duration, results } = event; // Attempting to match the output of Rust's test runner. - const failedTests = results.filter(r => r.error); + const failedTests = results.filter((r) => r.error); if (failedTests.length > 0) { - this.log(`\nfailures:\n`); + ConsoleTestReporter.log(`\nfailures:\n`); for (const result of failedTests) { - this.log(`${result.name}`); - this.log(`${stringifyArgs([result.error!])}`); - this.log(""); + ConsoleTestReporter.log(`${result.name}`); + ConsoleTestReporter.log(`${stringifyArgs([result.error!])}`); + ConsoleTestReporter.log(""); } - this.log(`failures:\n`); + ConsoleTestReporter.log(`failures:\n`); for (const result of failedTests) { - this.log(`\t${result.name}`); + ConsoleTestReporter.log(`\t${result.name}`); } } - this.log( + ConsoleTestReporter.log( `\ntest result: ${stats.failed ? RED_FAILED : GREEN_OK}. ` + `${stats.passed} passed; ${stats.failed} failed; ` + `${stats.ignored} ignored; ${stats.measured} measured; ` + @@ -362,6 +350,20 @@ export class ConsoleTestReporter implements TestReporter { return Promise.resolve(); } + + static encoder = new TextEncoder(); + + static log(msg: string, noNewLine = false): Promise { + if (!noNewLine) { + msg += "\n"; + } + + // Using `stdout` here because it doesn't force new lines + // compared to `console.log`; `core.print` on the other hand + // is line-buffered and doesn't output message without newline + stdout.writeSync(ConsoleTestReporter.encoder.encode(msg)); + return Promise.resolve(); + } } export async function runTests({ @@ -370,7 +372,7 @@ export async function runTests({ only = undefined, skip = undefined, disableLog = false, - reporter = undefined + reporter = undefined, }: RunTestsOptions = {}): Promise<{ results: TestResult[]; stats: TestStats; diff --git a/cli/js/tests/blob_test.ts b/cli/js/tests/blob_test.ts index 54071a11e8ad2c..57793af0ea7a7f 100644 --- a/cli/js/tests/blob_test.ts +++ b/cli/js/tests/blob_test.ts @@ -38,7 +38,7 @@ unitTest(function blobShouldNotThrowError(): void { try { const options1: object = { ending: "utf8", - hasOwnProperty: "hasOwnProperty" + hasOwnProperty: "hasOwnProperty", }; const options2: object = Object.create(null); new Blob(["Hello World"], options1); @@ -52,7 +52,7 @@ unitTest(function blobShouldNotThrowError(): void { unitTest(function nativeEndLine(): void { const options: object = { - ending: "native" + ending: "native", }; const blob = new Blob(["Hello\nWorld"], options); diff --git a/cli/js/tests/body_test.ts b/cli/js/tests/body_test.ts index 23f6d89e48b6d5..c8f783e0430eab 100644 --- a/cli/js/tests/body_test.ts +++ b/cli/js/tests/body_test.ts @@ -5,7 +5,7 @@ import { unitTest, assertEquals, assert } from "./test_util.ts"; // eslint-disable-next-line @typescript-eslint/no-explicit-any function buildBody(body: any): Body { const stub = new Request("", { - body: body + body: body, }); return stub as Body; } @@ -19,7 +19,7 @@ const intArrays = [ Uint32Array, Uint8ClampedArray, Float32Array, - Float64Array + Float64Array, ]; unitTest(async function arrayBufferFromByteArrays(): Promise { const buffer = new TextEncoder().encode("ahoyhoy8").buffer; diff --git a/cli/js/tests/buffer_test.ts b/cli/js/tests/buffer_test.ts index 163ed0a3085889..9cfb7166971539 100644 --- a/cli/js/tests/buffer_test.ts +++ b/cli/js/tests/buffer_test.ts @@ -7,7 +7,7 @@ import { assertEquals, assert, assertStrContains, - unitTest + unitTest, } from "./test_util.ts"; const { Buffer, readAll, readAllSync, writeAll, writeAllSync } = Deno; diff --git a/cli/js/tests/chmod_test.ts b/cli/js/tests/chmod_test.ts index 169934e92a0f30..3a00963091525b 100644 --- a/cli/js/tests/chmod_test.ts +++ b/cli/js/tests/chmod_test.ts @@ -22,7 +22,7 @@ unitTest( unitTest( { ignore: Deno.build.os === "win", - perms: { read: true, write: true } + perms: { read: true, write: true }, }, function chmodSyncSymlinkSuccess(): void { const enc = new TextEncoder(); @@ -94,7 +94,7 @@ unitTest( unitTest( { ignore: Deno.build.os === "win", - perms: { read: true, write: true } + perms: { read: true, write: true }, }, async function chmodSymlinkSuccess(): Promise { const enc = new TextEncoder(); diff --git a/cli/js/tests/chown_test.ts b/cli/js/tests/chown_test.ts index 50dcd6dc13a462..2d1dc7756a093b 100644 --- a/cli/js/tests/chown_test.ts +++ b/cli/js/tests/chown_test.ts @@ -7,11 +7,11 @@ if (Deno.build.os !== "win") { // get the user ID and group ID of the current process const uidProc = Deno.run({ stdout: "piped", - args: ["python", "-c", "import os; print(os.getuid())"] + cmd: ["python", "-c", "import os; print(os.getuid())"], }); const gidProc = Deno.run({ stdout: "piped", - args: ["python", "-c", "import os; print(os.getgid())"] + cmd: ["python", "-c", "import os; print(os.getgid())"], }); assertEquals((await uidProc.status()).code, 0); diff --git a/cli/js/tests/console_test.ts b/cli/js/tests/console_test.ts index b640160787c74f..b4848332f715ca 100644 --- a/cli/js/tests/console_test.ts +++ b/cli/js/tests/console_test.ts @@ -6,14 +6,14 @@ import { assert, assertEquals, unitTest } from "./test_util.ts"; const { inspect, writeSync, - stdout + stdout, // eslint-disable-next-line @typescript-eslint/no-explicit-any } = Deno as any; const customInspect = Deno.symbols.customInspect; const { Console, - stringifyArgs + stringifyArgs, // @ts-ignore TypeScript (as of 3.7) does not support indexing namespaces by symbol } = Deno[Deno.symbols.internal]; @@ -37,7 +37,7 @@ unitTest(function consoleHasRightInstance(): void { }); unitTest(function consoleTestAssertShouldNotThrowError(): void { - mockConsole(console => { + mockConsole((console) => { console.assert(true); let hasThrown = undefined; try { @@ -92,7 +92,7 @@ unitTest(function consoleTestStringifyCircular(): void { arrowFunc: () => {}, extendedClass: new Extended(), nFunc: new Function(), - extendedCstr: Extended + extendedCstr: Extended, }; const circularObj = { @@ -105,11 +105,36 @@ unitTest(function consoleTestStringifyCircular(): void { nested: nestedObj, emptyObj: {}, arr: [1, "s", false, null, nestedObj], - baseClass: new Base() + baseClass: new Base(), }; nestedObj.o = circularObj; - const nestedObjExpected = `{ num, bool, str, method, asyncMethod, generatorMethod, un, nu, arrowFunc, extendedClass, nFunc, extendedCstr, o }`; + const nestedObjExpected = `{ + num: 1, + bool: true, + str: "a", + method: [Function: method], + asyncMethod: [AsyncFunction: asyncMethod], + generatorMethod: [GeneratorFunction: generatorMethod], + un: undefined, + nu: null, + arrowFunc: [Function: arrowFunc], + extendedClass: Extended { a: 1, b: 2 }, + nFunc: [Function], + extendedCstr: [Function: Extended], + o: { + num: 2, + bool: false, + str: "b", + method: [Function: method], + un: undefined, + nu: null, + nested: [Circular], + emptyObj: {}, + arr: [ 1, "s", false, null, [Circular] ], + baseClass: Base { a: 1 } + } +}`; assertEquals(stringify(1), "1"); assertEquals(stringify(-0), "-0"); @@ -129,7 +154,7 @@ unitTest(function consoleTestStringifyCircular(): void { stringify( new Map([ [1, "one"], - [2, "two"] + [2, "two"], ]) ), `Map { 1 => "one", 2 => "two" }` @@ -166,7 +191,29 @@ unitTest(function consoleTestStringifyCircular(): void { assertEquals(stringify(JSON), 'JSON { Symbol(Symbol.toStringTag): "JSON" }'); assertEquals( stringify(console), - "{ printFunc, log, debug, info, dir, dirxml, warn, error, assert, count, countReset, table, time, timeLog, timeEnd, group, groupCollapsed, groupEnd, clear, trace, indentLevel, Symbol(isConsoleInstance) }" + `{ + log: [Function], + debug: [Function], + info: [Function], + dir: [Function], + dirxml: [Function], + warn: [Function], + error: [Function], + assert: [Function], + count: [Function], + countReset: [Function], + table: [Function], + time: [Function], + timeLog: [Function], + timeEnd: [Function], + group: [Function], + groupCollapsed: [Function], + groupEnd: [Function], + clear: [Function], + trace: [Function], + indentLevel: 0, + Symbol(isConsoleInstance): true +}` ); assertEquals( stringify({ str: 1, [Symbol.for("sym")]: 2, [Symbol.toStringTag]: "TAG" }), @@ -200,6 +247,42 @@ unitTest(function consoleTestStringifyWithDepth(): void { ); }); +unitTest(function consoleTestStringifyLargeObject(): void { + const obj = { + a: 2, + o: { + a: "1", + b: "2", + c: "3", + d: "4", + e: "5", + f: "6", + g: 10, + asd: 2, + asda: 3, + x: { a: "asd", x: 3 }, + }, + }; + assertEquals( + stringify(obj), + `{ + a: 2, + o: { + a: "1", + b: "2", + c: "3", + d: "4", + e: "5", + f: "6", + g: 10, + asd: 2, + asda: 3, + x: { a: "asd", x: 3 } + } +}` + ); +}); + unitTest(function consoleTestWithCustomInspector(): void { class A { [customInspect](): string { @@ -310,14 +393,14 @@ unitTest(function consoleTestWithVariousOrInvalidFormatSpecifier(): void { unitTest(function consoleTestCallToStringOnLabel(): void { const methods = ["count", "countReset", "time", "timeLog", "timeEnd"]; - mockConsole(console => { + mockConsole((console) => { for (const method of methods) { let hasCalled = false; // @ts-ignore console[method]({ toString(): void { hasCalled = true; - } + }, }); assertEquals(hasCalled, true); } @@ -362,7 +445,7 @@ unitTest(function consoleTestClear(): void { // Test bound this issue unitTest(function consoleDetachedLog(): void { - mockConsole(console => { + mockConsole((console) => { const log = console.log; const dir = console.dir; const dirxml = console.dirxml; @@ -551,7 +634,7 @@ unitTest(function consoleTable(): void { console.table( new Map([ [1, "one"], - [2, "two"] + [2, "two"], ]) ); assertEquals( @@ -571,7 +654,7 @@ unitTest(function consoleTable(): void { b: { c: { d: 10 }, e: [1, 2, [5, 6]] }, f: "test", g: new Set([1, 2, 3, "test"]), - h: new Map([[1, "one"]]) + h: new Map([[1, "one"]]), }); assertEquals( out.toString(), @@ -593,7 +676,7 @@ unitTest(function consoleTable(): void { "test", false, { a: 10 }, - ["test", { b: 20, c: "test" }] + ["test", { b: 20, c: "test" }], ]); assertEquals( out.toString(), @@ -661,7 +744,7 @@ unitTest(function consoleTable(): void { // console.log(Error) test unitTest(function consoleLogShouldNotThrowError(): void { - mockConsole(console => { + mockConsole((console) => { let result = 0; try { console.log(new Error("foo")); diff --git a/cli/js/tests/custom_event_test.ts b/cli/js/tests/custom_event_test.ts index 7a5cc44ca194ba..a8b2fcf8844155 100644 --- a/cli/js/tests/custom_event_test.ts +++ b/cli/js/tests/custom_event_test.ts @@ -7,7 +7,7 @@ unitTest(function customEventInitializedWithDetail(): void { const customEventInit = { bubbles: true, cancelable: true, - detail + detail, } as CustomEventInit; const event = new CustomEvent(type, customEventInit); diff --git a/cli/js/tests/dispatch_minimal_test.ts b/cli/js/tests/dispatch_minimal_test.ts index 60bb620db69663..afc17f4fb8434b 100644 --- a/cli/js/tests/dispatch_minimal_test.ts +++ b/cli/js/tests/dispatch_minimal_test.ts @@ -3,7 +3,7 @@ import { assertEquals, assertMatch, unitTest, - unreachable + unreachable, } from "./test_util.ts"; const readErrorStackPattern = new RegExp( diff --git a/cli/js/tests/dom_iterable_test.ts b/cli/js/tests/dom_iterable_test.ts index e1637894551d9b..827a788a9e9c6e 100644 --- a/cli/js/tests/dom_iterable_test.ts +++ b/cli/js/tests/dom_iterable_test.ts @@ -5,7 +5,7 @@ import { unitTest, assert, assertEquals } from "./test_util.ts"; function setup() { const dataSymbol = Symbol("data symbol"); class Base { - private [dataSymbol] = new Map(); + [dataSymbol] = new Map(); constructor( data: Array<[string, number]> | IterableIterator<[string, number]> @@ -21,7 +21,7 @@ function setup() { // This is using an internal API we don't want published as types, so having // to cast to any to "trick" TypeScript // @ts-ignore TypeScript (as of 3.7) does not support indexing namespaces by symbol - DomIterable: Deno[Deno.symbols.internal].DomIterableMixin(Base, dataSymbol) + DomIterable: Deno[Deno.symbols.internal].DomIterableMixin(Base, dataSymbol), }; } @@ -30,7 +30,7 @@ unitTest(function testDomIterable(): void { const fixture: Array<[string, number]> = [ ["foo", 1], - ["bar", 2] + ["bar", 2], ]; const domIterable = new DomIterable(fixture); diff --git a/cli/js/tests/error_stack_test.ts b/cli/js/tests/error_stack_test.ts index 7acbd3a3db8042..6868be2155b590 100644 --- a/cli/js/tests/error_stack_test.ts +++ b/cli/js/tests/error_stack_test.ts @@ -76,7 +76,7 @@ function getMockCallSite( }, getPromiseIndex(): null { return null; - } + }, }; } @@ -90,7 +90,7 @@ unitTest(function prepareStackTrace(): void { structuredStackTrace: CallSite[] ) => string = MockError.prepareStackTrace; const result = prepareStackTrace(new Error("foo"), [ - getMockCallSite("CLI_SNAPSHOT.js", 23, 0) + getMockCallSite("CLI_SNAPSHOT.js", 23, 0), ]); assert(result.startsWith("Error: foo\n")); assert(result.includes(".ts:"), "should remap to something in 'js/'"); @@ -100,7 +100,7 @@ unitTest(function applySourceMap(): void { const result = Deno.applySourceMap({ filename: "CLI_SNAPSHOT.js", line: 23, - column: 0 + column: 0, }); assert(result.filename.endsWith(".ts")); assert(result.line != null); diff --git a/cli/js/tests/event_target_test.ts b/cli/js/tests/event_target_test.ts index 020db1acd3ea80..45f62650298743 100644 --- a/cli/js/tests/event_target_test.ts +++ b/cli/js/tests/event_target_test.ts @@ -114,7 +114,7 @@ unitTest(function dispatchEventShouldNotThrowError(): void { const target = new EventTarget(); const event = new Event("hasOwnProperty", { bubbles: true, - cancelable: false + cancelable: false, }); const listener = (): void => {}; target.addEventListener("hasOwnProperty", listener); @@ -130,7 +130,7 @@ unitTest(function eventTargetThisShouldDefaultToWindow(): void { const { addEventListener, dispatchEvent, - removeEventListener + removeEventListener, } = EventTarget.prototype; let n = 1; const event = new Event("hello"); @@ -164,7 +164,7 @@ unitTest(function eventTargetShouldAcceptEventListenerObject(): void { handleEvent(e: Event): void { assertEquals(e, event); ++callCount; - } + }, }; target.addEventListener("foo", listener); @@ -213,7 +213,7 @@ unitTest( handleEvent(e: Event): void { assertEquals(e, event); ++callCount; - } + }, }; target.addEventListener("foo", listener); diff --git a/cli/js/tests/fetch_test.ts b/cli/js/tests/fetch_test.ts index 67675177e9badd..432ecd59c2165f 100644 --- a/cli/js/tests/fetch_test.ts +++ b/cli/js/tests/fetch_test.ts @@ -5,7 +5,7 @@ import { assertEquals, assertStrContains, assertThrows, - fail + fail, } from "./test_util.ts"; unitTest({ perms: { net: true } }, async function fetchProtocolError(): Promise< @@ -174,7 +174,7 @@ unitTest( unitTest( { - perms: { net: true } + perms: { net: true }, }, async function fetchWithRedirection(): Promise { const response = await fetch("http://localhost:4546/"); // will redirect to http://localhost:4545/ @@ -188,7 +188,7 @@ unitTest( unitTest( { - perms: { net: true } + perms: { net: true }, }, async function fetchWithRelativeRedirection(): Promise { const response = await fetch("http://localhost:4545/cli/tests"); // will redirect to /cli/tests/ @@ -204,7 +204,7 @@ unitTest( // FIXME(bartlomieju): // The feature below is not implemented, but the test should work after implementation ignore: true, - perms: { net: true } + perms: { net: true }, }, async function fetchWithInfRedirection(): Promise { const response = await fetch("http://localhost:4549/cli/tests"); // will redirect to the same place @@ -218,7 +218,7 @@ unitTest( const data = "Hello World"; const response = await fetch("http://localhost:4545/echo_server", { method: "POST", - body: data + body: data, }); const text = await response.text(); assertEquals(text, data); @@ -232,7 +232,7 @@ unitTest( const data = "Hello World"; const req = new Request("http://localhost:4545/echo_server", { method: "POST", - body: data + body: data, }); const response = await fetch(req); const text = await response.text(); @@ -246,7 +246,7 @@ unitTest( const data = "Hello World"; const response = await fetch("http://localhost:4545/echo_server", { method: "POST", - body: new TextEncoder().encode(data) + body: new TextEncoder().encode(data), }); const text = await response.text(); assertEquals(text, data); @@ -260,7 +260,7 @@ unitTest( const params = new URLSearchParams(data); const response = await fetch("http://localhost:4545/echo_server", { method: "POST", - body: params + body: params, }); const text = await response.text(); assertEquals(text, data); @@ -277,11 +277,11 @@ unitTest({ perms: { net: true } }, async function fetchInitBlobBody(): Promise< > { const data = "const a = 1"; const blob = new Blob([data], { - type: "text/javascript" + type: "text/javascript", }); const response = await fetch("http://localhost:4545/echo_server", { method: "POST", - body: blob + body: blob, }); const text = await response.text(); assertEquals(text, data); @@ -295,7 +295,7 @@ unitTest( form.append("field", "value"); const response = await fetch("http://localhost:4545/echo_server", { method: "POST", - body: form + body: form, }); const resultForm = await response.formData(); assertEquals(form.get("field"), resultForm.get("field")); @@ -308,7 +308,7 @@ unitTest({ perms: { net: true } }, async function fetchUserAgent(): Promise< const data = "Hello World"; const response = await fetch("http://localhost:4545/echo_server", { method: "POST", - body: new TextEncoder().encode(data) + body: new TextEncoder().encode(data), }); assertEquals(response.headers.get("user-agent"), `Deno/${Deno.version.deno}`); await response.text(); @@ -337,7 +337,7 @@ function bufferServer(addr: string): Deno.Buffer { const [hostname, port] = addr.split(":"); const listener = Deno.listen({ hostname, - port: Number(port) + port: Number(port), }) as Deno.Listener; const buf = new Deno.Buffer(); listener.accept().then(async (conn: Deno.Conn) => { @@ -364,7 +364,7 @@ unitTest( { // FIXME(bartlomieju) ignore: true, - perms: { net: true } + perms: { net: true }, }, async function fetchRequest(): Promise { const addr = "127.0.0.1:4501"; @@ -373,8 +373,8 @@ unitTest( method: "POST", headers: [ ["Hello", "World"], - ["Foo", "Bar"] - ] + ["Foo", "Bar"], + ], }); assertEquals(response.status, 404); assertEquals(response.headers.get("Content-Length"), "2"); @@ -384,7 +384,7 @@ unitTest( "POST /blah HTTP/1.1\r\n", "hello: World\r\n", "foo: Bar\r\n", - `host: ${addr}\r\n\r\n` + `host: ${addr}\r\n\r\n`, ].join(""); assertEquals(actual, expected); } @@ -394,7 +394,7 @@ unitTest( { // FIXME(bartlomieju) ignore: true, - perms: { net: true } + perms: { net: true }, }, async function fetchPostBodyString(): Promise { const addr = "127.0.0.1:4502"; @@ -404,9 +404,9 @@ unitTest( method: "POST", headers: [ ["Hello", "World"], - ["Foo", "Bar"] + ["Foo", "Bar"], ], - body + body, }); assertEquals(response.status, 404); assertEquals(response.headers.get("Content-Length"), "2"); @@ -418,7 +418,7 @@ unitTest( "foo: Bar\r\n", `host: ${addr}\r\n`, `content-length: ${body.length}\r\n\r\n`, - body + body, ].join(""); assertEquals(actual, expected); } @@ -428,7 +428,7 @@ unitTest( { // FIXME(bartlomieju) ignore: true, - perms: { net: true } + perms: { net: true }, }, async function fetchPostBodyTypedArray(): Promise { const addr = "127.0.0.1:4503"; @@ -439,9 +439,9 @@ unitTest( method: "POST", headers: [ ["Hello", "World"], - ["Foo", "Bar"] + ["Foo", "Bar"], ], - body + body, }); assertEquals(response.status, 404); assertEquals(response.headers.get("Content-Length"), "2"); @@ -453,7 +453,7 @@ unitTest( "foo: Bar\r\n", `host: ${addr}\r\n`, `content-length: ${body.byteLength}\r\n\r\n`, - bodyStr + bodyStr, ].join(""); assertEquals(actual, expected); } @@ -461,11 +461,11 @@ unitTest( unitTest( { - perms: { net: true } + perms: { net: true }, }, async function fetchWithManualRedirection(): Promise { const response = await fetch("http://localhost:4546/", { - redirect: "manual" + redirect: "manual", }); // will redirect to http://localhost:4545/ assertEquals(response.status, 0); assertEquals(response.statusText, ""); @@ -484,11 +484,11 @@ unitTest( unitTest( { - perms: { net: true } + perms: { net: true }, }, async function fetchWithErrorRedirection(): Promise { const response = await fetch("http://localhost:4546/", { - redirect: "error" + redirect: "error", }); // will redirect to http://localhost:4545/ assertEquals(response.status, 0); assertEquals(response.statusText, ""); diff --git a/cli/js/tests/file_test.ts b/cli/js/tests/file_test.ts index 1a7a5f88b9ff06..4941554adbef23 100644 --- a/cli/js/tests/file_test.ts +++ b/cli/js/tests/file_test.ts @@ -58,7 +58,7 @@ unitTest(function fileVariousFileBits(): void { new Blob(), new Uint8Array([0x50, 0x41]), new Uint16Array([0x5353]), - new Uint32Array([0x53534150]) + new Uint32Array([0x53534150]), ], 16 ); diff --git a/cli/js/tests/files_test.ts b/cli/js/tests/files_test.ts index fb1cbd80e3a207..9a1034dc553042 100644 --- a/cli/js/tests/files_test.ts +++ b/cli/js/tests/files_test.ts @@ -3,7 +3,7 @@ import { unitTest, assert, assertEquals, - assertStrContains + assertStrContains, } from "./test_util.ts"; unitTest(function filesStdioFileDescriptors(): void { @@ -46,15 +46,17 @@ unitTest(async function readerToAsyncIterator(): Promise { const encoder = new TextEncoder(); class TestReader implements Deno.Reader { - private offset = 0; - private buf = new Uint8Array(encoder.encode(this.s)); + #offset = 0; + #buf: Uint8Array; - constructor(private readonly s: string) {} + constructor(s: string) { + this.#buf = new Uint8Array(encoder.encode(s)); + } read(p: Uint8Array): Promise { - const n = Math.min(p.byteLength, this.buf.byteLength - this.offset); - p.set(this.buf.slice(this.offset, this.offset + n)); - this.offset += n; + const n = Math.min(p.byteLength, this.#buf.byteLength - this.#offset); + p.set(this.#buf.slice(this.#offset, this.#offset + n)); + this.#offset += n; if (n === 0) { return Promise.resolve(Deno.EOF); @@ -76,14 +78,14 @@ unitTest(async function readerToAsyncIterator(): Promise { unitTest( { - perms: { read: true, write: true } + perms: { read: true, write: true }, }, function openSyncMode(): void { const path = Deno.makeTempDirSync() + "/test_openSync.txt"; const file = Deno.openSync(path, { write: true, createNew: true, - mode: 0o626 + mode: 0o626, }); file.close(); const pathInfo = Deno.statSync(path); @@ -95,14 +97,14 @@ unitTest( unitTest( { - perms: { read: true, write: true } + perms: { read: true, write: true }, }, async function openMode(): Promise { const path = (await Deno.makeTempDir()) + "/test_open.txt"; const file = await Deno.open(path, { write: true, createNew: true, - mode: 0o626 + mode: 0o626, }); file.close(); const pathInfo = Deno.statSync(path); @@ -198,7 +200,7 @@ unitTest( const w = { write: true, truncate: true, - create: true + create: true, }; const file = await Deno.open(filename, w); diff --git a/cli/js/tests/form_data_test.ts b/cli/js/tests/form_data_test.ts index 9b218547c1e0e5..f51a511905faa9 100644 --- a/cli/js/tests/form_data_test.ts +++ b/cli/js/tests/form_data_test.ts @@ -88,7 +88,7 @@ unitTest(function formDataSetEmptyBlobSuccess(): void { unitTest(function formDataParamsForEachSuccess(): void { const init = [ ["a", "54"], - ["b", "true"] + ["b", "true"], ]; const formData = new FormData(); for (const [name, value] of init) { @@ -110,7 +110,7 @@ unitTest(function formDataParamsArgumentsCheck(): void { "getAll", "get", "has", - "forEach" + "forEach", ] as const; const methodRequireTwoParams = ["append", "set"] as const; diff --git a/cli/js/tests/format_error_test.ts b/cli/js/tests/format_error_test.ts index 9831ef160a5a7b..42c16b0c037453 100644 --- a/cli/js/tests/format_error_test.ts +++ b/cli/js/tests/format_error_test.ts @@ -11,8 +11,8 @@ unitTest(function formatDiagnosticBasic() { scriptResourceName: "foo.ts", startColumn: 1, endColumn: 2, - code: 4000 - } + code: 4000, + }, ]; const out = Deno.formatDiagnostics(fixture); assert(out.includes("Example error")); diff --git a/cli/js/tests/fs_events_test.ts b/cli/js/tests/fs_events_test.ts index b1697971ad2299..8494bf6af55503 100644 --- a/cli/js/tests/fs_events_test.ts +++ b/cli/js/tests/fs_events_test.ts @@ -14,6 +14,26 @@ unitTest({ perms: { read: false } }, function fsEventsPermissions() { assert(thrown); }); +unitTest({ perms: { read: true } }, function fsEventsInvalidPath() { + let thrown = false; + try { + Deno.fsEvents("non-existant.file"); + } catch (err) { + console.error(err); + if (Deno.build.os === "win") { + assert( + err.message.includes( + "Input watch path is neither a file nor a directory" + ) + ); + } else { + assert(err instanceof Deno.errors.NotFound); + } + thrown = true; + } + assert(thrown); +}); + async function getTwoEvents( iter: AsyncIterableIterator ): Promise { diff --git a/cli/js/tests/headers_test.ts b/cli/js/tests/headers_test.ts index fcb5385a55017d..1ed58c9a43ffb1 100644 --- a/cli/js/tests/headers_test.ts +++ b/cli/js/tests/headers_test.ts @@ -1,7 +1,7 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. import { unitTest, assert, assertEquals } from "./test_util.ts"; const { - stringifyArgs + stringifyArgs, // @ts-ignore TypeScript (as of 3.7) does not support indexing namespaces by symbol } = Deno[Deno.symbols.internal]; @@ -29,7 +29,7 @@ const headerDict: Record = { name3: "value3", // @ts-ignore name4: undefined, - "Content-Type": "value4" + "Content-Type": "value4", }; // eslint-disable-next-line @typescript-eslint/no-explicit-any const headerSeq: any[] = []; @@ -142,7 +142,7 @@ const headerEntriesDict: Record = { name: "value3", "content-Type": "value4", "Content-Typ": "value5", - "Content-Types": "value6" + "Content-Types": "value6", }; unitTest(function headerForEachSuccess(): void { @@ -346,7 +346,7 @@ unitTest(function customInspectReturnsCorrectHeadersFormat(): void { ); const multiParamHeader = new Headers([ ["Content-Type", "application/json"], - ["Content-Length", "1337"] + ["Content-Length", "1337"], ]); assertEquals( stringify(multiParamHeader), diff --git a/cli/js/tests/internals_test.ts b/cli/js/tests/internals_test.ts index fb712707c69769..b794bb5e8ba563 100644 --- a/cli/js/tests/internals_test.ts +++ b/cli/js/tests/internals_test.ts @@ -3,7 +3,7 @@ import { unitTest, assert } from "./test_util.ts"; unitTest(function internalsExists(): void { const { - stringifyArgs + stringifyArgs, // @ts-ignore TypeScript (as of 3.7) does not support indexing namespaces by symbol } = Deno[Deno.symbols.internal]; assert(!!stringifyArgs); diff --git a/cli/js/tests/net_test.ts b/cli/js/tests/net_test.ts index f27dcdc1953917..6eb0f0dc6f7c45 100644 --- a/cli/js/tests/net_test.ts +++ b/cli/js/tests/net_test.ts @@ -3,12 +3,12 @@ import { unitTest, assert, assertEquals, - createResolvable + createResolvable, } from "./test_util.ts"; unitTest({ perms: { net: true } }, function netTcpListenClose(): void { const listener = Deno.listen({ hostname: "127.0.0.1", port: 4500 }); - assertEquals(listener.addr.transport, "tcp"); + assert(listener.addr.transport === "tcp"); assertEquals(listener.addr.hostname, "127.0.0.1"); assertEquals(listener.addr.port, 4500); listener.close(); @@ -18,24 +18,52 @@ unitTest( { perms: { net: true }, // TODO: - ignore: Deno.build.os === "win" + ignore: Deno.build.os === "win", }, function netUdpListenClose(): void { const socket = Deno.listen({ hostname: "127.0.0.1", port: 4500, - transport: "udp" + transport: "udp", }); - assertEquals(socket.addr.transport, "udp"); + assert(socket.addr.transport === "udp"); assertEquals(socket.addr.hostname, "127.0.0.1"); assertEquals(socket.addr.port, 4500); socket.close(); } ); +unitTest( + { ignore: Deno.build.os === "win", perms: { read: true, write: true } }, + function netUnixListenClose(): void { + const filePath = Deno.makeTempFileSync(); + const socket = Deno.listen({ + address: filePath, + transport: "unix", + }); + assert(socket.addr.transport === "unix"); + assertEquals(socket.addr.address, filePath); + socket.close(); + } +); + +unitTest( + { ignore: Deno.build.os === "win", perms: { read: true, write: true } }, + function netUnixPacketListenClose(): void { + const filePath = Deno.makeTempFileSync(); + const socket = Deno.listen({ + address: filePath, + transport: "unixpacket", + }); + assert(socket.addr.transport === "unixpacket"); + assertEquals(socket.addr.address, filePath); + socket.close(); + } +); + unitTest( { - perms: { net: true } + perms: { net: true }, }, async function netTcpCloseWhileAccept(): Promise { const listener = Deno.listen({ port: 4501 }); @@ -53,6 +81,28 @@ unitTest( } ); +unitTest( + { ignore: Deno.build.os === "win", perms: { read: true, write: true } }, + async function netUnixCloseWhileAccept(): Promise { + const filePath = await Deno.makeTempFile(); + const listener = Deno.listen({ + address: filePath, + transport: "unix", + }); + const p = listener.accept(); + listener.close(); + let err; + try { + await p; + } catch (e) { + err = e; + } + assert(!!err); + assert(err instanceof Error); + assertEquals(err.message, "Listener has been closed"); + } +); + unitTest( { perms: { net: true } }, async function netTcpConcurrentAccept(): Promise { @@ -76,6 +126,31 @@ unitTest( } ); +// TODO(jsouto): Enable when tokio updates mio to v0.7! +unitTest( + { ignore: true, perms: { read: true, write: true } }, + async function netUnixConcurrentAccept(): Promise { + const filePath = await Deno.makeTempFile(); + const listener = Deno.listen({ transport: "unix", address: filePath }); + let acceptErrCount = 0; + const checkErr = (e: Error): void => { + if (e.message === "Listener has been closed") { + assertEquals(acceptErrCount, 1); + } else if (e.message === "Another accept task is ongoing") { + acceptErrCount++; + } else { + throw new Error("Unexpected error message"); + } + }; + const p = listener.accept().catch(checkErr); + const p1 = listener.accept().catch(checkErr); + await Promise.race([p, p1]); + listener.close(); + await [p, p1]; + assertEquals(acceptErrCount, 1); + } +); + unitTest({ perms: { net: true } }, async function netTcpDialListen(): Promise< void > { @@ -83,13 +158,16 @@ unitTest({ perms: { net: true } }, async function netTcpDialListen(): Promise< listener.accept().then( async (conn): Promise => { assert(conn.remoteAddr != null); + assert(conn.localAddr.transport === "tcp"); assertEquals(conn.localAddr.hostname, "127.0.0.1"); assertEquals(conn.localAddr.port, 4500); await conn.write(new Uint8Array([1, 2, 3])); conn.close(); } ); + const conn = await Deno.connect({ hostname: "127.0.0.1", port: 4500 }); + assert(conn.remoteAddr.transport === "tcp"); assertEquals(conn.remoteAddr.hostname, "127.0.0.1"); assertEquals(conn.remoteAddr.port, 4500); assert(conn.localAddr != null); @@ -110,23 +188,60 @@ unitTest({ perms: { net: true } }, async function netTcpDialListen(): Promise< conn.close(); }); +unitTest( + { ignore: Deno.build.os === "win", perms: { read: true, write: true } }, + async function netUnixDialListen(): Promise { + const filePath = await Deno.makeTempFile(); + const listener = Deno.listen({ address: filePath, transport: "unix" }); + listener.accept().then( + async (conn): Promise => { + assert(conn.remoteAddr != null); + assert(conn.localAddr.transport === "unix"); + assertEquals(conn.localAddr.address, filePath); + await conn.write(new Uint8Array([1, 2, 3])); + conn.close(); + } + ); + const conn = await Deno.connect({ address: filePath, transport: "unix" }); + assert(conn.remoteAddr.transport === "unix"); + assertEquals(conn.remoteAddr.address, filePath); + assert(conn.remoteAddr != null); + const buf = new Uint8Array(1024); + const readResult = await conn.read(buf); + assertEquals(3, readResult); + assertEquals(1, buf[0]); + assertEquals(2, buf[1]); + assertEquals(3, buf[2]); + assert(conn.rid > 0); + + assert(readResult !== Deno.EOF); + + const readResult2 = await conn.read(buf); + assertEquals(Deno.EOF, readResult2); + + listener.close(); + conn.close(); + } +); + unitTest( { ignore: Deno.build.os === "win", perms: { net: true } }, async function netUdpSendReceive(): Promise { const alice = Deno.listen({ port: 4500, transport: "udp" }); + assert(alice.addr.transport === "udp"); assertEquals(alice.addr.port, 4500); - assertEquals(alice.addr.hostname, "0.0.0.0"); - assertEquals(alice.addr.transport, "udp"); + assertEquals(alice.addr.hostname, "127.0.0.1"); const bob = Deno.listen({ port: 4501, transport: "udp" }); + assert(bob.addr.transport === "udp"); assertEquals(bob.addr.port, 4501); - assertEquals(bob.addr.hostname, "0.0.0.0"); - assertEquals(bob.addr.transport, "udp"); + assertEquals(bob.addr.hostname, "127.0.0.1"); const sent = new Uint8Array([1, 2, 3]); await alice.send(sent, bob.addr); const [recvd, remote] = await bob.receive(); + assert(remote.transport === "udp"); assertEquals(remote.port, 4500); assertEquals(recvd.length, 3); assertEquals(1, recvd[0]); @@ -137,6 +252,33 @@ unitTest( } ); +unitTest( + { ignore: Deno.build.os === "win", perms: { read: true, write: true } }, + async function netUnixPacketSendReceive(): Promise { + const filePath = await Deno.makeTempFile(); + const alice = Deno.listen({ address: filePath, transport: "unixpacket" }); + assert(alice.addr.transport === "unixpacket"); + assertEquals(alice.addr.address, filePath); + + const bob = Deno.listen({ address: filePath, transport: "unixpacket" }); + assert(bob.addr.transport === "unixpacket"); + assertEquals(bob.addr.address, filePath); + + const sent = new Uint8Array([1, 2, 3]); + await alice.send(sent, bob.addr); + + const [recvd, remote] = await bob.receive(); + assert(remote.transport === "unixpacket"); + assertEquals(remote.address, filePath); + assertEquals(recvd.length, 3); + assertEquals(1, recvd[0]); + assertEquals(2, recvd[1]); + assertEquals(3, recvd[2]); + alice.close(); + bob.close(); + } +); + unitTest( { perms: { net: true } }, async function netTcpListenCloseWhileIterating(): Promise { @@ -163,11 +305,39 @@ unitTest( } ); +unitTest( + { ignore: Deno.build.os === "win", perms: { read: true, write: true } }, + async function netUnixListenCloseWhileIterating(): Promise { + const filePath = Deno.makeTempFileSync(); + const socket = Deno.listen({ address: filePath, transport: "unix" }); + const nextWhileClosing = socket[Symbol.asyncIterator]().next(); + socket.close(); + assertEquals(await nextWhileClosing, { value: undefined, done: true }); + + const nextAfterClosing = socket[Symbol.asyncIterator]().next(); + assertEquals(await nextAfterClosing, { value: undefined, done: true }); + } +); + +unitTest( + { ignore: Deno.build.os === "win", perms: { read: true, write: true } }, + async function netUnixPacketListenCloseWhileIterating(): Promise { + const filePath = Deno.makeTempFileSync(); + const socket = Deno.listen({ address: filePath, transport: "unixpacket" }); + const nextWhileClosing = socket[Symbol.asyncIterator]().next(); + socket.close(); + assertEquals(await nextWhileClosing, { value: undefined, done: true }); + + const nextAfterClosing = socket[Symbol.asyncIterator]().next(); + assertEquals(await nextAfterClosing, { value: undefined, done: true }); + } +); + unitTest( { // FIXME(bartlomieju) ignore: true, - perms: { net: true } + perms: { net: true }, }, async function netListenAsyncIterator(): Promise { const addr = { hostname: "127.0.0.1", port: 4500 }; @@ -202,14 +372,14 @@ unitTest( { // FIXME(bartlomieju) ignore: true, - perms: { net: true } + perms: { net: true }, }, async function netCloseReadSuccess() { const addr = { hostname: "127.0.0.1", port: 4500 }; const listener = Deno.listen(addr); const closeDeferred = createResolvable(); const closeReadDeferred = createResolvable(); - listener.accept().then(async conn => { + listener.accept().then(async (conn) => { await closeReadDeferred; await conn.write(new Uint8Array([1, 2, 3])); const buf = new Uint8Array(1024); @@ -239,13 +409,13 @@ unitTest( { // FIXME(bartlomieju) ignore: true, - perms: { net: true } + perms: { net: true }, }, async function netDoubleCloseRead() { const addr = { hostname: "127.0.0.1", port: 4500 }; const listener = Deno.listen(addr); const closeDeferred = createResolvable(); - listener.accept().then(async conn => { + listener.accept().then(async (conn) => { await conn.write(new Uint8Array([1, 2, 3])); await closeDeferred; conn.close(); @@ -271,13 +441,13 @@ unitTest( { // FIXME(bartlomieju) ignore: true, - perms: { net: true } + perms: { net: true }, }, async function netCloseWriteSuccess() { const addr = { hostname: "127.0.0.1", port: 4500 }; const listener = Deno.listen(addr); const closeDeferred = createResolvable(); - listener.accept().then(async conn => { + listener.accept().then(async (conn) => { await conn.write(new Uint8Array([1, 2, 3])); await closeDeferred; conn.close(); @@ -310,13 +480,13 @@ unitTest( { // FIXME(bartlomieju) ignore: true, - perms: { net: true } + perms: { net: true }, }, async function netDoubleCloseWrite() { const addr = { hostname: "127.0.0.1", port: 4500 }; const listener = Deno.listen(addr); const closeDeferred = createResolvable(); - listener.accept().then(async conn => { + listener.accept().then(async (conn) => { await closeDeferred; conn.close(); }); @@ -339,7 +509,7 @@ unitTest( unitTest( { - perms: { net: true } + perms: { net: true }, }, async function netHangsOnClose() { let acceptedConn: Deno.Conn; diff --git a/cli/js/tests/os_test.ts b/cli/js/tests/os_test.ts index bc1766a2b5f8a0..423cded501dab8 100644 --- a/cli/js/tests/os_test.ts +++ b/cli/js/tests/os_test.ts @@ -4,7 +4,7 @@ import { assertEquals, assertNotEquals, assertThrows, - unitTest + unitTest, } from "./test_util.ts"; unitTest({ perms: { env: true } }, function envSuccess(): void { @@ -65,9 +65,9 @@ unitTest( ${JSON.stringify(Object.keys(expectedEnv))}.map(k => Deno.env(k)) )`; const proc = Deno.run({ - args: [Deno.execPath(), "eval", src], + cmd: [Deno.execPath(), "eval", src], env: inputEnv, - stdout: "piped" + stdout: "piped", }); const status = await proc.status(); assertEquals(status.success, true); @@ -134,121 +134,121 @@ unitTest({ perms: { env: true } }, function getDir(): void { runtime: [ { os: "mac", shouldHaveValue: true }, { os: "win", shouldHaveValue: true }, - { os: "linux", shouldHaveValue: true } - ] + { os: "linux", shouldHaveValue: true }, + ], }, { kind: "cache", runtime: [ { os: "mac", shouldHaveValue: true }, { os: "win", shouldHaveValue: true }, - { os: "linux", shouldHaveValue: true } - ] + { os: "linux", shouldHaveValue: true }, + ], }, { kind: "executable", runtime: [ { os: "mac", shouldHaveValue: false }, { os: "win", shouldHaveValue: false }, - { os: "linux", shouldHaveValue: true } - ] + { os: "linux", shouldHaveValue: true }, + ], }, { kind: "data", runtime: [ { os: "mac", shouldHaveValue: true }, { os: "win", shouldHaveValue: true }, - { os: "linux", shouldHaveValue: true } - ] + { os: "linux", shouldHaveValue: true }, + ], }, { kind: "data_local", runtime: [ { os: "mac", shouldHaveValue: true }, { os: "win", shouldHaveValue: true }, - { os: "linux", shouldHaveValue: true } - ] + { os: "linux", shouldHaveValue: true }, + ], }, { kind: "audio", runtime: [ { os: "mac", shouldHaveValue: true }, { os: "win", shouldHaveValue: true }, - { os: "linux", shouldHaveValue: false } - ] + { os: "linux", shouldHaveValue: false }, + ], }, { kind: "desktop", runtime: [ { os: "mac", shouldHaveValue: true }, { os: "win", shouldHaveValue: true }, - { os: "linux", shouldHaveValue: false } - ] + { os: "linux", shouldHaveValue: false }, + ], }, { kind: "document", runtime: [ { os: "mac", shouldHaveValue: true }, { os: "win", shouldHaveValue: true }, - { os: "linux", shouldHaveValue: false } - ] + { os: "linux", shouldHaveValue: false }, + ], }, { kind: "download", runtime: [ { os: "mac", shouldHaveValue: true }, { os: "win", shouldHaveValue: true }, - { os: "linux", shouldHaveValue: false } - ] + { os: "linux", shouldHaveValue: false }, + ], }, { kind: "font", runtime: [ { os: "mac", shouldHaveValue: true }, { os: "win", shouldHaveValue: false }, - { os: "linux", shouldHaveValue: true } - ] + { os: "linux", shouldHaveValue: true }, + ], }, { kind: "picture", runtime: [ { os: "mac", shouldHaveValue: true }, { os: "win", shouldHaveValue: true }, - { os: "linux", shouldHaveValue: false } - ] + { os: "linux", shouldHaveValue: false }, + ], }, { kind: "public", runtime: [ { os: "mac", shouldHaveValue: true }, { os: "win", shouldHaveValue: true }, - { os: "linux", shouldHaveValue: false } - ] + { os: "linux", shouldHaveValue: false }, + ], }, { kind: "template", runtime: [ { os: "mac", shouldHaveValue: false }, { os: "win", shouldHaveValue: true }, - { os: "linux", shouldHaveValue: false } - ] + { os: "linux", shouldHaveValue: false }, + ], }, { kind: "tmp", runtime: [ { os: "mac", shouldHaveValue: true }, { os: "win", shouldHaveValue: true }, - { os: "linux", shouldHaveValue: true } - ] + { os: "linux", shouldHaveValue: true }, + ], }, { kind: "video", runtime: [ { os: "mac", shouldHaveValue: true }, { os: "win", shouldHaveValue: true }, - { os: "linux", shouldHaveValue: false } - ] - } + { os: "linux", shouldHaveValue: false }, + ], + }, ]; for (const s of scenes) { diff --git a/cli/js/tests/process_test.ts b/cli/js/tests/process_test.ts index e2da6cab59c3f6..47efd86d5af9a9 100644 --- a/cli/js/tests/process_test.ts +++ b/cli/js/tests/process_test.ts @@ -3,14 +3,14 @@ import { assert, assertEquals, assertStrContains, - unitTest + unitTest, } from "./test_util.ts"; const { kill, run, readFile, open, makeTempDir, writeFile } = Deno; unitTest(function runPermissions(): void { let caughtError = false; try { - Deno.run({ args: ["python", "-c", "print('hello world')"] }); + Deno.run({ cmd: ["python", "-c", "print('hello world')"] }); } catch (e) { caughtError = true; assert(e instanceof Deno.errors.PermissionDenied); @@ -20,9 +20,9 @@ unitTest(function runPermissions(): void { unitTest({ perms: { run: true } }, async function runSuccess(): Promise { const p = run({ - args: ["python", "-c", "print('hello world')"], + cmd: ["python", "-c", "print('hello world')"], stdout: "piped", - stderr: "null" + stderr: "null", }); const status = await p.status(); assertEquals(status.success, true); @@ -36,7 +36,7 @@ unitTest( { perms: { run: true } }, async function runCommandFailedWithCode(): Promise { const p = run({ - args: ["python", "-c", "import sys;sys.exit(41 + 1)"] + cmd: ["python", "-c", "import sys;sys.exit(41 + 1)"], }); const status = await p.status(); assertEquals(status.success, false); @@ -50,11 +50,11 @@ unitTest( { // No signals on windows. ignore: Deno.build.os === "win", - perms: { run: true } + perms: { run: true }, }, async function runCommandFailedWithSignal(): Promise { const p = run({ - args: ["python", "-c", "import os;os.kill(os.getpid(), 9)"] + cmd: ["python", "-c", "import os;os.kill(os.getpid(), 9)"], }); const status = await p.status(); assertEquals(status.success, false); @@ -67,7 +67,7 @@ unitTest( unitTest({ perms: { run: true } }, function runNotFound(): void { let error; try { - run({ args: ["this file hopefully doesn't exist"] }); + run({ cmd: ["this file hopefully doesn't exist"] }); } catch (e) { error = e; } @@ -102,7 +102,7 @@ while True: Deno.writeFileSync(`${cwd}/${pyProgramFile}.py`, enc.encode(pyProgram)); const p = run({ cwd, - args: ["python", `${pyProgramFile}.py`] + cmd: ["python", `${pyProgramFile}.py`], }); // Write the expected exit code *after* starting python. @@ -122,8 +122,8 @@ unitTest({ perms: { run: true } }, async function runStdinPiped(): Promise< void > { const p = run({ - args: ["python", "-c", "import sys; assert 'hello' == sys.stdin.read();"], - stdin: "piped" + cmd: ["python", "-c", "import sys; assert 'hello' == sys.stdin.read();"], + stdin: "piped", }); assert(p.stdin); assert(!p.stdout); @@ -146,8 +146,8 @@ unitTest({ perms: { run: true } }, async function runStdoutPiped(): Promise< void > { const p = run({ - args: ["python", "-c", "import sys; sys.stdout.write('hello')"], - stdout: "piped" + cmd: ["python", "-c", "import sys; sys.stdout.write('hello')"], + stdout: "piped", }); assert(!p.stdin); assert(!p.stderr); @@ -175,8 +175,8 @@ unitTest({ perms: { run: true } }, async function runStderrPiped(): Promise< void > { const p = run({ - args: ["python", "-c", "import sys; sys.stderr.write('hello')"], - stderr: "piped" + cmd: ["python", "-c", "import sys; sys.stderr.write('hello')"], + stderr: "piped", }); assert(!p.stdin); assert(!p.stdout); @@ -202,8 +202,8 @@ unitTest({ perms: { run: true } }, async function runStderrPiped(): Promise< unitTest({ perms: { run: true } }, async function runOutput(): Promise { const p = run({ - args: ["python", "-c", "import sys; sys.stdout.write('hello')"], - stdout: "piped" + cmd: ["python", "-c", "import sys; sys.stdout.write('hello')"], + stdout: "piped", }); const output = await p.output(); const s = new TextDecoder().decode(output); @@ -215,8 +215,8 @@ unitTest({ perms: { run: true } }, async function runStderrOutput(): Promise< void > { const p = run({ - args: ["python", "-c", "import sys; sys.stderr.write('error')"], - stderr: "piped" + cmd: ["python", "-c", "import sys; sys.stderr.write('error')"], + stderr: "piped", }); const error = await p.stderrOutput(); const s = new TextDecoder().decode(error); @@ -232,13 +232,13 @@ unitTest( const file = await open(fileName, "w"); const p = run({ - args: [ + cmd: [ "python", "-c", - "import sys; sys.stderr.write('error\\n'); sys.stdout.write('output\\n');" + "import sys; sys.stderr.write('error\\n'); sys.stdout.write('output\\n');", ], stdout: file.rid, - stderr: file.rid + stderr: file.rid, }); await p.status(); @@ -264,8 +264,8 @@ unitTest( const file = await open(fileName, "r"); const p = run({ - args: ["python", "-c", "import sys; assert 'hello' == sys.stdin.read();"], - stdin: file.rid + cmd: ["python", "-c", "import sys; assert 'hello' == sys.stdin.read();"], + stdin: file.rid, }); const status = await p.status(); @@ -277,16 +277,16 @@ unitTest( unitTest({ perms: { run: true } }, async function runEnv(): Promise { const p = run({ - args: [ + cmd: [ "python", "-c", - "import os, sys; sys.stdout.write(os.environ.get('FOO', '') + os.environ.get('BAR', ''))" + "import os, sys; sys.stdout.write(os.environ.get('FOO', '') + os.environ.get('BAR', ''))", ], env: { FOO: "0123", - BAR: "4567" + BAR: "4567", }, - stdout: "piped" + stdout: "piped", }); const output = await p.output(); const s = new TextDecoder().decode(output); @@ -296,12 +296,12 @@ unitTest({ perms: { run: true } }, async function runEnv(): Promise { unitTest({ perms: { run: true } }, async function runClose(): Promise { const p = run({ - args: [ + cmd: [ "python", "-c", - "from time import sleep; import sys; sleep(10000); sys.stderr.write('error')" + "from time import sleep; import sys; sleep(10000); sys.stderr.write('error')", ], - stderr: "piped" + stderr: "piped", }); assert(!p.stdin); assert(!p.stdout); @@ -343,7 +343,7 @@ if (Deno.build.os !== "win") { void > { const p = run({ - args: ["python", "-c", "from time import sleep; sleep(10000)"] + cmd: ["python", "-c", "from time import sleep; sleep(10000)"], }); assertEquals(Deno.Signal.SIGINT, 2); @@ -361,7 +361,7 @@ if (Deno.build.os !== "win") { unitTest({ perms: { run: true } }, function killFailed(): void { const p = run({ - args: ["python", "-c", "from time import sleep; sleep(10000)"] + cmd: ["python", "-c", "from time import sleep; sleep(10000)"], }); assert(!p.stdin); assert(!p.stdout); diff --git a/cli/js/tests/realpath_test.ts b/cli/js/tests/realpath_test.ts index d185e40952f42e..7725a3aa84de33 100644 --- a/cli/js/tests/realpath_test.ts +++ b/cli/js/tests/realpath_test.ts @@ -15,7 +15,7 @@ unitTest({ perms: { read: true } }, function realpathSyncSuccess(): void { unitTest( { ignore: Deno.build.os === "win", - perms: { read: true, write: true } + perms: { read: true, write: true }, }, function realpathSyncSymlink(): void { const testDir = Deno.makeTempDirSync(); @@ -67,7 +67,7 @@ unitTest({ perms: { read: true } }, async function realpathSuccess(): Promise< unitTest( { ignore: Deno.build.os === "win", - perms: { read: true, write: true } + perms: { read: true, write: true }, }, async function realpathSymlink(): Promise { const testDir = Deno.makeTempDirSync(); diff --git a/cli/js/tests/request_test.ts b/cli/js/tests/request_test.ts index 15e19e28532c69..8a276c5e79284b 100644 --- a/cli/js/tests/request_test.ts +++ b/cli/js/tests/request_test.ts @@ -6,8 +6,8 @@ unitTest(function fromInit(): void { body: "ahoyhoy", method: "POST", headers: { - "test-header": "value" - } + "test-header": "value", + }, }); // @ts-ignore @@ -34,7 +34,7 @@ unitTest(async function cloneRequestBodyStream(): Promise { // hack to get a stream const stream = new Request("", { body: "a test body" }).body; const r1 = new Request("https://example.com", { - body: stream + body: stream, }); const r2 = r1.clone(); diff --git a/cli/js/tests/signal_test.ts b/cli/js/tests/signal_test.ts index c966e696b9ed64..a51df09d7843ca 100644 --- a/cli/js/tests/signal_test.ts +++ b/cli/js/tests/signal_test.ts @@ -4,7 +4,7 @@ import { assert, assertEquals, assertThrows, - createResolvable + createResolvable, } from "./test_util.ts"; function defer(n: number): Promise { diff --git a/cli/js/tests/test_util.ts b/cli/js/tests/test_util.ts index 980d32bac403b6..da2e917f8b5d2e 100644 --- a/cli/js/tests/test_util.ts +++ b/cli/js/tests/test_util.ts @@ -10,7 +10,7 @@ export { assertStrictEq, assertStrContains, unreachable, - fail + fail, } from "../../../std/testing/asserts.ts"; export { readLines } from "../../../std/io/bufio.ts"; export { parse as parseArgs } from "../../../std/flags/mod.ts"; @@ -28,7 +28,7 @@ export interface Permissions { export function fmtPerms(perms: Permissions): string { const p = Object.keys(perms) .filter((e): boolean => perms[e as keyof Permissions] === true) - .map(key => `--allow-${key}`); + .map((key) => `--allow-${key}`); if (p.length) { return p.join(" "); @@ -48,7 +48,7 @@ export async function getProcessPermissions(): Promise { net: await isGranted("net"), env: await isGranted("env"), plugin: await isGranted("plugin"), - hrtime: await isGranted("hrtime") + hrtime: await isGranted("hrtime"), }; } @@ -108,7 +108,7 @@ function normalizeTestPermissions(perms: UnitTestPermissions): Permissions { run: !!perms.run, env: !!perms.env, plugin: !!perms.plugin, - hrtime: !!perms.hrtime + hrtime: !!perms.hrtime, }; } @@ -170,7 +170,7 @@ export function unitTest( name, fn, ignore: !!options.ignore, - perms: normalizedPerms + perms: normalizedPerms, }; REGISTERED_UNIT_TESTS.push(unitTestDefinition); @@ -194,17 +194,19 @@ export function createResolvable(): Resolvable { return Object.assign(promise, methods!) as Resolvable; } +const encoder = new TextEncoder(); + export class SocketReporter implements Deno.TestReporter { - private encoder: TextEncoder; + #conn: Deno.Conn; - constructor(private conn: Deno.Conn) { - this.encoder = new TextEncoder(); + constructor(conn: Deno.Conn) { + this.#conn = conn; } // eslint-disable-next-line @typescript-eslint/no-explicit-any async write(msg: any): Promise { - const encodedMsg = this.encoder.encode(JSON.stringify(msg) + "\n"); - await Deno.writeAll(this.conn, encodedMsg); + const encodedMsg = encoder.encode(JSON.stringify(msg) + "\n"); + await Deno.writeAll(this.#conn, encodedMsg); } async start(msg: Deno.TestEventStart): Promise { @@ -229,9 +231,9 @@ export class SocketReporter implements Deno.TestReporter { } async end(msg: Deno.TestEventEnd): Promise { - const encodedMsg = this.encoder.encode(JSON.stringify(msg)); - await Deno.writeAll(this.conn, encodedMsg); - this.conn.closeWrite(); + const encodedMsg = encoder.encode(JSON.stringify(msg)); + await Deno.writeAll(this.#conn, encodedMsg); + this.#conn.closeWrite(); } } @@ -245,7 +247,7 @@ unitTest(function permissionsMatches(): void { env: false, run: false, plugin: false, - hrtime: false + hrtime: false, }, normalizeTestPermissions({ read: true }) ) @@ -260,7 +262,7 @@ unitTest(function permissionsMatches(): void { env: false, run: false, plugin: false, - hrtime: false + hrtime: false, }, normalizeTestPermissions({}) ) @@ -275,7 +277,7 @@ unitTest(function permissionsMatches(): void { env: true, run: true, plugin: true, - hrtime: true + hrtime: true, }, normalizeTestPermissions({ read: true }) ), @@ -291,7 +293,7 @@ unitTest(function permissionsMatches(): void { env: false, run: false, plugin: false, - hrtime: false + hrtime: false, }, normalizeTestPermissions({ read: true }) ), @@ -307,7 +309,7 @@ unitTest(function permissionsMatches(): void { env: true, run: true, plugin: true, - hrtime: true + hrtime: true, }, { read: true, @@ -316,7 +318,7 @@ unitTest(function permissionsMatches(): void { env: true, run: true, plugin: true, - hrtime: true + hrtime: true, } ) ); @@ -330,9 +332,9 @@ unitTest( { perms: { read: true } }, function assertAllUnitTestFilesImported(): void { const directoryTestFiles = Deno.readdirSync("./cli/js/tests/") - .map(k => k.name) + .map((k) => k.name) .filter( - file => + (file) => file!.endsWith(".ts") && !file!.endsWith("unit_tests.ts") && !file!.endsWith("test_util.ts") && @@ -344,12 +346,12 @@ unitTest( const importLines = new TextDecoder("utf-8") .decode(unitTestsFile) .split("\n") - .filter(line => line.startsWith("import")); + .filter((line) => line.startsWith("import")); const importedTestFiles = importLines.map( - relativeFilePath => relativeFilePath.match(/\/([^\/]+)";/)![1] + (relativeFilePath) => relativeFilePath.match(/\/([^\/]+)";/)![1] ); - directoryTestFiles.forEach(dirFile => { + directoryTestFiles.forEach((dirFile) => { if (!importedTestFiles.includes(dirFile!)) { throw new Error( "cil/js/tests/unit_tests.ts is missing import of test file: cli/js/" + diff --git a/cli/js/tests/testing_test.ts b/cli/js/tests/testing_test.ts index 9ed89f53239456..09378ec3045671 100644 --- a/cli/js/tests/testing_test.ts +++ b/cli/js/tests/testing_test.ts @@ -18,7 +18,7 @@ unitTest(function nameOfTestCaseCantBeEmpty(): void { () => { Deno.test({ name: "", - fn: () => {} + fn: () => {}, }); }, TypeError, @@ -29,7 +29,7 @@ unitTest(function nameOfTestCaseCantBeEmpty(): void { unitTest(function testFnCantBeAnonymous(): void { assertThrows( () => { - Deno.test(function() {}); + Deno.test(function () {}); }, TypeError, "The test function can't be anonymous" diff --git a/cli/js/tests/text_encoding_test.ts b/cli/js/tests/text_encoding_test.ts index e85655feb81676..c8a7fbe426ae1e 100644 --- a/cli/js/tests/text_encoding_test.ts +++ b/cli/js/tests/text_encoding_test.ts @@ -21,7 +21,7 @@ unitTest(function atobWithAsciiWhitespace(): void { "aGVsbG8gd29ybGQ=\n", "aGVsbG\t8gd29ybGQ=", `aGVsbG\t8g - d29ybGQ=` + d29ybGQ=`, ]; for (const encoded of encodedList) { diff --git a/cli/js/tests/timers_test.ts b/cli/js/tests/timers_test.ts index b7da6a8471c83d..7adff00959c4f6 100644 --- a/cli/js/tests/timers_test.ts +++ b/cli/js/tests/timers_test.ts @@ -4,7 +4,7 @@ import { createResolvable, assert, assertEquals, - assertNotEquals + assertNotEquals, } from "./test_util.ts"; function deferred(): { @@ -23,7 +23,7 @@ function deferred(): { return { promise, resolve: resolve!, - reject: reject! + reject: reject!, }; } @@ -180,7 +180,7 @@ unitTest(async function timeoutCallbackThis(): Promise { foo(): void { assertEquals(this, window); resolve(); - } + }, }; setTimeout(obj.foo, 1); await promise; @@ -198,7 +198,7 @@ unitTest(async function timeoutBindThis(): Promise { [], "foo", (): void => {}, - Object.prototype + Object.prototype, ]; for (const thisArg of thisCheckPassed) { @@ -240,7 +240,7 @@ unitTest(function clearTimeoutShouldConvertToNumber(): void { valueOf(): number { called = true; return 1; - } + }, }; clearTimeout((obj as unknown) as number); assert(called); @@ -362,3 +362,7 @@ unitTest(async function timerNestedMicrotaskOrdering(): Promise { await promise; assertEquals(s, "0123456789AB"); }); + +unitTest(function testQueueMicrotask() { + assertEquals(typeof queueMicrotask, "function"); +}); diff --git a/cli/js/tests/tls_test.ts b/cli/js/tests/tls_test.ts index 20dd62f9b1ef96..019b816523209f 100644 --- a/cli/js/tests/tls_test.ts +++ b/cli/js/tests/tls_test.ts @@ -3,7 +3,7 @@ import { assert, assertEquals, createResolvable, - unitTest + unitTest, } from "./test_util.ts"; import { BufWriter, BufReader } from "../../../std/io/bufio.ts"; import { TextProtoReader } from "../../../std/textproto/mod.ts"; @@ -28,7 +28,7 @@ unitTest(async function connectTLSCertFileNoReadPerm(): Promise { await Deno.connectTLS({ hostname: "github.com", port: 443, - certFile: "cli/tests/tls/RootCA.crt" + certFile: "cli/tests/tls/RootCA.crt", }); } catch (e) { err = e; @@ -45,13 +45,13 @@ unitTest( hostname: "localhost", port: 4500, certFile: "cli/tests/tls/localhost.crt", - keyFile: "cli/tests/tls/localhost.key" + keyFile: "cli/tests/tls/localhost.key", }; try { Deno.listenTLS({ ...options, - certFile: "./non/existent/file" + certFile: "./non/existent/file", }); } catch (e) { err = e; @@ -61,7 +61,7 @@ unitTest( try { Deno.listenTLS({ ...options, - keyFile: "./non/existent/file" + keyFile: "./non/existent/file", }); } catch (e) { err = e; @@ -77,7 +77,7 @@ unitTest({ perms: { net: true } }, function listenTLSNoReadPerm(): void { hostname: "localhost", port: 4500, certFile: "cli/tests/tls/localhost.crt", - keyFile: "cli/tests/tls/localhost.key" + keyFile: "cli/tests/tls/localhost.key", }); } catch (e) { err = e; @@ -88,7 +88,7 @@ unitTest({ perms: { net: true } }, function listenTLSNoReadPerm(): void { unitTest( { - perms: { read: true, write: true, net: true } + perms: { read: true, write: true, net: true }, }, function listenTLSEmptyKeyFile(): void { let err; @@ -96,19 +96,19 @@ unitTest( hostname: "localhost", port: 4500, certFile: "cli/tests/tls/localhost.crt", - keyFile: "cli/tests/tls/localhost.key" + keyFile: "cli/tests/tls/localhost.key", }; const testDir = Deno.makeTempDirSync(); const keyFilename = testDir + "/key.pem"; Deno.writeFileSync(keyFilename, new Uint8Array([]), { - mode: 0o666 + mode: 0o666, }); try { Deno.listenTLS({ ...options, - keyFile: keyFilename + keyFile: keyFilename, }); } catch (e) { err = e; @@ -125,19 +125,19 @@ unitTest( hostname: "localhost", port: 4500, certFile: "cli/tests/tls/localhost.crt", - keyFile: "cli/tests/tls/localhost.key" + keyFile: "cli/tests/tls/localhost.key", }; const testDir = Deno.makeTempDirSync(); const certFilename = testDir + "/cert.crt"; Deno.writeFileSync(certFilename, new Uint8Array([]), { - mode: 0o666 + mode: 0o666, }); try { Deno.listenTLS({ ...options, - certFile: certFilename + certFile: certFilename, }); } catch (e) { err = e; @@ -157,7 +157,7 @@ unitTest( hostname, port, certFile: "cli/tests/tls/localhost.crt", - keyFile: "cli/tests/tls/localhost.key" + keyFile: "cli/tests/tls/localhost.key", }); const response = encoder.encode( @@ -180,7 +180,7 @@ unitTest( const conn = await Deno.connectTLS({ hostname, port, - certFile: "cli/tests/tls/RootCA.pem" + certFile: "cli/tests/tls/RootCA.pem", }); assert(conn.rid > 0); const w = new BufWriter(conn); diff --git a/cli/js/tests/umask_test.ts b/cli/js/tests/umask_test.ts index e4576c515ed67c..71a5e71f8c5d6c 100644 --- a/cli/js/tests/umask_test.ts +++ b/cli/js/tests/umask_test.ts @@ -3,7 +3,7 @@ import { unitTest, assertEquals } from "./test_util.ts"; unitTest( { - ignore: Deno.build.os === "win" + ignore: Deno.build.os === "win", }, function umaskSuccess(): void { const prevMask = Deno.umask(0o020); diff --git a/cli/js/tests/unit_test_runner.ts b/cli/js/tests/unit_test_runner.ts index 62c3250a791240..8d3eaa4f5ca719 100755 --- a/cli/js/tests/unit_test_runner.ts +++ b/cli/js/tests/unit_test_runner.ts @@ -8,7 +8,7 @@ import { registerUnitTests, SocketReporter, fmtPerms, - parseArgs + parseArgs, } from "./test_util.ts"; interface PermissionSetTestResult { @@ -27,7 +27,7 @@ const PERMISSIONS: Deno.PermissionName[] = [ "env", "run", "plugin", - "hrtime" + "hrtime", ]; /** @@ -69,7 +69,7 @@ async function workerRunnerMain( failFast: false, exitOnFail: false, reporter: socketReporter, - only: filter + only: filter, }); } @@ -86,28 +86,28 @@ function spawnWorkerRunner( }) .join(","); - const args = [ + const cmd = [ Deno.execPath(), "run", "-A", "cli/js/tests/unit_test_runner.ts", "--worker", `--addr=${addr}`, - `--perms=${permStr}` + `--perms=${permStr}`, ]; if (filter) { - args.push("--"); - args.push(filter); + cmd.push("--"); + cmd.push(filter); } const ioMode = verbose ? "inherit" : "null"; const p = Deno.run({ - args, + cmd, stdin: ioMode, stdout: ioMode, - stderr: ioMode + stderr: ioMode, }); return p; @@ -177,7 +177,7 @@ async function runTestsForPermissionSet( permsStr: permsFmt, duration: endEvent.duration, stats: endEvent.stats, - results: endEvent.results + results: endEvent.results, }; } @@ -223,7 +223,7 @@ async function masterRunnerMain( kind: Deno.TestEvent.End, stats, duration, - results + results, }); testsPassed = testsPassed && testResult.passed; } @@ -288,7 +288,7 @@ function assertOrHelp(expr: unknown): asserts expr { async function main(): Promise { const args = parseArgs(Deno.args, { boolean: ["master", "worker", "verbose"], - "--": true + "--": true, }); if (args.help) { @@ -315,7 +315,7 @@ async function main(): Promise { await Deno.runTests({ failFast: false, exitOnFail: true, - only: filter + only: filter, }); } diff --git a/cli/js/tests/url_search_params_test.ts b/cli/js/tests/url_search_params_test.ts index b256395a0f0fcc..3e71d290038e5d 100644 --- a/cli/js/tests/url_search_params_test.ts +++ b/cli/js/tests/url_search_params_test.ts @@ -13,7 +13,7 @@ unitTest(function urlSearchParamsInitString(): void { unitTest(function urlSearchParamsInitIterable(): void { const init = [ ["a", "54"], - ["b", "true"] + ["b", "true"], ]; const searchParams = new URLSearchParams(init); assertEquals(searchParams.toString(), "a=54&b=true"); @@ -94,7 +94,7 @@ unitTest(function urlSearchParamsSortSuccess(): void { unitTest(function urlSearchParamsForEachSuccess(): void { const init = [ ["a", "54"], - ["b", "true"] + ["b", "true"], ]; const searchParams = new URLSearchParams(init); let callNum = 0; @@ -225,7 +225,7 @@ unitTest(function urlSearchParamsDeletingAppendedMultiple(): void { // ref: https://github.com/web-platform-tests/wpt/blob/master/url/urlsearchparams-constructor.any.js#L176-L182 unitTest(function urlSearchParamsCustomSymbolIterator(): void { const params = new URLSearchParams(); - params[Symbol.iterator] = function*(): IterableIterator<[string, string]> { + params[Symbol.iterator] = function* (): IterableIterator<[string, string]> { yield ["a", "b"]; }; const params1 = new URLSearchParams((params as unknown) as string[][]); @@ -236,7 +236,7 @@ unitTest( function urlSearchParamsCustomSymbolIteratorWithNonStringParams(): void { const params = {}; // @ts-ignore - params[Symbol.iterator] = function*(): IterableIterator<[number, number]> { + params[Symbol.iterator] = function* (): IterableIterator<[number, number]> { yield [1, 2]; }; const params1 = new URLSearchParams((params as unknown) as string[][]); diff --git a/cli/js/tests/url_test.ts b/cli/js/tests/url_test.ts index 5b3067e4b4f95e..e1b2d47bdc9f8c 100644 --- a/cli/js/tests/url_test.ts +++ b/cli/js/tests/url_test.ts @@ -98,6 +98,12 @@ unitTest(function urlModifyHref(): void { assertEquals(url.hash, "#qux"); }); +unitTest(function urlNormalize(): void { + const url = new URL("http://example.com"); + assertEquals(url.pathname, "/"); + assertEquals(url.href, "http://example.com/"); +}); + unitTest(function urlModifyPathname(): void { const url = new URL("http://foo.bar/baz%qat/qux%quux"); assertEquals(url.pathname, "/baz%qat/qux%quux"); @@ -183,7 +189,7 @@ unitTest(function sortingNonExistentParamRemovesQuestionMarkFromURL(): void { unitTest( { // FIXME(bartlomieju) - ignore: true + ignore: true, }, function customInspectFunction(): void { const url = new URL("http://example.com/?"); diff --git a/cli/js/tests/utime_test.ts b/cli/js/tests/utime_test.ts index 8cd34d39ab9190..917b8b8b60b811 100644 --- a/cli/js/tests/utime_test.ts +++ b/cli/js/tests/utime_test.ts @@ -15,7 +15,7 @@ unitTest( const testDir = Deno.makeTempDirSync(); const filename = testDir + "/file.txt"; Deno.writeFileSync(filename, new TextEncoder().encode("hello"), { - mode: 0o666 + mode: 0o666, }); const atime = 1000; @@ -115,7 +115,7 @@ unitTest( const testDir = Deno.makeTempDirSync(); const filename = testDir + "/file.txt"; Deno.writeFileSync(filename, new TextEncoder().encode("hello"), { - mode: 0o666 + mode: 0o666, }); const atime = 1000; diff --git a/cli/js/tls.ts b/cli/js/tls.ts index 3ed70727dab5f8..ef87b5aa1c6b9b 100644 --- a/cli/js/tls.ts +++ b/cli/js/tls.ts @@ -1,11 +1,11 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. import * as tlsOps from "./ops/tls.ts"; -import { Listener, Transport, Conn, ConnImpl, ListenerImpl } from "./net.ts"; +import { Listener, Conn, ConnImpl, ListenerImpl } from "./net.ts"; // TODO(ry) There are many configuration options to add... // https://docs.rs/rustls/0.16.0/rustls/struct.ClientConfig.html interface ConnectTLSOptions { - transport?: Transport; + transport?: "tcp"; port: number; hostname?: string; certFile?: string; @@ -15,13 +15,13 @@ export async function connectTLS({ port, hostname = "127.0.0.1", transport = "tcp", - certFile = undefined + certFile = undefined, }: ConnectTLSOptions): Promise { const res = await tlsOps.connectTLS({ port, hostname, transport, - certFile + certFile, }); return new ConnImpl(res.rid, res.remoteAddr!, res.localAddr!); } @@ -36,7 +36,7 @@ class TLSListenerImpl extends ListenerImpl { export interface ListenTLSOptions { port: number; hostname?: string; - transport?: Transport; + transport?: "tcp"; certFile: string; keyFile: string; } @@ -46,14 +46,14 @@ export function listenTLS({ certFile, keyFile, hostname = "0.0.0.0", - transport = "tcp" + transport = "tcp", }: ListenTLSOptions): Listener { const res = tlsOps.listenTLS({ port, certFile, keyFile, hostname, - transport + transport, }); return new TLSListenerImpl(res.rid, res.localAddr); } diff --git a/cli/js/util.ts b/cli/js/util.ts index 692ea6d00b9e99..6db8ade7b87fa1 100644 --- a/cli/js/util.ts +++ b/cli/js/util.ts @@ -67,6 +67,6 @@ export function immutableDefine( Object.defineProperty(o, p, { value, configurable: false, - writable: false + writable: false, }); } diff --git a/cli/js/version.ts b/cli/js/version.ts index 8f7851589e1044..534195ce5e007d 100644 --- a/cli/js/version.ts +++ b/cli/js/version.ts @@ -8,7 +8,7 @@ interface Version { export const version: Version = { deno: "", v8: "", - typescript: "" + typescript: "", }; export function setVersions( diff --git a/cli/js/web/blob.ts b/cli/js/web/blob.ts index 31674a62d51d54..5309ddaf44463f 100644 --- a/cli/js/web/blob.ts +++ b/cli/js/web/blob.ts @@ -124,12 +124,8 @@ function processBlobParts( return bytes; } -// A WeakMap holding blob to byte array mapping. -// Ensures it does not impact garbage collection. -export const blobBytesWeakMap = new WeakMap(); - export class DenoBlob implements domTypes.Blob { - private readonly [bytesSymbol]: Uint8Array; + [bytesSymbol]: Uint8Array; readonly size: number = 0; readonly type: string = ""; @@ -165,14 +161,11 @@ export class DenoBlob implements domTypes.Blob { this[bytesSymbol] = bytes; this.size = bytes.byteLength; this.type = normalizedType; - - // Register bytes for internal private use. - blobBytesWeakMap.set(this, bytes); } slice(start?: number, end?: number, contentType?: string): DenoBlob { return new DenoBlob([this[bytesSymbol].slice(start, end)], { - type: contentType || this.type + type: contentType || this.type, }); } } diff --git a/cli/js/web/body.ts b/cli/js/web/body.ts index 03c35848a74b3e..a16f872b9569d7 100644 --- a/cli/js/web/body.ts +++ b/cli/js/web/body.ts @@ -124,7 +124,7 @@ export const BodyUsedError = "Failed to execute 'clone' on 'Body': body is already used"; export class Body implements domTypes.Body { - protected _stream: domTypes.ReadableStream | null; + protected _stream: domTypes.ReadableStream | null; constructor(protected _bodySource: BodySource, readonly contentType: string) { validateBodyType(this, _bodySource); @@ -148,8 +148,8 @@ export class Body implements domTypes.Body { start(controller: ReadableStreamController): void { controller.enqueue(bodySource); controller.close(); - } - }); + }, + }) as domTypes.ReadableStream; } return this._stream; } @@ -247,7 +247,7 @@ export class Body implements domTypes.Body { if (dispositionParams.has("filename")) { const filename = dispositionParams.get("filename")!; const blob = new DenoBlob([enc.encode(octets)], { - type: partContentType + type: partContentType, }); // TODO: based on spec // https://xhr.spec.whatwg.org/#dom-formdata-append diff --git a/cli/js/web/console.ts b/cli/js/web/console.ts index 0812a4e213d2e2..554c5a1b342f54 100644 --- a/cli/js/web/console.ts +++ b/cli/js/web/console.ts @@ -6,7 +6,7 @@ import { cliTable } from "./console_table.ts"; import { exposeForTest } from "../internals.ts"; type ConsoleContext = Set; -type ConsoleOptions = Partial<{ +type InspectOptions = Partial<{ showHidden: boolean; depth: number; colors: boolean; @@ -16,9 +16,7 @@ type ConsoleOptions = Partial<{ // Default depth of logging nested objects const DEFAULT_MAX_DEPTH = 4; -// Number of elements an object must have before it's displayed in appreviated -// form. -const OBJ_ABBREVIATE_SIZE = 5; +const LINE_BREAKING_LENGTH = 80; const STR_ABBREVIATE_SIZE = 100; @@ -176,7 +174,7 @@ function createArrayString( displayName: "", delims: ["[", "]"], entryHandler: (el, ctx, level, maxLevel): string => - stringifyWithQuotes(el, ctx, level + 1, maxLevel) + stringifyWithQuotes(el, ctx, level + 1, maxLevel), }; return createIterableString(value, ctx, level, maxLevel, printConfig); } @@ -193,7 +191,7 @@ function createTypedArrayString( displayName: typedArrayName, delims: ["[", "]"], entryHandler: (el, ctx, level, maxLevel): string => - stringifyWithQuotes(el, ctx, level + 1, maxLevel) + stringifyWithQuotes(el, ctx, level + 1, maxLevel), }; return createIterableString(value, ctx, level, maxLevel, printConfig); } @@ -209,7 +207,7 @@ function createSetString( displayName: "Set", delims: ["{", "}"], entryHandler: (el, ctx, level, maxLevel): string => - stringifyWithQuotes(el, ctx, level + 1, maxLevel) + stringifyWithQuotes(el, ctx, level + 1, maxLevel), }; return createIterableString(value, ctx, level, maxLevel, printConfig); } @@ -232,7 +230,7 @@ function createMapString( level + 1, maxLevel )} => ${stringifyWithQuotes(val, ctx, level + 1, maxLevel)}`; - } + }, }; return createIterableString(value, ctx, level, maxLevel, printConfig); } @@ -299,37 +297,36 @@ function createRawObjectString( const entries: string[] = []; const stringKeys = Object.keys(value); const symbolKeys = Object.getOwnPropertySymbols(value); - const numKeys = stringKeys.length + symbolKeys.length; - if (numKeys > OBJ_ABBREVIATE_SIZE) { - for (const key of stringKeys) { - entries.push(key); - } - for (const key of symbolKeys) { - entries.push(key.toString()); - } - } else { - for (const key of stringKeys) { - entries.push( - `${key}: ${stringifyWithQuotes(value[key], ctx, level + 1, maxLevel)}` - ); - } - for (const key of symbolKeys) { - entries.push( - `${key.toString()}: ${stringifyWithQuotes( - // @ts-ignore - value[key], - ctx, - level + 1, - maxLevel - )}` - ); - } + + for (const key of stringKeys) { + entries.push( + `${key}: ${stringifyWithQuotes(value[key], ctx, level + 1, maxLevel)}` + ); + } + for (const key of symbolKeys) { + entries.push( + `${key.toString()}: ${stringifyWithQuotes( + // @ts-ignore + value[key], + ctx, + level + 1, + maxLevel + )}` + ); } + const totalLength = entries.length + level + entries.join("").length; + ctx.delete(value); if (entries.length === 0) { baseString = "{}"; + } else if (totalLength > LINE_BREAKING_LENGTH) { + const entryIndent = " ".repeat(level + 1); + const closingIndent = " ".repeat(level); + baseString = `{\n${entryIndent}${entries.join( + `,\n${entryIndent}` + )}\n${closingIndent}}`; } else { baseString = `{ ${entries.join(", ")} }`; } @@ -386,7 +383,7 @@ function createObjectString( export function stringifyArgs( args: unknown[], - { depth = DEFAULT_MAX_DEPTH, indentLevel = 0 }: ConsoleOptions = {} + { depth = DEFAULT_MAX_DEPTH, indentLevel = 0 }: InspectOptions = {} ): string { const first = args[0]; let a = 0; @@ -497,10 +494,12 @@ const timerMap = new Map(); const isConsoleInstance = Symbol("isConsoleInstance"); export class Console { + #printFunc: PrintFunc; indentLevel: number; [isConsoleInstance] = false; - constructor(private printFunc: PrintFunc) { + constructor(printFunc: PrintFunc) { + this.#printFunc = printFunc; this.indentLevel = 0; this[isConsoleInstance] = true; @@ -514,9 +513,9 @@ export class Console { } log = (...args: unknown[]): void => { - this.printFunc( + this.#printFunc( stringifyArgs(args, { - indentLevel: this.indentLevel + indentLevel: this.indentLevel, }) + "\n", false ); @@ -525,16 +524,16 @@ export class Console { debug = this.log; info = this.log; - dir = (obj: unknown, options: ConsoleOptions = {}): void => { - this.printFunc(stringifyArgs([obj], options) + "\n", false); + dir = (obj: unknown, options: InspectOptions = {}): void => { + this.#printFunc(stringifyArgs([obj], options) + "\n", false); }; dirxml = this.dir; warn = (...args: unknown[]): void => { - this.printFunc( + this.#printFunc( stringifyArgs(args, { - indentLevel: this.indentLevel + indentLevel: this.indentLevel, }) + "\n", true ); @@ -607,7 +606,7 @@ export class Console { this.log(cliTable(header, body)); const createColumn = (value: unknown, shift?: number): string[] => [ ...(shift ? [...new Array(shift)].map((): string => "") : []), - stringifyValue(value) + stringifyValue(value), ]; // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -663,8 +662,8 @@ export class Console { indexKey, ...(properties || [ ...headerKeys, - !isMap && values.length > 0 && valuesKey - ]) + !isMap && values.length > 0 && valuesKey, + ]), ].filter(Boolean) as string[]; const body = [indexKeys, ...bodyValues, values]; @@ -736,7 +735,7 @@ export class Console { const message = stringifyArgs(args, { indentLevel: 0 }); const err = { name: "Trace", - message + message, }; // @ts-ignore Error.captureStackTrace(err, this.trace); @@ -752,7 +751,7 @@ export const customInspect = Symbol.for("Deno.customInspect"); export function inspect( value: unknown, - { depth = DEFAULT_MAX_DEPTH }: ConsoleOptions = {} + { depth = DEFAULT_MAX_DEPTH }: InspectOptions = {} ): string { if (typeof value === "string") { return value; diff --git a/cli/js/web/console_table.ts b/cli/js/web/console_table.ts index 7e698f712fabc9..2cb0005d70de24 100644 --- a/cli/js/web/console_table.ts +++ b/cli/js/web/console_table.ts @@ -19,7 +19,7 @@ const tableChars = { rightMiddle: "┤", left: "│ ", right: " │", - middle: " │ " + middle: " │ ", }; const colorRegExp = /\u001b\[\d\d?m/g; diff --git a/cli/js/web/custom_event.ts b/cli/js/web/custom_event.ts index 24a263baf8abab..418b7ea34f701d 100644 --- a/cli/js/web/custom_event.ts +++ b/cli/js/web/custom_event.ts @@ -1,32 +1,31 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. import * as domTypes from "./dom_types.ts"; import * as event from "./event.ts"; -import { getPrivateValue, requiredArguments } from "./util.ts"; - -// WeakMaps are recommended for private attributes (see MDN link below) -// https://developer.mozilla.org/en-US/docs/Archive/Add-ons/Add-on_SDK/Guides/Contributor_s_Guide/Private_Properties#Using_WeakMaps -export const customEventAttributes = new WeakMap(); +import { requiredArguments } from "./util.ts"; export class CustomEvent extends event.Event implements domTypes.CustomEvent { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + #detail: any; + constructor( type: string, customEventInitDict: domTypes.CustomEventInit = {} ) { - requiredArguments("CustomEvent", arguments.length, 1); super(type, customEventInitDict); + requiredArguments("CustomEvent", arguments.length, 1); const { detail = null } = customEventInitDict; - customEventAttributes.set(this, { detail }); + this.#detail = detail; } // eslint-disable-next-line @typescript-eslint/no-explicit-any get detail(): any { - return getPrivateValue(this, customEventAttributes, "detail"); + return this.#detail; } initCustomEvent( - type: string, - bubbles?: boolean, - cancelable?: boolean, + _type: string, + _bubbles?: boolean, + _cancelable?: boolean, // eslint-disable-next-line @typescript-eslint/no-explicit-any detail?: any ): void { @@ -34,7 +33,7 @@ export class CustomEvent extends event.Event implements domTypes.CustomEvent { return; } - customEventAttributes.set(this, { detail }); + this.#detail = detail; } get [Symbol.toStringTag](): string { diff --git a/cli/js/web/dom_iterable.ts b/cli/js/web/dom_iterable.ts index e9be9009fbaedd..191958f111e05d 100644 --- a/cli/js/web/dom_iterable.ts +++ b/cli/js/web/dom_iterable.ts @@ -72,7 +72,7 @@ export function DomIterableMixin( // we want the Base class name to be the name of the class. Object.defineProperty(DomIterable, "name", { value: Base.name, - configurable: true + configurable: true, }); return DomIterable; diff --git a/cli/js/web/dom_types.ts b/cli/js/web/dom_types.ts index bcc6be46844ac6..33cda15820927e 100644 --- a/cli/js/web/dom_types.ts +++ b/cli/js/web/dom_types.ts @@ -68,7 +68,7 @@ interface AbortSignalEventMap { export enum NodeType { ELEMENT_NODE = 1, TEXT_NODE = 3, - DOCUMENT_FRAGMENT_NODE = 11 + DOCUMENT_FRAGMENT_NODE = 11, } export const eventTargetHost: unique symbol = Symbol(); @@ -153,7 +153,7 @@ export enum EventPhase { NONE = 0, CAPTURING_PHASE = 1, AT_TARGET = 2, - BUBBLING_PHASE = 3 + BUBBLING_PHASE = 3, } export interface EventPath { @@ -280,7 +280,7 @@ export interface Blob { } export interface Body { - readonly body: ReadableStream | null; + readonly body: ReadableStream | null; readonly bodyUsed: boolean; arrayBuffer(): Promise; blob(): Promise; @@ -289,11 +289,78 @@ export interface Body { text(): Promise; } -export interface ReadableStream { +export interface ReadableStreamReadDoneResult { + done: true; + value?: T; +} + +export interface ReadableStreamReadValueResult { + done: false; + value: T; +} + +export type ReadableStreamReadResult = + | ReadableStreamReadValueResult + | ReadableStreamReadDoneResult; + +export interface ReadableStreamDefaultReader { + readonly closed: Promise; + cancel(reason?: any): Promise; + read(): Promise>; + releaseLock(): void; +} + +export interface PipeOptions { + preventAbort?: boolean; + preventCancel?: boolean; + preventClose?: boolean; + signal?: AbortSignal; +} + +export interface ReadableStream { readonly locked: boolean; cancel(reason?: any): Promise; - getReader(): ReadableStreamReader; - tee(): ReadableStream[]; + getReader(options: { mode: "byob" }): ReadableStreamBYOBReader; + getReader(): ReadableStreamDefaultReader; + /* disabled for now + pipeThrough( + { + writable, + readable + }: { + writable: WritableStream; + readable: ReadableStream; + }, + options?: PipeOptions + ): ReadableStream; + pipeTo(dest: WritableStream, options?: PipeOptions): Promise; + */ + tee(): [ReadableStream, ReadableStream]; +} + +export interface ReadableStreamBYOBReader { + readonly closed: Promise; + cancel(reason?: any): Promise; + read( + view: T + ): Promise>; + releaseLock(): void; +} + +export interface WritableStream { + readonly locked: boolean; + abort(reason?: any): Promise; + getWriter(): WritableStreamDefaultWriter; +} + +export interface WritableStreamDefaultWriter { + readonly closed: Promise; + readonly desiredSize: number | null; + readonly ready: Promise; + abort(reason?: any): Promise; + close(): Promise; + releaseLock(): void; + write(chunk: W): Promise; } export interface UnderlyingSource { @@ -311,9 +378,9 @@ export interface UnderlyingByteSource { type: "bytes"; } -export interface ReadableStreamReader { - cancel(reason?: any): Promise; - read(): Promise; +export interface ReadableStreamReader { + cancel(reason: any): Promise; + read(): Promise>; releaseLock(): void; } @@ -530,12 +597,20 @@ export interface Response extends Body { clone(): Response; } +export interface DOMStringList { + readonly length: number; + contains(string: string): boolean; + item(index: number): string | null; + [index: number]: string; +} + export interface Location { - readonly ancestorOrigins: string[]; + readonly ancestorOrigins: DOMStringList; hash: string; host: string; hostname: string; href: string; + toString(): string; readonly origin: string; pathname: string; port: string; @@ -543,6 +618,72 @@ export interface Location { search: string; assign(url: string): void; reload(): void; - reload(forcedReload: boolean): void; replace(url: string): void; } + +export interface URL { + hash: string; + host: string; + hostname: string; + href: string; + toString(): string; + readonly origin: string; + password: string; + pathname: string; + port: string; + protocol: string; + search: string; + readonly searchParams: URLSearchParams; + username: string; + toJSON(): string; +} + +export interface URLSearchParams { + /** + * Appends a specified key/value pair as a new search parameter. + */ + append(name: string, value: string): void; + /** + * Deletes the given search parameter, and its associated value, from the list of all search parameters. + */ + delete(name: string): void; + /** + * Returns the first value associated to the given search parameter. + */ + get(name: string): string | null; + /** + * Returns all the values association with a given search parameter. + */ + getAll(name: string): string[]; + /** + * Returns a Boolean indicating if such a search parameter exists. + */ + has(name: string): boolean; + /** + * Sets the value associated to a given search parameter to the given value. If there were several values, delete the others. + */ + set(name: string, value: string): void; + sort(): void; + /** + * Returns a string containing a query string suitable for use in a URL. Does not include the question mark. + */ + toString(): string; + forEach( + callbackfn: (value: string, key: string, parent: URLSearchParams) => void, + thisArg?: any + ): void; + + [Symbol.iterator](): IterableIterator<[string, string]>; + /** + * Returns an array of key, value pairs for every entry in the search params. + */ + entries(): IterableIterator<[string, string]>; + /** + * Returns a list of keys in the search params. + */ + keys(): IterableIterator; + /** + * Returns a list of values in the search params. + */ + values(): IterableIterator; +} diff --git a/cli/js/web/dom_util.ts b/cli/js/web/dom_util.ts index 5780d9c523ecfd..40a8c618f6423b 100644 --- a/cli/js/web/dom_util.ts +++ b/cli/js/web/dom_util.ts @@ -2,6 +2,23 @@ // Utility functions for DOM nodes import * as domTypes from "./dom_types.ts"; +export function getDOMStringList(arr: string[]): domTypes.DOMStringList { + Object.defineProperties(arr, { + contains: { + value(searchElement: string): boolean { + return arr.includes(searchElement); + }, + enumerable: true, + }, + item: { + value(idx: number): string | null { + return idx in arr ? arr[idx] : null; + }, + }, + }); + return (arr as unknown) as domTypes.DOMStringList; +} + export function isNode(nodeImpl: domTypes.EventTarget | null): boolean { return Boolean(nodeImpl && "nodeType" in nodeImpl); } diff --git a/cli/js/web/event.ts b/cli/js/web/event.ts index ef5c4d1755d1cf..b063efa6005052 100644 --- a/cli/js/web/event.ts +++ b/cli/js/web/event.ts @@ -39,11 +39,11 @@ export class Event implements domTypes.Event { isTrusted: false, relatedTarget: null, target: null, - timeStamp: Date.now() + timeStamp: Date.now(), }); Reflect.defineProperty(this, "isTrusted", { enumerable: true, - get: isTrusted + get: isTrusted, }); } @@ -90,7 +90,7 @@ export class Event implements domTypes.Event { isTrusted: this.isTrusted, relatedTarget: this.relatedTarget, target: this.target, - timeStamp: this.timeStamp + timeStamp: this.timeStamp, }); } @@ -121,7 +121,7 @@ export class Event implements domTypes.Event { isTrusted: this.isTrusted, relatedTarget: this.relatedTarget, target: this.target, - timeStamp: this.timeStamp + timeStamp: this.timeStamp, }); } @@ -156,7 +156,7 @@ export class Event implements domTypes.Event { isTrusted: this.isTrusted, relatedTarget: value, target: this.target, - timeStamp: this.timeStamp + timeStamp: this.timeStamp, }); } @@ -175,7 +175,7 @@ export class Event implements domTypes.Event { isTrusted: this.isTrusted, relatedTarget: this.relatedTarget, target: value, - timeStamp: this.timeStamp + timeStamp: this.timeStamp, }); } @@ -200,8 +200,8 @@ export class Event implements domTypes.Event { rootOfClosedTree: false, slotInClosedTree: false, target: null, - touchTargetList: [] - } + touchTargetList: [], + }, ]; let currentTargetIndex = 0; @@ -242,7 +242,7 @@ export class Event implements domTypes.Event { rootOfClosedTree: false, slotInClosedTree: false, target: null, - touchTargetList: [] + touchTargetList: [], }); } @@ -277,7 +277,7 @@ export class Event implements domTypes.Event { rootOfClosedTree: false, slotInClosedTree: false, target: null, - touchTargetList: [] + touchTargetList: [], }); } @@ -314,7 +314,7 @@ Reflect.defineProperty(Event.prototype, "cancelable", { enumerable: true }); Reflect.defineProperty(Event.prototype, "composed", { enumerable: true }); Reflect.defineProperty(Event.prototype, "currentTarget", { enumerable: true }); Reflect.defineProperty(Event.prototype, "defaultPrevented", { - enumerable: true + enumerable: true, }); Reflect.defineProperty(Event.prototype, "dispatched", { enumerable: true }); Reflect.defineProperty(Event.prototype, "eventPhase", { enumerable: true }); diff --git a/cli/js/web/event_target.ts b/cli/js/web/event_target.ts index 7fe26441d06e8a..605504a3a87a94 100644 --- a/cli/js/web/event_target.ts +++ b/cli/js/web/event_target.ts @@ -7,7 +7,7 @@ import { isShadowRoot, isShadowInclusiveAncestor, isSlotable, - retarget + retarget, } from "./dom_util.ts"; // https://dom.spec.whatwg.org/#get-the-parent @@ -70,7 +70,7 @@ export class EventTarget implements domTypes.EventTarget { listeners[type].push({ callback, - options: normalizedOptions + options: normalizedOptions, }); } @@ -438,7 +438,7 @@ const eventTargetHelpers = { const returnValue: domTypes.AddEventListenerOptions = { capture: Boolean(options), once: false, - passive: false + passive: false, }; return returnValue; @@ -452,7 +452,7 @@ const eventTargetHelpers = { ): domTypes.EventListenerOptions { if (typeof options === "boolean" || typeof options === "undefined") { const returnValue: domTypes.EventListenerOptions = { - capture: Boolean(options) + capture: Boolean(options), }; return returnValue; @@ -481,17 +481,17 @@ const eventTargetHelpers = { relatedTarget, touchTargetList: touchTargets, rootOfClosedTree, - slotInClosedTree + slotInClosedTree, }); - } + }, }; Reflect.defineProperty(EventTarget.prototype, "addEventListener", { - enumerable: true + enumerable: true, }); Reflect.defineProperty(EventTarget.prototype, "removeEventListener", { - enumerable: true + enumerable: true, }); Reflect.defineProperty(EventTarget.prototype, "dispatchEvent", { - enumerable: true + enumerable: true, }); diff --git a/cli/js/web/fetch.ts b/cli/js/web/fetch.ts index 62e5d7928712f2..6438838c76e9f0 100644 --- a/cli/js/web/fetch.ts +++ b/cli/js/web/fetch.ts @@ -32,53 +32,58 @@ function hasHeaderValueOf(s: string, value: string): boolean { return new RegExp(`^${value}[\t\s]*;?`).test(s); } -class Body implements domTypes.Body, domTypes.ReadableStream, io.ReadCloser { - private _bodyUsed = false; - private _bodyPromise: null | Promise = null; - private _data: ArrayBuffer | null = null; +class Body + implements domTypes.Body, domTypes.ReadableStream, io.ReadCloser { + #bodyUsed = false; + #bodyPromise: Promise | null = null; + #data: ArrayBuffer | null = null; + #rid: number; readonly locked: boolean = false; // TODO - readonly body: null | Body = this; + readonly body: domTypes.ReadableStream; - constructor(private rid: number, readonly contentType: string) {} + constructor(rid: number, readonly contentType: string) { + this.#rid = rid; + this.body = this; + } - private async _bodyBuffer(): Promise { - assert(this._bodyPromise == null); + #bodyBuffer = async (): Promise => { + assert(this.#bodyPromise == null); const buf = new Buffer(); try { const nread = await buf.readFrom(this); const ui8 = buf.bytes(); assert(ui8.byteLength === nread); - this._data = ui8.buffer.slice( + this.#data = ui8.buffer.slice( ui8.byteOffset, ui8.byteOffset + nread ) as ArrayBuffer; - assert(this._data.byteLength === nread); + assert(this.#data.byteLength === nread); } finally { this.close(); } - return this._data; - } + return this.#data; + }; // eslint-disable-next-line require-await async arrayBuffer(): Promise { // If we've already bufferred the response, just return it. - if (this._data != null) { - return this._data; + if (this.#data != null) { + return this.#data; } // If there is no _bodyPromise yet, start it. - if (this._bodyPromise == null) { - this._bodyPromise = this._bodyBuffer(); + if (this.#bodyPromise == null) { + this.#bodyPromise = this.#bodyBuffer(); } - return this._bodyPromise; + return this.#bodyPromise; } async blob(): Promise { const arrayBuffer = await this.arrayBuffer(); return new DenoBlob([arrayBuffer], { - type: this.contentType + type: this.contentType, }); } @@ -164,7 +169,7 @@ class Body implements domTypes.Body, domTypes.ReadableStream, io.ReadCloser { if (dispositionParams.has("filename")) { const filename = dispositionParams.get("filename")!; const blob = new DenoBlob([enc.encode(octets)], { - type: partContentType + type: partContentType, }); // TODO: based on spec // https://xhr.spec.whatwg.org/#dom-formdata-append @@ -220,12 +225,12 @@ class Body implements domTypes.Body, domTypes.ReadableStream, io.ReadCloser { } read(p: Uint8Array): Promise { - this._bodyUsed = true; - return read(this.rid, p); + this.#bodyUsed = true; + return read(this.#rid, p); } close(): Promise { - close(this.rid); + close(this.#rid); return Promise.resolve(); } @@ -233,7 +238,11 @@ class Body implements domTypes.Body, domTypes.ReadableStream, io.ReadCloser { return notImplemented(); } - getReader(): domTypes.ReadableStreamReader { + getReader(options: { mode: "byob" }): domTypes.ReadableStreamBYOBReader; + getReader(): domTypes.ReadableStreamDefaultReader; + getReader(): + | domTypes.ReadableStreamBYOBReader + | domTypes.ReadableStreamDefaultReader { return notImplemented(); } @@ -246,7 +255,24 @@ class Body implements domTypes.Body, domTypes.ReadableStream, io.ReadCloser { } get bodyUsed(): boolean { - return this._bodyUsed; + return this.#bodyUsed; + } + + pipeThrough( + _: { + writable: domTypes.WritableStream; + readable: domTypes.ReadableStream; + }, + _options?: domTypes.PipeOptions + ): domTypes.ReadableStream { + return notImplemented(); + } + + pipeTo( + _dest: domTypes.WritableStream, + _options?: domTypes.PipeOptions + ): Promise { + return notImplemented(); } } @@ -255,7 +281,7 @@ export class Response implements domTypes.Response { readonly redirected: boolean; headers: domTypes.Headers; readonly trailer: Promise; - readonly body: null | Body; + readonly body: Body | null; constructor( readonly url: string, @@ -308,7 +334,7 @@ export class Response implements domTypes.Response { "Content-Type", "Expires", "Last-Modified", - "Pragma" + "Pragma", ].map((c: string) => c.toLowerCase()); for (const h of this.headers) { /* Technically this is still not standards compliant because we are @@ -337,35 +363,36 @@ export class Response implements domTypes.Response { this.redirected = redirected_; } - private bodyViewable(): boolean { + #bodyViewable = (): boolean => { if ( this.type == "error" || this.type == "opaque" || this.type == "opaqueredirect" || this.body == undefined - ) + ) { return true; + } return false; - } + }; arrayBuffer(): Promise { /* You have to do the null check here and not in the function because * otherwise TS complains about this.body potentially being null */ - if (this.bodyViewable() || this.body == null) { + if (this.#bodyViewable() || this.body == null) { return Promise.reject(new Error("Response body is null")); } return this.body.arrayBuffer(); } blob(): Promise { - if (this.bodyViewable() || this.body == null) { + if (this.#bodyViewable() || this.body == null) { return Promise.reject(new Error("Response body is null")); } return this.body.blob(); } formData(): Promise { - if (this.bodyViewable() || this.body == null) { + if (this.#bodyViewable() || this.body == null) { return Promise.reject(new Error("Response body is null")); } return this.body.formData(); @@ -373,14 +400,14 @@ export class Response implements domTypes.Response { // eslint-disable-next-line @typescript-eslint/no-explicit-any json(): Promise { - if (this.bodyViewable() || this.body == null) { + if (this.#bodyViewable() || this.body == null) { return Promise.reject(new Error("Response body is null")); } return this.body.json(); } text(): Promise { - if (this.bodyViewable() || this.body == null) { + if (this.#bodyViewable() || this.body == null) { return Promise.reject(new Error("Response body is null")); } return this.body.text(); @@ -453,7 +480,7 @@ function sendFetchReq( const args = { method, url, - headers: headerArray + headers: headerArray, }; return opFetch(args, body); @@ -527,8 +554,9 @@ export async function fetch( } part += "\r\n"; if (fieldValue instanceof DomFileImpl) { - part += `Content-Type: ${fieldValue.type || - "application/octet-stream"}\r\n`; + part += `Content-Type: ${ + fieldValue.type || "application/octet-stream" + }\r\n`; } part += "\r\n"; if (fieldValue instanceof DomFileImpl) { diff --git a/cli/js/web/form_data.ts b/cli/js/web/form_data.ts index f60a146d9f0181..db5d24ad444a71 100644 --- a/cli/js/web/form_data.ts +++ b/cli/js/web/form_data.ts @@ -8,7 +8,7 @@ import { requiredArguments } from "./util.ts"; const dataSymbol = Symbol("data"); class FormDataBase { - private [dataSymbol]: Array<[string, domTypes.FormDataEntryValue]> = []; + [dataSymbol]: Array<[string, domTypes.FormDataEntryValue]> = []; append(name: string, value: string): void; append(name: string, value: blob.DenoBlob, filename?: string): void; @@ -17,7 +17,7 @@ class FormDataBase { name = String(name); if (value instanceof blob.DenoBlob) { const dfile = new domFile.DomFileImpl([value], filename || name, { - type: value.type + type: value.type, }); this[dataSymbol].push([name, dfile]); } else { @@ -84,7 +84,7 @@ class FormDataBase { if (!found) { if (value instanceof blob.DenoBlob) { const dfile = new domFile.DomFileImpl([value], filename || name, { - type: value.type + type: value.type, }); this[dataSymbol][i][1] = dfile; } else { @@ -103,7 +103,7 @@ class FormDataBase { if (!found) { if (value instanceof blob.DenoBlob) { const dfile = new domFile.DomFileImpl([value], filename || name, { - type: value.type + type: value.type, }); this[dataSymbol].push([name, dfile]); } else { diff --git a/cli/js/web/headers.ts b/cli/js/web/headers.ts index 9ff59422489619..e1d81393d865c2 100644 --- a/cli/js/web/headers.ts +++ b/cli/js/web/headers.ts @@ -17,32 +17,32 @@ function isHeaders(value: any): value is domTypes.Headers { const headerMap = Symbol("header map"); -// ref: https://fetch.spec.whatwg.org/#dom-headers -class HeadersBase { - private [headerMap]: Map; - // TODO: headerGuard? Investigate if it is needed - // node-fetch did not implement this but it is in the spec - - private _normalizeParams(name: string, value?: string): string[] { - name = String(name).toLowerCase(); - value = String(value).trim(); - return [name, value]; - } +// TODO: headerGuard? Investigate if it is needed +// node-fetch did not implement this but it is in the spec +function normalizeParams(name: string, value?: string): string[] { + name = String(name).toLowerCase(); + value = String(value).trim(); + return [name, value]; +} - // The following name/value validations are copied from - // https://github.com/bitinn/node-fetch/blob/master/src/headers.js - // Copyright (c) 2016 David Frank. MIT License. - private _validateName(name: string): void { - if (invalidTokenRegex.test(name) || name === "") { - throw new TypeError(`${name} is not a legal HTTP header name`); - } +// The following name/value validations are copied from +// https://github.com/bitinn/node-fetch/blob/master/src/headers.js +// Copyright (c) 2016 David Frank. MIT License. +function validateName(name: string): void { + if (invalidTokenRegex.test(name) || name === "") { + throw new TypeError(`${name} is not a legal HTTP header name`); } +} - private _validateValue(value: string): void { - if (invalidHeaderCharRegex.test(value)) { - throw new TypeError(`${value} is not a legal HTTP header value`); - } +function validateValue(value: string): void { + if (invalidHeaderCharRegex.test(value)) { + throw new TypeError(`${value} is not a legal HTTP header value`); } +} + +// ref: https://fetch.spec.whatwg.org/#dom-headers +class HeadersBase { + [headerMap]: Map; constructor(init?: domTypes.HeadersInit) { if (init === null) { @@ -64,9 +64,9 @@ class HeadersBase { 2 ); - const [name, value] = this._normalizeParams(tuple[0], tuple[1]); - this._validateName(name); - this._validateValue(value); + const [name, value] = normalizeParams(tuple[0], tuple[1]); + validateName(name); + validateValue(value); const existingValue = this[headerMap].get(name); this[headerMap].set( name, @@ -77,9 +77,9 @@ class HeadersBase { const names = Object.keys(init); for (const rawName of names) { const rawValue = init[rawName]; - const [name, value] = this._normalizeParams(rawName, rawValue); - this._validateName(name); - this._validateValue(value); + const [name, value] = normalizeParams(rawName, rawValue); + validateName(name); + validateValue(value); this[headerMap].set(name, value); } } @@ -101,9 +101,9 @@ class HeadersBase { // ref: https://fetch.spec.whatwg.org/#concept-headers-append append(name: string, value: string): void { requiredArguments("Headers.append", arguments.length, 2); - const [newname, newvalue] = this._normalizeParams(name, value); - this._validateName(newname); - this._validateValue(newvalue); + const [newname, newvalue] = normalizeParams(name, value); + validateName(newname); + validateValue(newvalue); const v = this[headerMap].get(newname); const str = v ? `${v}, ${newvalue}` : newvalue; this[headerMap].set(newname, str); @@ -111,31 +111,31 @@ class HeadersBase { delete(name: string): void { requiredArguments("Headers.delete", arguments.length, 1); - const [newname] = this._normalizeParams(name); - this._validateName(newname); + const [newname] = normalizeParams(name); + validateName(newname); this[headerMap].delete(newname); } get(name: string): string | null { requiredArguments("Headers.get", arguments.length, 1); - const [newname] = this._normalizeParams(name); - this._validateName(newname); + const [newname] = normalizeParams(name); + validateName(newname); const value = this[headerMap].get(newname); return value || null; } has(name: string): boolean { requiredArguments("Headers.has", arguments.length, 1); - const [newname] = this._normalizeParams(name); - this._validateName(newname); + const [newname] = normalizeParams(name); + validateName(newname); return this[headerMap].has(newname); } set(name: string, value: string): void { requiredArguments("Headers.set", arguments.length, 2); - const [newname, newvalue] = this._normalizeParams(name, value); - this._validateName(newname); - this._validateValue(newvalue); + const [newname, newvalue] = normalizeParams(name, value); + validateName(newname); + validateValue(newvalue); this[headerMap].set(newname, newvalue); } diff --git a/cli/js/web/location.ts b/cli/js/web/location.ts index d48cce3c78bb34..862a4c1e49fc76 100644 --- a/cli/js/web/location.ts +++ b/cli/js/web/location.ts @@ -1,12 +1,15 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. import { URL } from "./url.ts"; import { notImplemented } from "../util.ts"; -import { Location } from "./dom_types.ts"; +import { DOMStringList, Location } from "./dom_types.ts"; +import { getDOMStringList } from "./dom_util.ts"; export class LocationImpl implements Location { + #url: URL; + constructor(url: string) { const u = new URL(url); - this.url = u; + this.#url = u; this.hash = u.hash; this.host = u.host; this.href = u.href; @@ -18,13 +21,11 @@ export class LocationImpl implements Location { this.search = u.search; } - private url: URL; - toString(): string { - return this.url.toString(); + return this.#url.toString(); } - readonly ancestorOrigins: string[] = []; + readonly ancestorOrigins: DOMStringList = getDOMStringList([]); hash: string; host: string; hostname: string; @@ -45,6 +46,8 @@ export class LocationImpl implements Location { } } +/** Sets the `window.location` at runtime. + * @internal */ export function setLocation(url: string): void { globalThis.location = new LocationImpl(url); Object.freeze(globalThis.location); diff --git a/cli/js/web/request.ts b/cli/js/web/request.ts index 8afc35e7a2f591..96edaf59e3d946 100644 --- a/cli/js/web/request.ts +++ b/cli/js/web/request.ts @@ -136,7 +136,7 @@ export class Request extends body.Body implements domTypes.Request { body: body2, method: this.method, headers: new Headers(headersList), - credentials: this.credentials + credentials: this.credentials, }); return cloned; } diff --git a/cli/js/web/streams/readable-byte-stream-controller.ts b/cli/js/web/streams/readable-byte-stream-controller.ts index 8067b5d35edfdf..1b473b77acfadb 100644 --- a/cli/js/web/streams/readable-byte-stream-controller.ts +++ b/cli/js/web/streams/readable-byte-stream-controller.ts @@ -148,7 +148,7 @@ export class ReadableByteStreamController bytesFilled: 0, elementSize: 1, ctor: Uint8Array, - readerType: "default" + readerType: "default", }; this[rs.pendingPullIntos_].push(pullIntoDescriptor); } diff --git a/cli/js/web/streams/readable-internals.ts b/cli/js/web/streams/readable-internals.ts index b96262ef752ce8..f46c79850421f7 100644 --- a/cli/js/web/streams/readable-internals.ts +++ b/cli/js/web/streams/readable-internals.ts @@ -10,7 +10,7 @@ import { QueuingStrategy, QueuingStrategySizeCallback, UnderlyingSource, - UnderlyingByteSource + UnderlyingByteSource, } from "../dom_types.ts"; // ReadableStreamDefaultController @@ -345,7 +345,7 @@ export function readableStreamCancel( const sourceCancelPromise = stream[readableStreamController_][cancelSteps_]( reason ); - return sourceCancelPromise.then(_ => undefined); + return sourceCancelPromise.then((_) => undefined); } export function readableStreamClose( @@ -558,13 +558,13 @@ export function setUpReadableStreamDefaultController( const startResult = startAlgorithm(); Promise.resolve(startResult).then( - _ => { + (_) => { controller[started_] = true; // Assert: controller.[[pulling]] is false. // Assert: controller.[[pullAgain]] is false. readableStreamDefaultControllerCallPullIfNeeded(controller); }, - error => { + (error) => { readableStreamDefaultControllerError(controller, error); } ); @@ -678,14 +678,14 @@ export function readableStreamDefaultControllerCallPullIfNeeded( controller[pulling_] = true; controller[pullAlgorithm_](controller).then( - _ => { + (_) => { controller[pulling_] = false; if (controller[pullAgain_]) { controller[pullAgain_] = false; readableStreamDefaultControllerCallPullIfNeeded(controller); } }, - error => { + (error) => { readableStreamDefaultControllerError(controller, error); } ); @@ -768,13 +768,13 @@ export function setUpReadableByteStreamController( // Let startResult be the result of performing startAlgorithm. const startResult = startAlgorithm(); Promise.resolve(startResult).then( - _ => { + (_) => { controller[started_] = true; // Assert: controller.[[pulling]] is false. // Assert: controller.[[pullAgain]] is false. readableByteStreamControllerCallPullIfNeeded(controller); }, - error => { + (error) => { readableByteStreamControllerError(controller, error); } ); @@ -811,14 +811,14 @@ export function readableByteStreamControllerCallPullIfNeeded( // Assert: controller.[[pullAgain]] is false. controller[pulling_] = true; controller[pullAlgorithm_](controller).then( - _ => { + (_) => { controller[pulling_] = false; if (controller[pullAgain_]) { controller[pullAgain_] = false; readableByteStreamControllerCallPullIfNeeded(controller); } }, - error => { + (error) => { readableByteStreamControllerError(controller, error); } ); @@ -1122,7 +1122,7 @@ export function readableByteStreamControllerPullInto( bytesFilled: 0, elementSize, ctor, - readerType: "byob" + readerType: "byob", }; if (controller[pendingPullIntos_].length > 0) { diff --git a/cli/js/web/streams/readable-stream.ts b/cli/js/web/streams/readable-stream.ts index e062c278e2524f..50753260d37fe5 100644 --- a/cli/js/web/streams/readable-stream.ts +++ b/cli/js/web/streams/readable-stream.ts @@ -11,18 +11,18 @@ import { QueuingStrategy, QueuingStrategySizeCallback, UnderlyingSource, - UnderlyingByteSource + UnderlyingByteSource, } from "../dom_types.ts"; import { ReadableStreamDefaultController, - setUpReadableStreamDefaultControllerFromUnderlyingSource + setUpReadableStreamDefaultControllerFromUnderlyingSource, } from "./readable-stream-default-controller.ts"; import { ReadableStreamDefaultReader } from "./readable-stream-default-reader.ts"; import { ReadableByteStreamController, - setUpReadableByteStreamControllerFromUnderlyingSource + setUpReadableByteStreamControllerFromUnderlyingSource, } from "./readable-byte-stream-controller.ts"; import { SDReadableStreamBYOBReader } from "./readable-stream-byob-reader.ts"; @@ -123,7 +123,7 @@ export class SDReadableStream return rs.readableStreamCancel(this, reason); } - tee(): Array> { + tee(): [SDReadableStream, SDReadableStream] { return readableStreamTee(this, false); } @@ -280,7 +280,9 @@ export function readableStreamTee( let branch2: SDReadableStream; let cancelResolve: (reason: shared.ErrorResult) => void; - const cancelPromise = new Promise(resolve => (cancelResolve = resolve)); + const cancelPromise = new Promise( + (resolve) => (cancelResolve = resolve) + ); const pullAlgorithm = (): Promise => { return rs @@ -362,7 +364,7 @@ export function readableStreamTee( cancel2Algorithm ); - reader[rs.closedPromise_].promise.catch(error => { + reader[rs.closedPromise_].promise.catch((error) => { if (!closedOrErrored) { rs.readableStreamDefaultControllerError( branch1![ diff --git a/cli/js/web/streams/shared-internals.ts b/cli/js/web/streams/shared-internals.ts index 3d802b083f513f..7b0de22748ee69 100644 --- a/cli/js/web/streams/shared-internals.ts +++ b/cli/js/web/streams/shared-internals.ts @@ -223,7 +223,7 @@ export function createAlgorithmFromUnderlyingMethod< if (typeof method !== "function") { throw new TypeError(`Field "${methodName}" is not a function.`); } - return function(...fnArgs: any[]): any { + return function (...fnArgs: any[]): any { return promiseCall(method, obj, fnArgs.concat(extraArgs)); }; } @@ -252,7 +252,7 @@ export function makeSizeAlgorithmFromSizeFunction( if (typeof sizeFn !== "function" && typeof sizeFn !== "undefined") { throw new TypeError("size function must be undefined or a function"); } - return function(chunk: T): number { + return function (chunk: T): number { if (typeof sizeFn === "function") { return sizeFn(chunk); } @@ -265,7 +265,7 @@ export function makeSizeAlgorithmFromSizeFunction( export const enum ControlledPromiseState { Pending, Resolved, - Rejected + Rejected, } export interface ControlledPromise { @@ -277,14 +277,14 @@ export interface ControlledPromise { export function createControlledPromise(): ControlledPromise { const conProm = { - state: ControlledPromiseState.Pending + state: ControlledPromiseState.Pending, } as ControlledPromise; - conProm.promise = new Promise(function(resolve, reject) { - conProm.resolve = function(v?: V): void { + conProm.promise = new Promise(function (resolve, reject) { + conProm.resolve = function (v?: V): void { conProm.state = ControlledPromiseState.Resolved; resolve(v); }; - conProm.reject = function(e?: ErrorResult): void { + conProm.reject = function (e?: ErrorResult): void { conProm.state = ControlledPromiseState.Rejected; reject(e); }; diff --git a/cli/js/web/text_encoding.ts b/cli/js/web/text_encoding.ts index 5f04972aa86ad0..6fd498e5967c5b 100644 --- a/cli/js/web/text_encoding.ts +++ b/cli/js/web/text_encoding.ts @@ -149,8 +149,8 @@ interface Encoder { } class SingleByteDecoder implements Decoder { - private _index: number[]; - private _fatal: boolean; + #index: number[]; + #fatal: boolean; constructor( index: number[], @@ -159,20 +159,20 @@ class SingleByteDecoder implements Decoder { if (ignoreBOM) { throw new TypeError("Ignoring the BOM is available only with utf-8."); } - this._fatal = fatal; - this._index = index; + this.#fatal = fatal; + this.#index = index; } - handler(stream: Stream, byte: number): number { + handler(_stream: Stream, byte: number): number { if (byte === END_OF_STREAM) { return FINISHED; } if (isASCIIByte(byte)) { return byte; } - const codePoint = this._index[byte - 0x80]; + const codePoint = this.#index[byte - 0x80]; if (codePoint == null) { - return decoderError(this._fatal); + return decoderError(this.#fatal); } return codePoint; @@ -199,9 +199,9 @@ const encodingMap: { [key: string]: string[] } = { "latin1", "us-ascii", "windows-1252", - "x-cp1252" + "x-cp1252", ], - "utf-8": ["unicode-1-1-utf-8", "utf-8", "utf8"] + "utf-8": ["unicode-1-1-utf-8", "utf-8", "utf8"], }; // We convert these into a Map where every label resolves to its canonical // encoding type. @@ -221,13 +221,134 @@ const decoders = new Map Decoder>(); const encodingIndexes = new Map(); // prettier-ignore encodingIndexes.set("windows-1252", [ - 8364,129,8218,402,8222,8230,8224,8225,710,8240,352,8249,338,141,381,143,144, - 8216,8217,8220,8221,8226,8211,8212,732,8482,353,8250,339,157,382,376,160,161, - 162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180, - 181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199, - 200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218, - 219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237, - 238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 + 8364, + 129, + 8218, + 402, + 8222, + 8230, + 8224, + 8225, + 710, + 8240, + 352, + 8249, + 338, + 141, + 381, + 143, + 144, + 8216, + 8217, + 8220, + 8221, + 8226, + 8211, + 8212, + 732, + 8482, + 353, + 8250, + 339, + 157, + 382, + 376, + 160, + 161, + 162, + 163, + 164, + 165, + 166, + 167, + 168, + 169, + 170, + 171, + 172, + 173, + 174, + 175, + 176, + 177, + 178, + 179, + 180, + 181, + 182, + 183, + 184, + 185, + 186, + 187, + 188, + 189, + 190, + 191, + 192, + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 209, + 210, + 211, + 212, + 213, + 214, + 215, + 216, + 217, + 218, + 219, + 220, + 221, + 222, + 223, + 224, + 225, + 226, + 227, + 228, + 229, + 230, + 231, + 232, + 233, + 234, + 235, + 236, + 237, + 238, + 239, + 240, + 241, + 242, + 243, + 244, + 245, + 246, + 247, + 248, + 249, + 250, + 251, + 252, + 253, + 254, + 255 ]); for (const [key, index] of encodingIndexes) { decoders.set( @@ -247,37 +368,37 @@ function codePointsToString(codePoints: number[]): string { } class Stream { - private _tokens: number[]; + #tokens: number[]; constructor(tokens: number[] | Uint8Array) { - this._tokens = [].slice.call(tokens); - this._tokens.reverse(); + this.#tokens = [...tokens]; + this.#tokens.reverse(); } endOfStream(): boolean { - return !this._tokens.length; + return !this.#tokens.length; } read(): number { - return !this._tokens.length ? END_OF_STREAM : this._tokens.pop()!; + return !this.#tokens.length ? END_OF_STREAM : this.#tokens.pop()!; } prepend(token: number | number[]): void { if (Array.isArray(token)) { while (token.length) { - this._tokens.push(token.pop()!); + this.#tokens.push(token.pop()!); } } else { - this._tokens.push(token); + this.#tokens.push(token); } } push(token: number | number[]): void { if (Array.isArray(token)) { while (token.length) { - this._tokens.unshift(token.shift()!); + this.#tokens.unshift(token.shift()!); } } else { - this._tokens.unshift(token); + this.#tokens.unshift(token); } } } @@ -299,10 +420,10 @@ function isEitherArrayBuffer(x: any): x is EitherArrayBuffer { } export class TextDecoder { - private _encoding: string; + #encoding: string; get encoding(): string { - return this._encoding; + return this.#encoding; } readonly fatal: boolean = false; readonly ignoreBOM: boolean = false; @@ -314,9 +435,7 @@ export class TextDecoder { if (options.fatal) { this.fatal = true; } - label = String(label) - .trim() - .toLowerCase(); + label = String(label).trim().toLowerCase(); const encoding = encodings.get(label); if (!encoding) { throw new RangeError( @@ -326,7 +445,7 @@ export class TextDecoder { if (!decoders.has(encoding) && encoding !== "utf-8") { throw new TypeError(`Internal decoder ('${encoding}') not found.`); } - this._encoding = encoding; + this.#encoding = encoding; } decode( @@ -354,7 +473,7 @@ export class TextDecoder { // For simple utf-8 decoding "Deno.core.decode" can be used for performance if ( - this._encoding === "utf-8" && + this.#encoding === "utf-8" && this.fatal === false && this.ignoreBOM === false ) { @@ -363,13 +482,13 @@ export class TextDecoder { // For performance reasons we utilise a highly optimised decoder instead of // the general decoder. - if (this._encoding === "utf-8") { + if (this.#encoding === "utf-8") { return decodeUtf8(bytes, this.fatal, this.ignoreBOM); } - const decoder = decoders.get(this._encoding)!({ + const decoder = decoders.get(this.#encoding)!({ fatal: this.fatal, - ignoreBOM: this.ignoreBOM + ignoreBOM: this.ignoreBOM, }); const inputStream = new Stream(bytes); const output: number[] = []; @@ -455,7 +574,7 @@ export class TextEncoder { return { read, - written + written, }; } get [Symbol.toStringTag](): string { diff --git a/cli/js/web/timers.ts b/cli/js/web/timers.ts index 9a957f3fe538e9..ff18543faef2f9 100644 --- a/cli/js/web/timers.ts +++ b/cli/js/web/timers.ts @@ -223,7 +223,7 @@ function setTimer( delay, due: now + delay, repeat, - scheduled: false + scheduled: false, }; // Register the timer's existence in the id-to-timer map. idMap.set(timer.id, timer); diff --git a/cli/js/web/url.ts b/cli/js/web/url.ts index 6ef6b367cdaa71..2b6a0d341df3b0 100644 --- a/cli/js/web/url.ts +++ b/cli/js/web/url.ts @@ -1,8 +1,8 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import * as urlSearchParams from "./url_search_params.ts"; +import { customInspect } from "./console.ts"; import * as domTypes from "./dom_types.ts"; +import { urls, URLSearchParams } from "./url_search_params.ts"; import { getRandomValues } from "../ops/get_random_values.ts"; -import { customInspect } from "./console.ts"; interface URLParts { protocol: string; @@ -24,7 +24,7 @@ const patterns = { authentication: "(?:([^:]*)(?::([^@]*))?@)", hostname: "([^:]+)", - port: "(?::(\\d+))" + port: "(?::(\\d+))", }; const urlRegExp = new RegExp( @@ -35,10 +35,10 @@ const authorityRegExp = new RegExp( `^${patterns.authentication}?${patterns.hostname}${patterns.port}?$` ); -const searchParamsMethods: Array = [ +const searchParamsMethods: Array = [ "append", "delete", - "set" + "set", ]; function parse(url: string): URLParts | undefined { @@ -57,7 +57,7 @@ function parse(url: string): URLParts | undefined { port: authorityMatch[4] || "", path: urlMatch[3] || "", query: urlMatch[4] || "", - hash: urlMatch[5] || "" + hash: urlMatch[5] || "", }; } } @@ -136,9 +136,11 @@ function resolvePathFromBase(path: string, basePath: string): string { return normalizePath(prefix + suffix); } -export class URL { - private _parts: URLParts; - private _searchParams!: urlSearchParams.URLSearchParams; +/** @internal */ +export const parts = new WeakMap(); + +export class URL implements domTypes.URL { + #searchParams!: URLSearchParams; [customInspect](): string { const keys = [ @@ -152,7 +154,7 @@ export class URL { "port", "pathname", "hash", - "search" + "search", ]; const objectString = keys .map((key: string) => `${key}: "${this[key as keyof this] || ""}"`) @@ -160,8 +162,8 @@ export class URL { return `URL { ${objectString} }`; } - private _updateSearchParams(): void { - const searchParams = new urlSearchParams.URLSearchParams(this.search); + #updateSearchParams = (): void => { + const searchParams = new URLSearchParams(this.search); for (const methodName of searchParamsMethods) { /* eslint-disable @typescript-eslint/no-explicit-any */ @@ -172,27 +174,25 @@ export class URL { }; /* eslint-enable */ } - this._searchParams = searchParams; + this.#searchParams = searchParams; - // convert to `any` that has avoided the private limit - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (this._searchParams as any).url = this; - } + urls.set(searchParams, this); + }; get hash(): string { - return this._parts.hash; + return parts.get(this)!.hash; } set hash(value: string) { value = unescape(String(value)); if (!value) { - this._parts.hash = ""; + parts.get(this)!.hash = ""; } else { if (value.charAt(0) !== "#") { value = `#${value}`; } // hashes can contain % and # unescaped - this._parts.hash = escape(value) + parts.get(this)!.hash = escape(value) .replace(/%25/g, "%") .replace(/%23/g, "#"); } @@ -205,17 +205,17 @@ export class URL { set host(value: string) { value = String(value); const url = new URL(`http://${value}`); - this._parts.hostname = url.hostname; - this._parts.port = url.port; + parts.get(this)!.hostname = url.hostname; + parts.get(this)!.port = url.port; } get hostname(): string { - return this._parts.hostname; + return parts.get(this)!.hostname; } set hostname(value: string) { value = String(value); - this._parts.hostname = encodeURIComponent(value); + parts.get(this)!.hostname = encodeURIComponent(value); } get href(): string { @@ -234,8 +234,8 @@ export class URL { value = String(value); if (value !== this.href) { const url = new URL(value); - this._parts = { ...url._parts }; - this._updateSearchParams(); + parts.set(this, { ...parts.get(url)! }); + this.#updateSearchParams(); } } @@ -247,16 +247,16 @@ export class URL { } get password(): string { - return this._parts.password; + return parts.get(this)!.password; } set password(value: string) { value = String(value); - this._parts.password = encodeURIComponent(value); + parts.get(this)!.password = encodeURIComponent(value); } get pathname(): string { - return this._parts.path ? this._parts.path : "/"; + return parts.get(this)?.path || "/"; } set pathname(value: string) { @@ -265,22 +265,22 @@ export class URL { value = `/${value}`; } // paths can contain % unescaped - this._parts.path = escape(value).replace(/%25/g, "%"); + parts.get(this)!.path = escape(value).replace(/%25/g, "%"); } get port(): string { - return this._parts.port; + return parts.get(this)!.port; } set port(value: string) { const port = parseInt(String(value), 10); - this._parts.port = isNaN(port) + parts.get(this)!.port = isNaN(port) ? "" : Math.max(0, port % 2 ** 16).toString(); } get protocol(): string { - return `${this._parts.protocol}:`; + return `${parts.get(this)!.protocol}:`; } set protocol(value: string) { @@ -289,16 +289,17 @@ export class URL { if (value.charAt(value.length - 1) === ":") { value = value.slice(0, -1); } - this._parts.protocol = encodeURIComponent(value); + parts.get(this)!.protocol = encodeURIComponent(value); } } get search(): string { - if (this._parts.query === null || this._parts.query === "") { + const query = parts.get(this)!.query; + if (query === null || query === "") { return ""; } - return this._parts.query; + return query; } set search(value: string) { @@ -313,27 +314,27 @@ export class URL { query = value; } - this._parts.query = query; - this._updateSearchParams(); + parts.get(this)!.query = query; + this.#updateSearchParams(); } get username(): string { - return this._parts.username; + return parts.get(this)!.username; } set username(value: string) { value = String(value); - this._parts.username = encodeURIComponent(value); + parts.get(this)!.username = encodeURIComponent(value); } - get searchParams(): urlSearchParams.URLSearchParams { - return this._searchParams; + get searchParams(): URLSearchParams { + return this.#searchParams; } constructor(url: string, base?: string | URL) { let baseParts: URLParts | undefined; if (base) { - baseParts = typeof base === "string" ? parse(base) : base._parts; + baseParts = typeof base === "string" ? parse(base) : parts.get(base); if (!baseParts || baseParts.protocol == "") { throw new TypeError("Invalid base URL."); } @@ -345,9 +346,9 @@ export class URL { } if (urlParts.protocol) { - this._parts = urlParts; + parts.set(this, urlParts); } else if (baseParts) { - this._parts = { + parts.set(this, { protocol: baseParts.protocol, username: baseParts.username, password: baseParts.password, @@ -355,12 +356,12 @@ export class URL { port: baseParts.port, path: resolvePathFromBase(urlParts.path, baseParts.path || "/"), query: urlParts.query, - hash: urlParts.hash - }; + hash: urlParts.hash, + }); } else { throw new TypeError("URL requires a base URL."); } - this._updateSearchParams(); + this.#updateSearchParams(); } toString(): string { diff --git a/cli/js/web/url_search_params.ts b/cli/js/web/url_search_params.ts index 8f60f291889419..aad59bb8c5d0fe 100644 --- a/cli/js/web/url_search_params.ts +++ b/cli/js/web/url_search_params.ts @@ -1,33 +1,61 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { URL } from "./url.ts"; -import { requiredArguments } from "./util.ts"; - -// Returns whether o is iterable. -// @internal -export function isIterable( - o: T -): o is T & Iterable<[P, K]> { - // checks for null and undefined - if (o == null) { - return false; - } - return ( - typeof ((o as unknown) as Iterable<[P, K]>)[Symbol.iterator] === "function" - ); +import * as domTypes from "./dom_types.ts"; +import { URL, parts } from "./url.ts"; +import { isIterable, requiredArguments } from "./util.ts"; + +/** @internal */ +export const urls = new WeakMap(); + +function handleStringInitialization( + searchParams: URLSearchParams, + init: string +): void { + // Overload: USVString + // If init is a string and starts with U+003F (?), + // remove the first code point from init. + if (init.charCodeAt(0) === 0x003f) { + init = init.slice(1); + } + + for (const pair of init.split("&")) { + // Empty params are ignored + if (pair.length === 0) { + continue; + } + const position = pair.indexOf("="); + const name = pair.slice(0, position === -1 ? pair.length : position); + const value = pair.slice(name.length + 1); + searchParams.append(decodeURIComponent(name), decodeURIComponent(value)); + } +} + +function handleArrayInitialization( + searchParams: URLSearchParams, + init: string[][] | Iterable<[string, string]> +): void { + // Overload: sequence> + for (const tuple of init) { + // If pair does not contain exactly two items, then throw a TypeError. + if (tuple.length !== 2) { + throw new TypeError( + "URLSearchParams.constructor tuple array argument must only contain pair elements" + ); + } + searchParams.append(tuple[0], tuple[1]); + } } -export class URLSearchParams { - private params: Array<[string, string]> = []; - private url: URL | null = null; +export class URLSearchParams implements domTypes.URLSearchParams { + #params: Array<[string, string]> = []; constructor(init: string | string[][] | Record = "") { if (typeof init === "string") { - this._handleStringInitialization(init); + handleStringInitialization(this, init); return; } if (Array.isArray(init) || isIterable(init)) { - this._handleArrayInitialization(init); + handleArrayInitialization(this, init); return; } @@ -36,7 +64,7 @@ export class URLSearchParams { } if (init instanceof URLSearchParams) { - this.params = init.params; + this.#params = [...init.#params]; return; } @@ -44,10 +72,13 @@ export class URLSearchParams { for (const key of Object.keys(init)) { this.append(key, init[key]); } + + urls.set(this, null); } - private updateSteps(): void { - if (this.url === null) { + #updateSteps = (): void => { + const url = urls.get(this); + if (url == null) { return; } @@ -56,35 +87,34 @@ export class URLSearchParams { query = null; } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (this.url as any)._parts.query = query; - } + parts.get(url)!.query = query; + }; append(name: string, value: string): void { requiredArguments("URLSearchParams.append", arguments.length, 2); - this.params.push([String(name), String(value)]); - this.updateSteps(); + this.#params.push([String(name), String(value)]); + this.#updateSteps(); } delete(name: string): void { requiredArguments("URLSearchParams.delete", arguments.length, 1); name = String(name); let i = 0; - while (i < this.params.length) { - if (this.params[i][0] === name) { - this.params.splice(i, 1); + while (i < this.#params.length) { + if (this.#params[i][0] === name) { + this.#params.splice(i, 1); } else { i++; } } - this.updateSteps(); + this.#updateSteps(); } getAll(name: string): string[] { requiredArguments("URLSearchParams.getAll", arguments.length, 1); name = String(name); const values = []; - for (const entry of this.params) { + for (const entry of this.#params) { if (entry[0] === name) { values.push(entry[1]); } @@ -96,7 +126,7 @@ export class URLSearchParams { get(name: string): string | null { requiredArguments("URLSearchParams.get", arguments.length, 1); name = String(name); - for (const entry of this.params) { + for (const entry of this.#params) { if (entry[0] === name) { return entry[1]; } @@ -108,7 +138,7 @@ export class URLSearchParams { has(name: string): boolean { requiredArguments("URLSearchParams.has", arguments.length, 1); name = String(name); - return this.params.some((entry): boolean => entry[0] === name); + return this.#params.some((entry) => entry[0] === name); } set(name: string, value: string): void { @@ -121,14 +151,14 @@ export class URLSearchParams { value = String(value); let found = false; let i = 0; - while (i < this.params.length) { - if (this.params[i][0] === name) { + while (i < this.#params.length) { + if (this.#params[i][0] === name) { if (!found) { - this.params[i][1] = value; + this.#params[i][1] = value; found = true; i++; } else { - this.params.splice(i, 1); + this.#params.splice(i, 1); } } else { i++; @@ -141,14 +171,12 @@ export class URLSearchParams { this.append(name, value); } - this.updateSteps(); + this.#updateSteps(); } sort(): void { - this.params = this.params.sort((a, b): number => - a[0] === b[0] ? 0 : a[0] > b[0] ? 1 : -1 - ); - this.updateSteps(); + this.#params.sort((a, b) => (a[0] === b[0] ? 0 : a[0] > b[0] ? 1 : -1)); + this.#updateSteps(); } forEach( @@ -168,66 +196,31 @@ export class URLSearchParams { } *keys(): IterableIterator { - for (const entry of this.params) { - yield entry[0]; + for (const [key] of this.#params) { + yield key; } } *values(): IterableIterator { - for (const entry of this.params) { - yield entry[1]; + for (const [, value] of this.#params) { + yield value; } } *entries(): IterableIterator<[string, string]> { - yield* this.params; + yield* this.#params; } *[Symbol.iterator](): IterableIterator<[string, string]> { - yield* this.params; + yield* this.#params; } toString(): string { - return this.params + return this.#params .map( - (tuple): string => + (tuple) => `${encodeURIComponent(tuple[0])}=${encodeURIComponent(tuple[1])}` ) .join("&"); } - - private _handleStringInitialization(init: string): void { - // Overload: USVString - // If init is a string and starts with U+003F (?), - // remove the first code point from init. - if (init.charCodeAt(0) === 0x003f) { - init = init.slice(1); - } - - for (const pair of init.split("&")) { - // Empty params are ignored - if (pair.length === 0) { - continue; - } - const position = pair.indexOf("="); - const name = pair.slice(0, position === -1 ? pair.length : position); - const value = pair.slice(name.length + 1); - this.append(decodeURIComponent(name), decodeURIComponent(value)); - } - } - - private _handleArrayInitialization( - init: string[][] | Iterable<[string, string]> - ): void { - // Overload: sequence> - for (const tuple of init) { - // If pair does not contain exactly two items, then throw a TypeError. - if (tuple.length !== 2) { - throw new TypeError( - "URLSearchParams.constructor tuple array argument must only contain pair elements" - ); - } - this.append(tuple[0], tuple[1]); - } - } } diff --git a/cli/js/web/util.ts b/cli/js/web/util.ts index 8d248ce1ffe5c0..19a30a6753341a 100644 --- a/cli/js/web/util.ts +++ b/cli/js/web/util.ts @@ -31,7 +31,7 @@ export function immutableDefine( Object.defineProperty(o, p, { value, configurable: false, - writable: false + writable: false, }); } @@ -53,3 +53,18 @@ export function hasOwnProperty(obj: T, v: PropertyKey): boolean { } return Object.prototype.hasOwnProperty.call(obj, v); } + +/** Returns whether o is iterable. + * + * @internal */ +export function isIterable( + o: T +): o is T & Iterable<[P, K]> { + // checks for null and undefined + if (o == null) { + return false; + } + return ( + typeof ((o as unknown) as Iterable<[P, K]>)[Symbol.iterator] === "function" + ); +} diff --git a/cli/js/web/workers.ts b/cli/js/web/workers.ts index 256090d57a3fca..834d0f29785488 100644 --- a/cli/js/web/workers.ts +++ b/cli/js/web/workers.ts @@ -4,13 +4,12 @@ import { createWorker, hostTerminateWorker, hostPostMessage, - hostGetMessage + hostGetMessage, } from "../ops/worker_host.ts"; import { log } from "../util.ts"; import { TextDecoder, TextEncoder } from "./text_encoding.ts"; /* import { blobURLMap } from "./web/url.ts"; -import { blobBytesWeakMap } from "./web/blob.ts"; */ import { Event } from "./event.ts"; import { EventTarget } from "./event_target.ts"; @@ -48,13 +47,13 @@ export interface WorkerOptions { } export class WorkerImpl extends EventTarget implements Worker { - private readonly id: number; - private isClosing = false; + readonly #id: number; + #name: string; + #terminated = false; + public onerror?: (e: any) => void; public onmessage?: (data: any) => void; public onmessageerror?: () => void; - private name: string; - private terminated = false; constructor(specifier: string, options?: WorkerOptions) { super(); @@ -66,7 +65,7 @@ export class WorkerImpl extends EventTarget implements Worker { ); } - this.name = name; + this.#name = name; const hasSourceCode = false; const sourceCode = decoder.decode(new Uint8Array()); @@ -92,11 +91,11 @@ export class WorkerImpl extends EventTarget implements Worker { sourceCode, options?.name ); - this.id = id; + this.#id = id; this.poll(); } - private handleError(e: any): boolean { + #handleError = (e: any): boolean => { // TODO: this is being handled in a type unsafe way, it should be type safe // eslint-disable-next-line @typescript-eslint/no-explicit-any const event = new Event("error", { cancelable: true }) as any; @@ -115,14 +114,14 @@ export class WorkerImpl extends EventTarget implements Worker { } return handled; - } + }; async poll(): Promise { - while (!this.terminated) { - const event = await hostGetMessage(this.id); + while (!this.#terminated) { + const event = await hostGetMessage(this.#id); // If terminate was called then we ignore all messages - if (this.terminated) { + if (this.#terminated) { return; } @@ -137,15 +136,15 @@ export class WorkerImpl extends EventTarget implements Worker { } if (type === "error") { - if (!this.handleError(event.error)) { + if (!this.#handleError(event.error)) { throw Error(event.error.message); } continue; } if (type === "close") { - log(`Host got "close" message from worker: ${this.name}`); - this.terminated = true; + log(`Host got "close" message from worker: ${this.#name}`); + this.#terminated = true; return; } @@ -154,17 +153,17 @@ export class WorkerImpl extends EventTarget implements Worker { } postMessage(data: any): void { - if (this.terminated) { + if (this.#terminated) { return; } - hostPostMessage(this.id, encodeMessage(data)); + hostPostMessage(this.#id, encodeMessage(data)); } terminate(): void { - if (!this.terminated) { - this.terminated = true; - hostTerminateWorker(this.id); + if (!this.#terminated) { + this.#terminated = true; + hostTerminateWorker(this.#id); } } } diff --git a/cli/lib.rs b/cli/lib.rs index c6bbe0b68f78b4..11ab26626bc12c 100644 --- a/cli/lib.rs +++ b/cli/lib.rs @@ -14,6 +14,8 @@ extern crate indexmap; #[cfg(unix)] extern crate nix; extern crate rand; +extern crate regex; +extern crate reqwest; extern crate serde; extern crate serde_derive; extern crate tokio; @@ -25,6 +27,7 @@ pub mod compilers; pub mod deno_dir; pub mod diagnostics; mod disk_cache; +mod doc; mod file_fetcher; pub mod flags; mod fmt; @@ -35,6 +38,7 @@ mod global_timer; pub mod http_cache; mod http_util; mod import_map; +mod inspector; pub mod installer; mod js; mod lockfile; @@ -52,6 +56,7 @@ pub mod state; mod test_runner; pub mod test_util; mod tokio_util; +mod upgrade; pub mod version; mod web_worker; pub mod worker; @@ -75,6 +80,7 @@ use log::Record; use std::env; use std::io::Write; use std::path::PathBuf; +use upgrade::upgrade_command; use url::Url; static LOGGER: Logger = Logger; @@ -106,6 +112,18 @@ impl log::Log for Logger { fn flush(&self) {} } +fn write_to_stdout_ignore_sigpipe(bytes: &[u8]) -> Result<(), std::io::Error> { + use std::io::ErrorKind; + + match std::io::stdout().write_all(bytes) { + Ok(()) => Ok(()), + Err(e) => match e.kind() { + ErrorKind::BrokenPipe => Ok(()), + _ => Err(e), + }, + } +} + fn create_main_worker( global_state: GlobalState, main_module: ModuleSpecifier, @@ -339,6 +357,57 @@ async fn bundle_command( bundle_result } +async fn doc_command( + flags: Flags, + source_file: String, + json: bool, + maybe_filter: Option, +) -> Result<(), ErrBox> { + let global_state = GlobalState::new(flags.clone())?; + let module_specifier = + ModuleSpecifier::resolve_url_or_path(&source_file).unwrap(); + let source_file = global_state + .file_fetcher + .fetch_source_file(&module_specifier, None) + .await?; + let source_code = String::from_utf8(source_file.source_code)?; + + let doc_parser = doc::DocParser::default(); + let parse_result = + doc_parser.parse(module_specifier.to_string(), source_code); + + let doc_nodes = match parse_result { + Ok(nodes) => nodes, + Err(e) => { + eprintln!("Failed to parse documentation:"); + for diagnostic in e { + eprintln!("{}", diagnostic.message()); + } + + std::process::exit(1); + } + }; + + if json { + let writer = std::io::BufWriter::new(std::io::stdout()); + serde_json::to_writer_pretty(writer, &doc_nodes).map_err(ErrBox::from) + } else { + let details = if let Some(filter) = maybe_filter { + let node = doc::find_node_by_name_recursively(doc_nodes, filter.clone()); + if let Some(node) = node { + doc::printer::format_details(node) + } else { + eprintln!("Node {} was not found!", filter); + std::process::exit(1); + } + } else { + doc::printer::format(doc_nodes) + }; + + write_to_stdout_ignore_sigpipe(details.as_bytes()).map_err(ErrBox::from) + } +} + async fn run_repl(flags: Flags) -> Result<(), ErrBox> { let main_module = ModuleSpecifier::resolve_url_or_path("./__$deno$repl.ts").unwrap(); @@ -446,6 +515,11 @@ pub fn main() { source_file, out_file, } => bundle_command(flags, source_file, out_file).boxed_local(), + DenoSubcommand::Doc { + source_file, + json, + filter, + } => doc_command(flags, source_file, json, filter).boxed_local(), DenoSubcommand::Eval { code, as_typescript, @@ -473,7 +547,10 @@ pub fn main() { allow_none, } => test_command(flags, include, fail_fast, allow_none).boxed_local(), DenoSubcommand::Completions { buf } => { - print!("{}", std::str::from_utf8(&buf).unwrap()); + if let Err(e) = write_to_stdout_ignore_sigpipe(&buf) { + eprintln!("{}", e); + std::process::exit(1); + } return; } DenoSubcommand::Types => { @@ -483,10 +560,15 @@ pub fn main() { crate::js::SHARED_GLOBALS_LIB, crate::js::WINDOW_LIB ); - // TODO(ry) Only ignore SIGPIPE. Currently ignoring all errors. - let _r = std::io::stdout().write_all(types.as_bytes()); + if let Err(e) = write_to_stdout_ignore_sigpipe(types.as_bytes()) { + eprintln!("{}", e); + std::process::exit(1); + } return; } + DenoSubcommand::Upgrade { force, dry_run } => { + upgrade_command(dry_run, force).boxed_local() + } _ => unreachable!(), }; diff --git a/cli/op_error.rs b/cli/op_error.rs index bebfd2e723238f..3537d4b287da2b 100644 --- a/cli/op_error.rs +++ b/cli/op_error.rs @@ -18,6 +18,7 @@ use crate::import_map::ImportMapError; use deno_core::ErrBox; use deno_core::ModuleResolutionError; use dlopen; +use notify; use reqwest; use rustyline::error::ReadlineError; use std; @@ -349,6 +350,30 @@ impl From<&dlopen::Error> for OpError { } } +impl From for OpError { + fn from(error: notify::Error) -> Self { + OpError::from(&error) + } +} + +impl From<¬ify::Error> for OpError { + fn from(error: ¬ify::Error) -> Self { + use notify::ErrorKind::*; + let kind = match error.kind { + Generic(_) => ErrorKind::Other, + Io(ref e) => return e.into(), + PathNotFound => ErrorKind::NotFound, + WatchNotFound => ErrorKind::NotFound, + InvalidConfig(_) => ErrorKind::InvalidData, + }; + + Self { + kind, + msg: error.to_string(), + } + } +} + impl From for OpError { fn from(error: ErrBox) -> Self { #[cfg(unix)] @@ -384,6 +409,7 @@ impl From for OpError { .map(|e| e.into()) }) .or_else(|| error.downcast_ref::().map(|e| e.into())) + .or_else(|| error.downcast_ref::().map(|e| e.into())) .or_else(|| unix_error_kind(&error)) .unwrap_or_else(|| { panic!("Can't downcast {:?} to OpError", error); diff --git a/cli/ops/fs.rs b/cli/ops/fs.rs index eb136e2e215b83..b997b4a5562f2b 100644 --- a/cli/ops/fs.rs +++ b/cli/ops/fs.rs @@ -256,7 +256,7 @@ fn op_umask( #[cfg(not(unix))] { let _ = args.mask; // avoid unused warning. - return Err(OpError::not_implemented()); + Err(OpError::not_implemented()) } #[cfg(unix)] { @@ -360,7 +360,7 @@ fn op_chmod( { // Still check file/dir exists on Windows let _metadata = std::fs::metadata(&path)?; - return Err(OpError::not_implemented()); + Err(OpError::not_implemented()) } }) } @@ -400,7 +400,7 @@ fn op_chown( { // Still check file/dir exists on Windows let _metadata = std::fs::metadata(&path)?; - return Err(OpError::not_implemented()); + Err(OpError::not_implemented()) } }) } @@ -732,7 +732,7 @@ fn op_symlink( // Unlike with chmod/chown, here we don't // require `oldpath` to exist on Windows let _ = oldpath; // avoid unused warning - return Err(OpError::not_implemented()); + Err(OpError::not_implemented()) } }) } diff --git a/cli/ops/io.rs b/cli/ops/io.rs index 7969184efba58c..0c9a8388353d27 100644 --- a/cli/ops/io.rs +++ b/cli/ops/io.rs @@ -148,6 +148,8 @@ pub enum StreamResource { Stderr(tokio::io::Stderr), FsFile(tokio::fs::File, FileMetadata), TcpStream(tokio::net::TcpStream), + #[cfg(not(windows))] + UnixStream(tokio::net::UnixStream), ServerTlsStream(Box>), ClientTlsStream(Box>), HttpBody(Box), @@ -183,6 +185,8 @@ impl DenoAsyncRead for StreamResource { FsFile(f, _) => f, Stdin(f, _) => f, TcpStream(f) => f, + #[cfg(not(windows))] + UnixStream(f) => f, ClientTlsStream(f) => f, ServerTlsStream(f) => f, ChildStdout(f) => f, @@ -262,6 +266,8 @@ impl DenoAsyncWrite for StreamResource { Stdout(f) => f, Stderr(f) => f, TcpStream(f) => f, + #[cfg(not(windows))] + UnixStream(f) => f, ClientTlsStream(f) => f, ServerTlsStream(f) => f, ChildStdin(f) => f, @@ -279,6 +285,8 @@ impl DenoAsyncWrite for StreamResource { Stdout(f) => f, Stderr(f) => f, TcpStream(f) => f, + #[cfg(not(windows))] + UnixStream(f) => f, ClientTlsStream(f) => f, ServerTlsStream(f) => f, ChildStdin(f) => f, diff --git a/cli/ops/mod.rs b/cli/ops/mod.rs index c011facfc677ea..b91a61c3a90c85 100644 --- a/cli/ops/mod.rs +++ b/cli/ops/mod.rs @@ -15,6 +15,8 @@ pub mod fs; pub mod fs_events; pub mod io; pub mod net; +#[cfg(unix)] +mod net_unix; pub mod os; pub mod permissions; pub mod plugins; diff --git a/cli/ops/net.rs b/cli/ops/net.rs index 3987e94c1cbbea..f074ef9ee0b577 100644 --- a/cli/ops/net.rs +++ b/cli/ops/net.rs @@ -18,6 +18,9 @@ use tokio::net::TcpListener; use tokio::net::TcpStream; use tokio::net::UdpSocket; +#[cfg(unix)] +use super::net_unix; + pub fn init(i: &mut Isolate, s: &State) { i.register_op("op_accept", s.stateful_json_op(op_accept)); i.register_op("op_connect", s.stateful_json_op(op_connect)); @@ -30,14 +33,14 @@ pub fn init(i: &mut Isolate, s: &State) { #[derive(Deserialize)] struct AcceptArgs { rid: i32, + transport: String, } -fn op_accept( +fn accept_tcp( state: &State, - args: Value, + args: AcceptArgs, _zero_copy: Option, ) -> Result { - let args: AcceptArgs = serde_json::from_value(args)?; let rid = args.rid as u32; let state_ = state.clone(); { @@ -102,20 +105,36 @@ fn op_accept( Ok(JsonOp::Async(op.boxed_local())) } +fn op_accept( + state: &State, + args: Value, + zero_copy: Option, +) -> Result { + let args: AcceptArgs = serde_json::from_value(args)?; + match args.transport.as_str() { + "tcp" => accept_tcp(state, args, zero_copy), + #[cfg(unix)] + "unix" => net_unix::accept_unix(state, args.rid as u32, zero_copy), + _ => Err(OpError::other(format!( + "Unsupported transport protocol {}", + args.transport + ))), + } +} + #[derive(Deserialize)] struct ReceiveArgs { rid: i32, + transport: String, } -fn op_receive( +fn receive_udp( state: &State, - args: Value, + args: ReceiveArgs, zero_copy: Option, ) -> Result { - assert!(zero_copy.is_some()); let mut buf = zero_copy.unwrap(); - let args: ReceiveArgs = serde_json::from_value(args)?; let rid = args.rid as u32; let state_ = state.clone(); @@ -145,12 +164,32 @@ fn op_receive( Ok(JsonOp::Async(op.boxed_local())) } +fn op_receive( + state: &State, + args: Value, + zero_copy: Option, +) -> Result { + assert!(zero_copy.is_some()); + let args: ReceiveArgs = serde_json::from_value(args)?; + match args.transport.as_str() { + "udp" => receive_udp(state, args, zero_copy), + #[cfg(unix)] + "unixpacket" => { + net_unix::receive_unix_packet(state, args.rid as u32, zero_copy) + } + _ => Err(OpError::other(format!( + "Unsupported transport protocol {}", + args.transport + ))), + } +} + #[derive(Deserialize)] struct SendArgs { rid: i32, - hostname: String, - port: u16, transport: String, + #[serde(flatten)] + transport_args: ArgsEnum, } fn op_send( @@ -160,38 +199,67 @@ fn op_send( ) -> Result { assert!(zero_copy.is_some()); let buf = zero_copy.unwrap(); - - let args: SendArgs = serde_json::from_value(args)?; - assert_eq!(args.transport, "udp"); - let rid = args.rid as u32; - let state_ = state.clone(); - state.check_net(&args.hostname, args.port)?; - - let op = async move { - let mut state = state_.borrow_mut(); - let resource = state - .resource_table - .get_mut::(rid) - .ok_or_else(|| { - OpError::bad_resource("Socket has been closed".to_string()) - })?; - - let socket = &mut resource.socket; - let addr = resolve_addr(&args.hostname, args.port).await?; - socket.send_to(&buf, addr).await?; - - Ok(json!({})) - }; - - Ok(JsonOp::Async(op.boxed_local())) + match serde_json::from_value(args)? { + SendArgs { + rid, + transport, + transport_args: ArgsEnum::Ip(args), + } if transport == "udp" => { + state.check_net(&args.hostname, args.port)?; + + let op = async move { + let mut state = state_.borrow_mut(); + let resource = state + .resource_table + .get_mut::(rid as u32) + .ok_or_else(|| { + OpError::bad_resource("Socket has been closed".to_string()) + })?; + let socket = &mut resource.socket; + let addr = resolve_addr(&args.hostname, args.port).await?; + socket.send_to(&buf, addr).await?; + Ok(json!({})) + }; + + Ok(JsonOp::Async(op.boxed_local())) + } + #[cfg(unix)] + SendArgs { + rid, + transport, + transport_args: ArgsEnum::Unix(args), + } if transport == "unixpacket" => { + let address_path = net_unix::Path::new(&args.address); + state.check_read(&address_path)?; + let op = async move { + let mut state = state_.borrow_mut(); + let resource = state + .resource_table + .get_mut::(rid as u32) + .ok_or_else(|| { + OpError::other("Socket has been closed".to_string()) + })?; + + let socket = &mut resource.socket; + socket + .send_to(&buf, &resource.local_addr.as_pathname().unwrap()) + .await?; + + Ok(json!({})) + }; + + Ok(JsonOp::Async(op.boxed_local())) + } + _ => Err(OpError::other("Wrong argument format!".to_owned())), + } } #[derive(Deserialize)] struct ConnectArgs { transport: String, - hostname: String, - port: u16, + #[serde(flatten)] + transport_args: ArgsEnum, } fn op_connect( @@ -199,39 +267,78 @@ fn op_connect( args: Value, _zero_copy: Option, ) -> Result { - let args: ConnectArgs = serde_json::from_value(args)?; - assert_eq!(args.transport, "tcp"); // TODO Support others. - let state_ = state.clone(); - state.check_net(&args.hostname, args.port)?; - - let op = async move { - let addr = resolve_addr(&args.hostname, args.port).await?; - let tcp_stream = TcpStream::connect(&addr).await?; - let local_addr = tcp_stream.local_addr()?; - let remote_addr = tcp_stream.peer_addr()?; - let mut state = state_.borrow_mut(); - let rid = state.resource_table.add( - "tcpStream", - Box::new(StreamResourceHolder::new(StreamResource::TcpStream( - tcp_stream, - ))), - ); - Ok(json!({ - "rid": rid, - "localAddr": { - "hostname": local_addr.ip().to_string(), - "port": local_addr.port(), - "transport": args.transport, - }, - "remoteAddr": { - "hostname": remote_addr.ip().to_string(), - "port": remote_addr.port(), - "transport": args.transport, - } - })) - }; - - Ok(JsonOp::Async(op.boxed_local())) + match serde_json::from_value(args)? { + ConnectArgs { + transport, + transport_args: ArgsEnum::Ip(args), + } if transport == "tcp" => { + let state_ = state.clone(); + state.check_net(&args.hostname, args.port)?; + let op = async move { + let addr = resolve_addr(&args.hostname, args.port).await?; + let tcp_stream = TcpStream::connect(&addr).await?; + let local_addr = tcp_stream.local_addr()?; + let remote_addr = tcp_stream.peer_addr()?; + let mut state = state_.borrow_mut(); + let rid = state.resource_table.add( + "tcpStream", + Box::new(StreamResourceHolder::new(StreamResource::TcpStream( + tcp_stream, + ))), + ); + Ok(json!({ + "rid": rid, + "localAddr": { + "hostname": local_addr.ip().to_string(), + "port": local_addr.port(), + "transport": transport, + }, + "remoteAddr": { + "hostname": remote_addr.ip().to_string(), + "port": remote_addr.port(), + "transport": transport, + } + })) + }; + Ok(JsonOp::Async(op.boxed_local())) + } + #[cfg(unix)] + ConnectArgs { + transport, + transport_args: ArgsEnum::Unix(args), + } if transport == "unix" => { + let address_path = net_unix::Path::new(&args.address); + let state_ = state.clone(); + state.check_read(&address_path)?; + let op = async move { + let address = args.address; + let unix_stream = + net_unix::UnixStream::connect(net_unix::Path::new(&address)).await?; + let local_addr = unix_stream.local_addr()?; + let remote_addr = unix_stream.peer_addr()?; + let mut state = state_.borrow_mut(); + let rid = state.resource_table.add( + "unixStream", + Box::new(StreamResourceHolder::new(StreamResource::UnixStream( + unix_stream, + ))), + ); + Ok(json!({ + "rid": rid, + "localAddr": { + "address": local_addr.as_pathname(), + "transport": transport, + }, + "remoteAddr": { + "address": remote_addr.as_pathname(), + "transport": transport, + } + })) + }; + Ok(JsonOp::Async(op.boxed_local())) + } + _ => Err(OpError::other("Wrong argument format!".to_owned())), + } } #[derive(Deserialize)] @@ -265,19 +372,17 @@ fn op_shutdown( StreamResource::TcpStream(ref mut stream) => { TcpStream::shutdown(stream, shutdown_mode).map_err(OpError::from)?; } + #[cfg(unix)] + StreamResource::UnixStream(ref mut stream) => { + net_unix::UnixStream::shutdown(stream, shutdown_mode) + .map_err(OpError::from)?; + } _ => return Err(OpError::bad_resource_id()), } Ok(JsonOp::Sync(json!({}))) } -#[derive(Deserialize)] -struct ListenArgs { - transport: String, - hostname: String, - port: u16, -} - #[allow(dead_code)] struct TcpListenerResource { listener: TcpListener, @@ -331,6 +436,27 @@ struct UdpSocketResource { socket: UdpSocket, } +#[derive(Deserialize)] +struct IpListenArgs { + hostname: String, + port: u16, +} + +#[derive(Deserialize)] +#[serde(untagged)] +enum ArgsEnum { + Ip(IpListenArgs), + #[cfg(unix)] + Unix(net_unix::UnixListenArgs), +} + +#[derive(Deserialize)] +struct ListenArgs { + transport: String, + #[serde(flatten)] + transport_args: ArgsEnum, +} + fn listen_tcp( state: &State, addr: SocketAddr, @@ -370,33 +496,60 @@ fn op_listen( args: Value, _zero_copy: Option, ) -> Result { - let args: ListenArgs = serde_json::from_value(args)?; - assert!(args.transport == "tcp" || args.transport == "udp"); - - state.check_net(&args.hostname, args.port)?; - - let addr = - futures::executor::block_on(resolve_addr(&args.hostname, args.port))?; - - let (rid, local_addr) = if args.transport == "tcp" { - listen_tcp(state, addr)? - } else { - listen_udp(state, addr)? - }; - - debug!( - "New listener {} {}:{}", - rid, - local_addr.ip().to_string(), - local_addr.port() - ); - - Ok(JsonOp::Sync(json!({ - "rid": rid, - "localAddr": { - "hostname": local_addr.ip().to_string(), - "port": local_addr.port(), - "transport": args.transport, - }, - }))) + match serde_json::from_value(args)? { + ListenArgs { + transport, + transport_args: ArgsEnum::Ip(args), + } => { + state.check_net(&args.hostname, args.port)?; + let addr = + futures::executor::block_on(resolve_addr(&args.hostname, args.port))?; + let (rid, local_addr) = if transport == "tcp" { + listen_tcp(state, addr)? + } else { + listen_udp(state, addr)? + }; + debug!( + "New listener {} {}:{}", + rid, + local_addr.ip().to_string(), + local_addr.port() + ); + Ok(JsonOp::Sync(json!({ + "rid": rid, + "localAddr": { + "hostname": local_addr.ip().to_string(), + "port": local_addr.port(), + "transport": transport, + }, + }))) + } + #[cfg(unix)] + ListenArgs { + transport, + transport_args: ArgsEnum::Unix(args), + } if transport == "unix" || transport == "unixpacket" => { + let address_path = net_unix::Path::new(&args.address); + state.check_read(&address_path)?; + let (rid, local_addr) = if transport == "unix" { + net_unix::listen_unix(state, &address_path)? + } else { + net_unix::listen_unix_packet(state, &address_path)? + }; + debug!( + "New listener {} {}", + rid, + local_addr.as_pathname().unwrap().display(), + ); + Ok(JsonOp::Sync(json!({ + "rid": rid, + "localAddr": { + "address": local_addr.as_pathname(), + "transport": transport, + }, + }))) + } + #[cfg(unix)] + _ => Err(OpError::other("Wrong argument format!".to_owned())), + } } diff --git a/cli/ops/net_unix.rs b/cli/ops/net_unix.rs new file mode 100644 index 00000000000000..43778e7c6d0911 --- /dev/null +++ b/cli/ops/net_unix.rs @@ -0,0 +1,142 @@ +use super::dispatch_json::{Deserialize, JsonOp}; +use super::io::{StreamResource, StreamResourceHolder}; +use crate::op_error::OpError; +use crate::state::State; +use futures::future::FutureExt; + +use deno_core::*; +use std::fs::remove_file; +use std::os::unix; +pub use std::path::Path; +use tokio::net::UnixDatagram; +use tokio::net::UnixListener; +pub use tokio::net::UnixStream; + +struct UnixListenerResource { + listener: UnixListener, +} + +pub struct UnixDatagramResource { + pub socket: UnixDatagram, + pub local_addr: unix::net::SocketAddr, +} + +#[derive(Deserialize)] +pub struct UnixListenArgs { + pub address: String, +} + +pub fn accept_unix( + state: &State, + rid: u32, + _zero_copy: Option, +) -> Result { + let state_ = state.clone(); + { + let state = state.borrow(); + state + .resource_table + .get::(rid) + .ok_or_else(OpError::bad_resource_id)?; + } + let op = async move { + let mut state = state_.borrow_mut(); + let listener_resource = state + .resource_table + .get_mut::(rid) + .ok_or_else(|| { + OpError::bad_resource("Listener has been closed".to_string()) + })?; + let (unix_stream, _socket_addr) = + listener_resource.listener.accept().await?; + let local_addr = unix_stream.local_addr()?; + let remote_addr = unix_stream.peer_addr()?; + let rid = state.resource_table.add( + "unixStream", + Box::new(StreamResourceHolder::new(StreamResource::UnixStream( + unix_stream, + ))), + ); + Ok(json!({ + "rid": rid, + "localAddr": { + "address": local_addr.as_pathname(), + "transport": "unix", + }, + "remoteAddr": { + "address": remote_addr.as_pathname(), + "transport": "unix", + } + })) + }; + + Ok(JsonOp::Async(op.boxed_local())) +} + +pub fn receive_unix_packet( + state: &State, + rid: u32, + zero_copy: Option, +) -> Result { + let mut buf = zero_copy.unwrap(); + let state_ = state.clone(); + + let op = async move { + let mut state = state_.borrow_mut(); + let resource = state + .resource_table + .get_mut::(rid) + .ok_or_else(|| { + OpError::bad_resource("Socket has been closed".to_string()) + })?; + let (size, remote_addr) = resource.socket.recv_from(&mut buf).await?; + Ok(json!({ + "size": size, + "remoteAddr": { + "address": remote_addr.as_pathname(), + "transport": "unixpacket", + } + })) + }; + + Ok(JsonOp::Async(op.boxed_local())) +} + +pub fn listen_unix( + state: &State, + addr: &Path, +) -> Result<(u32, unix::net::SocketAddr), OpError> { + let mut state = state.borrow_mut(); + if addr.exists() { + remove_file(&addr).unwrap(); + } + let listener = UnixListener::bind(&addr)?; + let local_addr = listener.local_addr()?; + let listener_resource = UnixListenerResource { listener }; + let rid = state + .resource_table + .add("unixListener", Box::new(listener_resource)); + + Ok((rid, local_addr)) +} + +pub fn listen_unix_packet( + state: &State, + addr: &Path, +) -> Result<(u32, unix::net::SocketAddr), OpError> { + let mut state = state.borrow_mut(); + if addr.exists() { + remove_file(&addr).unwrap(); + } + let socket = UnixDatagram::bind(&addr)?; + let local_addr = socket.local_addr()?; + let datagram_resource = UnixDatagramResource { + socket, + local_addr: local_addr.clone(), + }; + let rid = state + .resource_table + .add("unixDatagram", Box::new(datagram_resource)); + + Ok((rid, local_addr)) +} diff --git a/cli/ops/process.rs b/cli/ops/process.rs index 55080fc2d23291..0f25b6d38eb273 100644 --- a/cli/ops/process.rs +++ b/cli/ops/process.rs @@ -49,7 +49,7 @@ fn subprocess_stdio_map(s: &str) -> std::process::Stdio { #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct RunArgs { - args: Vec, + cmd: Vec, cwd: Option, env: Vec<(String, String)>, stdin: String, @@ -74,7 +74,7 @@ fn op_run( state.check_run()?; let state_ = state.clone(); - let args = run_args.args; + let args = run_args.cmd; let env = run_args.env; let cwd = run_args.cwd; diff --git a/cli/permissions.rs b/cli/permissions.rs index 6063ee9d16fdb5..16e3eebb788bef 100644 --- a/cli/permissions.rs +++ b/cli/permissions.rs @@ -217,7 +217,7 @@ impl DenoPermissions { pub fn request_run(&mut self) -> PermissionState { self .allow_run - .request("Deno requests to access to run a subprocess.") + .request("Deno requests to access to run a subprocess") } pub fn request_read(&mut self, path: &Option<&Path>) -> PermissionState { @@ -225,9 +225,9 @@ impl DenoPermissions { return PermissionState::Allow; }; self.allow_read.request(&match path { - None => "Deno requests read access.".to_string(), + None => "Deno requests read access".to_string(), Some(path) => { - format!("Deno requests read access to \"{}\".", path.display()) + format!("Deno requests read access to \"{}\"", path.display()) } }) } @@ -237,9 +237,9 @@ impl DenoPermissions { return PermissionState::Allow; }; self.allow_write.request(&match path { - None => "Deno requests write access.".to_string(), + None => "Deno requests write access".to_string(), Some(path) => { - format!("Deno requests write access to \"{}\".", path.display()) + format!("Deno requests write access to \"{}\"", path.display()) } }) } @@ -250,8 +250,8 @@ impl DenoPermissions { ) -> Result { if self.get_state_net_url(url)? == PermissionState::Ask { return Ok(self.allow_net.request(&match url { - None => "Deno requests network access.".to_string(), - Some(url) => format!("Deno requests network access to \"{}\".", url), + None => "Deno requests network access".to_string(), + Some(url) => format!("Deno requests network access to \"{}\"", url), })); }; self.get_state_net_url(url) @@ -260,17 +260,17 @@ impl DenoPermissions { pub fn request_env(&mut self) -> PermissionState { self .allow_env - .request("Deno requests to access to environment variables.") + .request("Deno requests to access to environment variables") } pub fn request_hrtime(&mut self) -> PermissionState { self .allow_hrtime - .request("Deno requests to access to high precision time.") + .request("Deno requests to access to high precision time") } pub fn request_plugin(&mut self) -> PermissionState { - self.allow_plugin.request("Deno requests to open plugins.") + self.allow_plugin.request("Deno requests to open plugins") } pub fn get_permission_state( diff --git a/cli/tests/015_duplicate_parallel_import.js b/cli/tests/015_duplicate_parallel_import.js index 37033cfa21a2f0..172eeaf5337cfa 100644 --- a/cli/tests/015_duplicate_parallel_import.js +++ b/cli/tests/015_duplicate_parallel_import.js @@ -5,7 +5,7 @@ const promises = new Array(100) .fill(null) .map(() => import("./subdir/mod1.ts")); -Promise.all(promises).then(imports => { +Promise.all(promises).then((imports) => { const mod = imports.reduce((first, cur) => { if (typeof first !== "object") { throw new Error("Expected an object."); diff --git a/cli/tests/045_proxy_test.ts b/cli/tests/045_proxy_test.ts index e9629db3791c65..6f8b45fd150ba9 100644 --- a/cli/tests/045_proxy_test.ts +++ b/cli/tests/045_proxy_test.ts @@ -17,18 +17,18 @@ async function proxyRequest(req: ServerRequest): Promise { console.log(`Proxy request to: ${req.url}`); const resp = await fetch(req.url, { method: req.method, - headers: req.headers + headers: req.headers, }); req.respond(resp); } async function testFetch(): Promise { const c = Deno.run({ - args: [Deno.execPath(), "--reload", "--allow-net", "045_proxy_client.ts"], + cmd: [Deno.execPath(), "--reload", "--allow-net", "045_proxy_client.ts"], stdout: "piped", env: { - HTTP_PROXY: `http://${addr}` - } + HTTP_PROXY: `http://${addr}`, + }, }); const status = await c.status(); @@ -38,16 +38,16 @@ async function testFetch(): Promise { async function testModuleDownload(): Promise { const http = Deno.run({ - args: [ + cmd: [ Deno.execPath(), "--reload", "fetch", - "http://localhost:4545/std/examples/colors.ts" + "http://localhost:4545/std/examples/colors.ts", ], stdout: "piped", env: { - HTTP_PROXY: `http://${addr}` - } + HTTP_PROXY: `http://${addr}`, + }, }); const httpStatus = await http.status(); diff --git a/cli/tests/050_more_jsons.ts.out b/cli/tests/050_more_jsons.ts.out index 0ca014a21491eb..c3d1e5cbfa0f02 100644 --- a/cli/tests/050_more_jsons.ts.out +++ b/cli/tests/050_more_jsons.ts.out @@ -1,5 +1,9 @@ { a: 123, b: [ 1, 2, 3 ], c: null } 123 -{ $var: { a: 123, b: [ 1, 2, 3 ], c: null }, with space: "invalid variable name", function: "reserved word" } +{ + $var: { a: 123, b: [ 1, 2, 3 ], c: null }, + with space: "invalid variable name", + function: "reserved word" +} invalid variable name just a string diff --git a/cli/tests/053_import_compression/main.ts b/cli/tests/053_import_compression/main.ts index b6f7e2c9a4a799..d18363b7d7b0d9 100644 --- a/cli/tests/053_import_compression/main.ts +++ b/cli/tests/053_import_compression/main.ts @@ -4,10 +4,10 @@ import "http://127.0.0.1:4545/cli/tests/053_import_compression/brotli"; console.log( await fetch( "http://127.0.0.1:4545/cli/tests/053_import_compression/gziped" - ).then(res => res.text()) + ).then((res) => res.text()) ); console.log( await fetch( "http://127.0.0.1:4545/cli/tests/053_import_compression/brotli" - ).then(res => res.text()) + ).then((res) => res.text()) ); diff --git a/cli/tests/055_import_wasm_via_network.ts.out b/cli/tests/055_import_wasm_via_network.ts.out index ec832c5858eb0b..c43c192fb432b1 100644 --- a/cli/tests/055_import_wasm_via_network.ts.out +++ b/cli/tests/055_import_wasm_via_network.ts.out @@ -1 +1,5 @@ -Module { add_one: [Function: 0], memory: WebAssembly.Memory {}, Symbol(Symbol.toStringTag): "Module" } +Module { + add_one: [Function: 0], + memory: WebAssembly.Memory {}, + Symbol(Symbol.toStringTag): "Module" +} diff --git a/cli/tests/057_revoke_permissions.ts b/cli/tests/057_revoke_permissions.ts index 4481dbfd91ade9..d93ae3538d5317 100644 --- a/cli/tests/057_revoke_permissions.ts +++ b/cli/tests/057_revoke_permissions.ts @@ -7,7 +7,7 @@ const knownPermissions: Deno.PermissionName[] = [ "net", "env", "plugin", - "hrtime" + "hrtime", ]; export function assert(cond: unknown): asserts cond { diff --git a/cli/tests/058_tasks_microtasks_close.ts b/cli/tests/058_tasks_microtasks_close.ts new file mode 100644 index 00000000000000..11de55a389d395 --- /dev/null +++ b/cli/tests/058_tasks_microtasks_close.ts @@ -0,0 +1,18 @@ +console.log("sync 1"); +setTimeout(() => { + console.log("setTimeout 1"); + Promise.resolve().then(() => { + console.log("Promise resolve in setTimeout 1"); + }); +}); +Promise.resolve().then(() => { + console.log("promise 1"); +}); +window.close(); +console.log("sync 2"); +setTimeout(() => { + console.log("setTimeout 2"); +}); +setTimeout(() => { + console.log("setTimeout 3"); +}, 100); diff --git a/cli/tests/058_tasks_microtasks_close.ts.out b/cli/tests/058_tasks_microtasks_close.ts.out new file mode 100644 index 00000000000000..218273cab1fba6 --- /dev/null +++ b/cli/tests/058_tasks_microtasks_close.ts.out @@ -0,0 +1,6 @@ +sync 1 +sync 2 +promise 1 +setTimeout 1 +Promise resolve in setTimeout 1 +setTimeout 2 diff --git a/cli/tests/cafile_ts_fetch.ts b/cli/tests/cafile_ts_fetch.ts index be158bf70a888f..14f39ef973da58 100644 --- a/cli/tests/cafile_ts_fetch.ts +++ b/cli/tests/cafile_ts_fetch.ts @@ -1,3 +1,3 @@ fetch("https://localhost:5545/cli/tests/cafile_ts_fetch.ts.out") - .then(r => r.text()) - .then(t => console.log(t.trimEnd())); + .then((r) => r.text()) + .then((t) => console.log(t.trimEnd())); diff --git a/cli/tests/compiler_api_test.ts b/cli/tests/compiler_api_test.ts index 540ac6680e375e..4886e03b86413b 100644 --- a/cli/tests/compiler_api_test.ts +++ b/cli/tests/compiler_api_test.ts @@ -6,7 +6,7 @@ const { compile, transpileOnly, bundle, test } = Deno; test(async function compilerApiCompileSources() { const [diagnostics, actual] = await compile("/foo.ts", { "/foo.ts": `import * as bar from "./bar.ts";\n\nconsole.log(bar);\n`, - "/bar.ts": `export const bar = "bar";\n` + "/bar.ts": `export const bar = "bar";\n`, }); assert(diagnostics == null); assert(actual); @@ -14,7 +14,7 @@ test(async function compilerApiCompileSources() { "/bar.js.map", "/bar.js", "/foo.js.map", - "/foo.js" + "/foo.js", ]); }); @@ -32,11 +32,11 @@ test(async function compilerApiCompileOptions() { const [diagnostics, actual] = await compile( "/foo.ts", { - "/foo.ts": `export const foo = "foo";` + "/foo.ts": `export const foo = "foo";`, }, { module: "amd", - sourceMap: false + sourceMap: false, } ); assert(diagnostics == null); @@ -50,10 +50,10 @@ test(async function compilerApiCompileLib() { "/foo.ts", { "/foo.ts": `console.log(document.getElementById("foo")); - console.log(Deno.args);` + console.log(Deno.args);`, }, { - lib: ["dom", "es2018", "deno.ns"] + lib: ["dom", "es2018", "deno.ns"], } ); assert(diagnostics == null); @@ -65,10 +65,10 @@ test(async function compilerApiCompileTypes() { const [diagnostics, actual] = await compile( "/foo.ts", { - "/foo.ts": `console.log(Foo.bar);` + "/foo.ts": `console.log(Foo.bar);`, }, { - types: ["./subdir/foo_types.d.ts"] + types: ["./subdir/foo_types.d.ts"], } ); assert(diagnostics == null); @@ -78,7 +78,7 @@ test(async function compilerApiCompileTypes() { test(async function transpileOnlyApi() { const actual = await transpileOnly({ - "foo.ts": `export enum Foo { Foo, Bar, Baz };\n` + "foo.ts": `export enum Foo { Foo, Bar, Baz };\n`, }); assert(actual); assertEquals(Object.keys(actual), ["foo.ts"]); @@ -89,11 +89,11 @@ test(async function transpileOnlyApi() { test(async function transpileOnlyApiConfig() { const actual = await transpileOnly( { - "foo.ts": `export enum Foo { Foo, Bar, Baz };\n` + "foo.ts": `export enum Foo { Foo, Bar, Baz };\n`, }, { sourceMap: false, - module: "amd" + module: "amd", } ); assert(actual); @@ -105,7 +105,7 @@ test(async function transpileOnlyApiConfig() { test(async function bundleApiSources() { const [diagnostics, actual] = await bundle("/foo.ts", { "/foo.ts": `export * from "./bar.ts";\n`, - "/bar.ts": `export const bar = "bar";\n` + "/bar.ts": `export const bar = "bar";\n`, }); assert(diagnostics == null); assert(actual.includes(`__instantiate("foo")`)); @@ -124,10 +124,10 @@ test(async function bundleApiConfig() { "/foo.ts", { "/foo.ts": `// random comment\nexport * from "./bar.ts";\n`, - "/bar.ts": `export const bar = "bar";\n` + "/bar.ts": `export const bar = "bar";\n`, }, { - removeComments: true + removeComments: true, } ); assert(diagnostics == null); @@ -137,7 +137,7 @@ test(async function bundleApiConfig() { test(async function bundleApiJsModules() { const [diagnostics, actual] = await bundle("/foo.js", { "/foo.js": `export * from "./bar.js";\n`, - "/bar.js": `export const bar = "bar";\n` + "/bar.js": `export const bar = "bar";\n`, }); assert(diagnostics == null); assert(actual.includes(`System.register("bar",`)); @@ -145,7 +145,7 @@ test(async function bundleApiJsModules() { test(async function diagnosticsTest() { const [diagnostics] = await compile("/foo.ts", { - "/foo.ts": `document.getElementById("foo");` + "/foo.ts": `document.getElementById("foo");`, }); assert(Array.isArray(diagnostics)); assert(diagnostics.length === 1); diff --git a/cli/tests/complex_permissions_test.ts b/cli/tests/complex_permissions_test.ts index 401c8cd8147403..55b4ead35dd9f0 100644 --- a/cli/tests/complex_permissions_test.ts +++ b/cli/tests/complex_permissions_test.ts @@ -4,23 +4,23 @@ const { args, readFileSync, writeFileSync, exit } = Deno; const name = args[0]; const test: { [key: string]: Function } = { read(files: string[]): void { - files.forEach(file => readFileSync(file)); + files.forEach((file) => readFileSync(file)); }, write(files: string[]): void { - files.forEach(file => + files.forEach((file) => writeFileSync(file, new Uint8Array(0), { append: true }) ); }, netFetch(hosts: string[]): void { - hosts.forEach(host => fetch(host)); + hosts.forEach((host) => fetch(host)); }, netListen(endpoints: string[]): void { - endpoints.forEach(endpoint => { + endpoints.forEach((endpoint) => { const [hostname, port] = endpoint.split(":"); const listener = Deno.listen({ transport: "tcp", hostname, - port: parseInt(port, 10) + port: parseInt(port, 10), }); listener.close(); }); @@ -31,11 +31,11 @@ const test: { [key: string]: Function } = { const listener = await Deno.connect({ transport: "tcp", hostname, - port: parseInt(port, 10) + port: parseInt(port, 10), }); listener.close(); } - } + }, }; if (!test[name]) { diff --git a/cli/tests/error_003_typescript.ts b/cli/tests/error_003_typescript.ts index 4ce86bb83b9828..e06e466e74612d 100644 --- a/cli/tests/error_003_typescript.ts +++ b/cli/tests/error_003_typescript.ts @@ -4,17 +4,17 @@ let x = { b: { c() { return { d: "hello" }; - } - } - } + }, + }, + }, }; let y = { a: { b: { c() { return { d: 1234 }; - } - } - } + }, + }, + }, }; x = y; diff --git a/cli/tests/error_017_hide_long_source_ts.ts b/cli/tests/error_017_hide_long_source_ts.ts new file mode 100644 index 00000000000000..a4c30670f9ca39 --- /dev/null +++ b/cli/tests/error_017_hide_long_source_ts.ts @@ -0,0 +1,2 @@ +const LONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONG = undefined; +LONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONG.a; diff --git a/cli/tests/error_017_hide_long_source_ts.ts.out b/cli/tests/error_017_hide_long_source_ts.ts.out new file mode 100644 index 00000000000000..4b4016b84d76fb --- /dev/null +++ b/cli/tests/error_017_hide_long_source_ts.ts.out @@ -0,0 +1,3 @@ +[WILDCARD]error TS2532: Object is possibly 'undefined'. + +â–º file:///[WILDCARD]cli/tests/error_017_hide_long_source_ts.ts:2:1 diff --git a/cli/tests/error_018_hide_long_source_js.js b/cli/tests/error_018_hide_long_source_js.js new file mode 100644 index 00000000000000..a4c30670f9ca39 --- /dev/null +++ b/cli/tests/error_018_hide_long_source_js.js @@ -0,0 +1,2 @@ +const LONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONG = undefined; +LONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONGLONG.a; diff --git a/cli/tests/error_018_hide_long_source_js.js.out b/cli/tests/error_018_hide_long_source_js.js.out new file mode 100644 index 00000000000000..dbdd924df36dfd --- /dev/null +++ b/cli/tests/error_018_hide_long_source_js.js.out @@ -0,0 +1,3 @@ +error: Uncaught TypeError: Cannot read property 'a' of undefined +â–º file:///[WILDCARD]cli/tests/error_018_hide_long_source_js.js:2:206 + at file:///[WILDCARD]cli/tests/error_018_hide_long_source_js.js:2:206 diff --git a/cli/tests/error_syntax_empty_trailing_line.mjs b/cli/tests/error_syntax_empty_trailing_line.mjs new file mode 100644 index 00000000000000..5bc6b1c239409d --- /dev/null +++ b/cli/tests/error_syntax_empty_trailing_line.mjs @@ -0,0 +1,2 @@ +// Deliberately using .mjs to avoid triggering prettier +setTimeout(() => {}), diff --git a/cli/tests/error_syntax_empty_trailing_line.mjs.out b/cli/tests/error_syntax_empty_trailing_line.mjs.out new file mode 100644 index 00000000000000..1f1c96cd3172bb --- /dev/null +++ b/cli/tests/error_syntax_empty_trailing_line.mjs.out @@ -0,0 +1,2 @@ +error: Uncaught SyntaxError: Unexpected end of input +â–º file:///[WILDCARD]cli/tests/error_syntax_empty_trailing_line.mjs:[WILDCARD] diff --git a/cli/tests/inspector1.js b/cli/tests/inspector1.js new file mode 100644 index 00000000000000..5cb059def636d6 --- /dev/null +++ b/cli/tests/inspector1.js @@ -0,0 +1,3 @@ +setInterval(() => { + console.log("hello"); +}, 1000); diff --git a/cli/tests/integration_tests.rs b/cli/tests/integration_tests.rs index ba1880b803267f..8342da10864316 100644 --- a/cli/tests/integration_tests.rs +++ b/cli/tests/integration_tests.rs @@ -168,6 +168,30 @@ fn fmt_stdin_error() { assert!(!output.status.success()); } +// Warning: this test requires internet access. +#[test] +fn upgrade_in_tmpdir() { + let temp_dir = TempDir::new().unwrap(); + let exe_path = if cfg!(windows) { + temp_dir.path().join("deno") + } else { + temp_dir.path().join("deno.exe") + }; + let _ = std::fs::copy(util::deno_exe_path(), &exe_path).unwrap(); + assert!(exe_path.exists()); + let _mtime1 = std::fs::metadata(&exe_path).unwrap().modified().unwrap(); + let status = Command::new(&exe_path) + .arg("upgrade") + .arg("--force") + .spawn() + .unwrap() + .wait() + .unwrap(); + assert!(status.success()); + let _mtime2 = std::fs::metadata(&exe_path).unwrap().modified().unwrap(); + // TODO(ry) assert!(mtime1 < mtime2); +} + #[test] fn installer_test_local_module_run() { let temp_dir = TempDir::new().expect("tempdir fail"); @@ -1054,6 +1078,11 @@ itest!(_057_revoke_permissions { output: "057_revoke_permissions.out", }); +itest!(_058_tasks_microtasks_close { + args: "run 058_tasks_microtasks_close.ts", + output: "058_tasks_microtasks_close.ts.out", +}); + itest!(js_import_detect { args: "run --reload js_import_detect.ts", output: "js_import_detect.ts.out", @@ -1250,6 +1279,20 @@ itest!(error_016_dynamic_import_permissions2 { http_server: true, }); +itest!(error_017_hide_long_source_ts { + args: "--reload error_017_hide_long_source_ts.ts", + output: "error_017_hide_long_source_ts.ts.out", + check_stderr: true, + exit_code: 1, +}); + +itest!(error_018_hide_long_source_js { + args: "error_018_hide_long_source_js.js", + output: "error_018_hide_long_source_js.js.out", + check_stderr: true, + exit_code: 1, +}); + itest!(error_stack { args: "run --reload error_stack.ts", check_stderr: true, @@ -1264,6 +1307,13 @@ itest!(error_syntax { output: "error_syntax.js.out", }); +itest!(error_syntax_empty_trailing_line { + args: "run --reload error_syntax_empty_trailing_line.mjs", + check_stderr: true, + exit_code: 1, + output: "error_syntax_empty_trailing_line.mjs.out", +}); + itest!(error_type_definitions { args: "run --reload error_type_definitions.ts", check_stderr: true, @@ -1418,7 +1468,7 @@ itest!(cafile_eval { http_server: true, }); -itest!(cafile_info { +itest_ignore!(cafile_info { args: "info --cert tls/RootCA.pem https://localhost:5545/cli/tests/cafile_info.ts", output: "cafile_info.ts.out", @@ -1917,6 +1967,149 @@ fn test_permissions_net_listen_allow_localhost() { assert!(!err.contains(util::PERMISSION_DENIED_PATTERN)); } +#[cfg(not(target_os = "linux"))] // TODO(ry) broken on github actions. +fn extract_ws_url_from_stderr( + stderr: &mut std::process::ChildStderr, +) -> url::Url { + use std::io::BufRead; + let mut stderr = std::io::BufReader::new(stderr); + let mut stderr_first_line = String::from(""); + let _ = stderr.read_line(&mut stderr_first_line).unwrap(); + assert!(stderr_first_line.starts_with("Debugger listening on ")); + let v: Vec<_> = stderr_first_line.match_indices("ws:").collect(); + assert_eq!(v.len(), 1); + let ws_url_index = v[0].0; + let ws_url = &stderr_first_line[ws_url_index..]; + url::Url::parse(ws_url).unwrap() +} + +#[cfg(not(target_os = "linux"))] // TODO(ry) broken on github actions. +#[tokio::test] +async fn inspector_connect() { + let script = deno::test_util::root_path() + .join("cli") + .join("tests") + .join("inspector1.js"); + let mut child = util::deno_cmd() + .arg("run") + // Warning: each inspector test should be on its own port to avoid + // conflicting with another inspector test. + .arg("--inspect=127.0.0.1:9229") + .arg(script) + .stderr(std::process::Stdio::piped()) + .spawn() + .unwrap(); + let ws_url = extract_ws_url_from_stderr(child.stderr.as_mut().unwrap()); + println!("ws_url {}", ws_url); + // We use tokio_tungstenite as a websocket client because warp (which is + // a dependency of Deno) uses it. + let (_socket, response) = tokio_tungstenite::connect_async(ws_url) + .await + .expect("Can't connect"); + assert_eq!("101 Switching Protocols", response.status().to_string()); + child.kill().unwrap(); +} + +#[cfg(not(target_os = "linux"))] // TODO(ry) broken on github actions. +#[tokio::test] +async fn inspector_pause() { + let script = deno::test_util::root_path() + .join("cli") + .join("tests") + .join("inspector1.js"); + let mut child = util::deno_cmd() + .arg("run") + // Warning: each inspector test should be on its own port to avoid + // conflicting with another inspector test. + .arg("--inspect=127.0.0.1:9230") + .arg(script) + .stderr(std::process::Stdio::piped()) + .spawn() + .unwrap(); + let ws_url = extract_ws_url_from_stderr(child.stderr.as_mut().unwrap()); + println!("ws_url {}", ws_url); + // We use tokio_tungstenite as a websocket client because warp (which is + // a dependency of Deno) uses it. + let (mut socket, _) = tokio_tungstenite::connect_async(ws_url) + .await + .expect("Can't connect"); + + /// Returns the next websocket message as a string ignoring + /// Debugger.scriptParsed messages. + async fn ws_read_msg( + socket: &mut tokio_tungstenite::WebSocketStream, + ) -> String { + use futures::stream::StreamExt; + while let Some(msg) = socket.next().await { + let msg = msg.unwrap().to_string(); + assert!(!msg.contains("error")); + if !msg.contains("Debugger.scriptParsed") { + return msg; + } + } + unreachable!() + } + + use futures::sink::SinkExt; + socket + .send(r#"{"id":6,"method":"Debugger.enable"}"#.into()) + .await + .unwrap(); + + let msg = ws_read_msg(&mut socket).await; + println!("response msg 1 {}", msg); + assert!(msg.starts_with(r#"{"id":6,"result":{"debuggerId":"#)); + + socket + .send(r#"{"id":31,"method":"Debugger.pause"}"#.into()) + .await + .unwrap(); + + let msg = ws_read_msg(&mut socket).await; + println!("response msg 2 {}", msg); + assert_eq!(msg, r#"{"id":31,"result":{}}"#); + + child.kill().unwrap(); +} + +#[cfg(not(target_os = "linux"))] // TODO(ry) broken on github actions. +#[tokio::test] +async fn inspector_port_collision() { + let script = deno::test_util::root_path() + .join("cli") + .join("tests") + .join("inspector1.js"); + let mut child1 = util::deno_cmd() + .arg("run") + .arg("--inspect=127.0.0.1:9231") + .arg(script.clone()) + .stderr(std::process::Stdio::piped()) + .spawn() + .unwrap(); + let ws_url_1 = extract_ws_url_from_stderr(child1.stderr.as_mut().unwrap()); + println!("ws_url {}", ws_url_1); + + let mut child2 = util::deno_cmd() + .arg("run") + .arg("--inspect=127.0.0.1:9231") + .arg(script) + .stderr(std::process::Stdio::piped()) + .spawn() + .unwrap(); + + use std::io::Read; + let mut stderr_str_2 = String::new(); + child2 + .stderr + .as_mut() + .unwrap() + .read_to_string(&mut stderr_str_2) + .unwrap(); + assert!(stderr_str_2.contains("Cannot start inspector server")); + child1.kill().unwrap(); + let _ = child2.kill(); +} + mod util { use deno::colors::strip_ansi_codes; pub use deno::test_util::*; diff --git a/cli/tests/lib_ref.ts b/cli/tests/lib_ref.ts index 9fc84ea3e7cf81..1b9f243c8f962a 100644 --- a/cli/tests/lib_ref.ts +++ b/cli/tests/lib_ref.ts @@ -1,11 +1,11 @@ const [errors, program] = await Deno.compile( "main.ts", { - "main.ts": `/// \n\ndocument.getElementById("foo");\nDeno.args;` + "main.ts": `/// \n\ndocument.getElementById("foo");\nDeno.args;`, }, { target: "es2018", - lib: ["es2018", "deno.ns"] + lib: ["es2018", "deno.ns"], } ); diff --git a/cli/tests/lib_runtime_api.ts b/cli/tests/lib_runtime_api.ts index 848b523a10af52..5d76ea1c5e2d0d 100644 --- a/cli/tests/lib_runtime_api.ts +++ b/cli/tests/lib_runtime_api.ts @@ -1,10 +1,10 @@ const [errors, program] = await Deno.compile( "main.ts", { - "main.ts": `document.getElementById("foo");` + "main.ts": `document.getElementById("foo");`, }, { - lib: ["dom", "esnext"] + lib: ["dom", "esnext"], } ); diff --git a/cli/tests/lock_write_fetch.ts b/cli/tests/lock_write_fetch.ts index 7d597724dec955..2e97353132b5dd 100644 --- a/cli/tests/lock_write_fetch.ts +++ b/cli/tests/lock_write_fetch.ts @@ -5,14 +5,14 @@ try { const fetchProc = Deno.run({ stdout: "null", stderr: "null", - args: [ + cmd: [ Deno.execPath(), "fetch", "--reload", "--lock=lock_write_fetch.json", "--lock-write", - "https_import.ts" - ] + "https_import.ts", + ], }); const fetchCode = (await fetchProc.status()).code; @@ -21,12 +21,12 @@ console.log(`fetch code: ${fetchCode}`); const fetchCheckProc = Deno.run({ stdout: "null", stderr: "null", - args: [ + cmd: [ Deno.execPath(), "fetch", "--lock=lock_write_fetch.json", - "https_import.ts" - ] + "https_import.ts", + ], }); const fetchCheckProcCode = (await fetchCheckProc.status()).code; @@ -35,7 +35,7 @@ console.log(`fetch check code: ${fetchCheckProcCode}`); const runProc = Deno.run({ stdout: "null", stderr: "null", - args: [Deno.execPath(), "--lock=lock_write_fetch.json", "https_import.ts"] + cmd: [Deno.execPath(), "--lock=lock_write_fetch.json", "https_import.ts"], }); const runCode = (await runProc.status()).code; diff --git a/cli/tests/permission_test.ts b/cli/tests/permission_test.ts index 11b95cf3aa722d..1e6abae217185c 100644 --- a/cli/tests/permission_test.ts +++ b/cli/tests/permission_test.ts @@ -18,13 +18,13 @@ const test: { [key: string]: Function } = { }, runRequired(): void { run({ - args: [ + cmd: [ "python", "-c", - "import sys; sys.stdout.write('hello'); sys.stdout.flush()" - ] + "import sys; sys.stdout.write('hello'); sys.stdout.flush()", + ], }); - } + }, }; if (!test[name]) { diff --git a/cli/tests/subdir/bench_worker.ts b/cli/tests/subdir/bench_worker.ts index 619a35fa267330..7e85eed03602c1 100644 --- a/cli/tests/subdir/bench_worker.ts +++ b/cli/tests/subdir/bench_worker.ts @@ -1,10 +1,10 @@ -onmessage = function(e): void { +onmessage = function (e): void { const { cmdId, action, data } = e.data; switch (action) { case 0: // Static response postMessage({ cmdId, - data: "HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World\n" + data: "HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World\n", }); break; case 1: // Respond with request data diff --git a/cli/tests/subdir/nested_worker.js b/cli/tests/subdir/nested_worker.js index a4eed723ae6be6..f5ac23a1946547 100644 --- a/cli/tests/subdir/nested_worker.js +++ b/cli/tests/subdir/nested_worker.js @@ -1,18 +1,18 @@ // Specifier should be resolved relative to current file const jsWorker = new Worker("./sibling_worker.js", { type: "module", - name: "sibling" + name: "sibling", }); -jsWorker.onerror = _e => { +jsWorker.onerror = (_e) => { postMessage({ type: "error" }); }; -jsWorker.onmessage = e => { +jsWorker.onmessage = (e) => { postMessage({ type: "msg", text: e }); close(); }; -onmessage = function(e) { +onmessage = function (e) { jsWorker.postMessage(e.data); }; diff --git a/cli/tests/subdir/sibling_worker.js b/cli/tests/subdir/sibling_worker.js index 0e91141ce4386f..99707e5d671321 100644 --- a/cli/tests/subdir/sibling_worker.js +++ b/cli/tests/subdir/sibling_worker.js @@ -1,4 +1,4 @@ -onmessage = e => { +onmessage = (e) => { postMessage(e.data); close(); }; diff --git a/cli/tests/subdir/test_worker.js b/cli/tests/subdir/test_worker.js index 9c1e555b51e597..02cd86eacd5965 100644 --- a/cli/tests/subdir/test_worker.js +++ b/cli/tests/subdir/test_worker.js @@ -4,7 +4,7 @@ if (self.name !== "jsWorker") { throw Error(`Bad worker name: ${self.name}, expected jsWorker`); } -onmessage = function(e) { +onmessage = function (e) { if (thrown === false) { thrown = true; throw new SyntaxError("[test error]"); @@ -14,6 +14,6 @@ onmessage = function(e) { close(); }; -onerror = function() { +onerror = function () { return false; }; diff --git a/cli/tests/subdir/test_worker.ts b/cli/tests/subdir/test_worker.ts index 1f924c07368511..ca79dcfe4646a7 100644 --- a/cli/tests/subdir/test_worker.ts +++ b/cli/tests/subdir/test_worker.ts @@ -2,7 +2,7 @@ if (self.name !== "tsWorker") { throw Error(`Invalid worker name: ${self.name}, expected tsWorker`); } -onmessage = function(e): void { +onmessage = function (e): void { postMessage(e.data); close(); }; diff --git a/cli/tests/subdir/test_worker_basic.js b/cli/tests/subdir/test_worker_basic.js index aef1658c0f9773..aea3608725d00a 100644 --- a/cli/tests/subdir/test_worker_basic.js +++ b/cli/tests/subdir/test_worker_basic.js @@ -5,11 +5,11 @@ if (self.name !== "jsWorker") { throw Error(`Bad worker name: ${self.name}, expected jsWorker`); } -onmessage = function(e) { +onmessage = function (e) { postMessage(e.data); close(); }; -onerror = function() { +onerror = function () { return false; }; diff --git a/cli/tests/workers_test.ts b/cli/tests/workers_test.ts index 84eeabf12bab96..42bd96d96901a2 100644 --- a/cli/tests/workers_test.ts +++ b/cli/tests/workers_test.ts @@ -31,15 +31,15 @@ Deno.test({ name: "workersBasic", // FIXME(bartlomieju): disableOpSanitizer: true, - fn: async function(): Promise { + fn: async function (): Promise { const promise = createResolvable(); const jsWorker = new Worker("../tests/subdir/test_worker.js", { type: "module", - name: "jsWorker" + name: "jsWorker", }); const tsWorker = new Worker("../tests/subdir/test_worker.ts", { type: "module", - name: "tsWorker" + name: "tsWorker", }); tsWorker.onmessage = (e): void => { @@ -59,19 +59,19 @@ Deno.test({ jsWorker.postMessage("Hello World"); await promise; - } + }, }); Deno.test({ name: "nestedWorker", // FIXME(bartlomieju): disableOpSanitizer: true, - fn: async function(): Promise { + fn: async function (): Promise { const promise = createResolvable(); const nestedWorker = new Worker("../tests/subdir/nested_worker.js", { type: "module", - name: "nested" + name: "nested", }); nestedWorker.onmessage = (e): void => { @@ -81,17 +81,17 @@ Deno.test({ nestedWorker.postMessage("Hello World"); await promise; - } + }, }); Deno.test({ name: "workerThrowsWhenExecuting", // FIXME(bartlomieju): disableOpSanitizer: true, - fn: async function(): Promise { + fn: async function (): Promise { const promise = createResolvable(); const throwingWorker = new Worker("../tests/subdir/throwing_worker.js", { - type: "module" + type: "module", }); // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -102,18 +102,18 @@ Deno.test({ }; await promise; - } + }, }); Deno.test({ name: "workerCanUseFetch", // FIXME(bartlomieju): disableOpSanitizer: true, - fn: async function(): Promise { + fn: async function (): Promise { const promise = createResolvable(); const fetchingWorker = new Worker("../tests/subdir/fetching_worker.js", { - type: "module" + type: "module", }); // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -129,5 +129,5 @@ Deno.test({ }; await promise; - } + }, }); diff --git a/cli/upgrade.rs b/cli/upgrade.rs new file mode 100644 index 00000000000000..519f8d6bc12a81 --- /dev/null +++ b/cli/upgrade.rs @@ -0,0 +1,224 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + +//! This module provides feature to upgrade deno executable +//! +//! At the moment it is only consumed using CLI but in +//! the future it can be easily extended to provide +//! the same functions as ops available in JS runtime. + +extern crate semver_parser; +use crate::futures::FutureExt; +use crate::http_util::fetch_once; +use crate::http_util::FetchOnceResult; +use crate::op_error::OpError; +use crate::ErrBox; +use regex::Regex; +use reqwest::{redirect::Policy, Client}; +use semver_parser::version::parse as semver_parse; +use semver_parser::version::Version; +use std::fs; +use std::future::Future; +use std::io::prelude::*; +use std::path::Path; +use std::path::PathBuf; +use std::pin::Pin; +use std::process::Command; +use std::process::Stdio; +use std::string::String; +use tempfile::TempDir; +use url::Url; + +// TODO(ry) Auto detect target triples for the uploaded files. +#[cfg(windows)] +const ARCHIVE_NAME: &str = "deno-x86_64-pc-windows-msvc.zip"; +#[cfg(target_os = "macos")] +const ARCHIVE_NAME: &str = "deno-x86_64-apple-darwin.zip"; +#[cfg(target_os = "linux")] +const ARCHIVE_NAME: &str = "deno-x86_64-unknown-linux-gnu.zip"; + +async fn get_latest_version(client: &Client) -> Result { + println!("Checking for latest version"); + let body = client + .get(Url::parse( + "https://github.com/denoland/deno/releases/latest", + )?) + .send() + .await? + .text() + .await?; + let v = find_version(&body)?; + Ok(semver_parse(&v).unwrap()) +} + +/// Asynchronously updates deno executable to greatest version +/// if greatest version is available. +pub async fn upgrade_command(dry_run: bool, force: bool) -> Result<(), ErrBox> { + let client = Client::builder().redirect(Policy::none()).build()?; + let latest_version = get_latest_version(&client).await?; + let current_version = semver_parse(crate::version::DENO).unwrap(); + + if !force && current_version >= latest_version { + println!( + "Local deno version {} is the most recent release", + &crate::version::DENO + ); + } else { + println!( + "New version has been found\nDeno is upgrading to version {}", + &latest_version + ); + let archive_data = + download_package(&compose_url_to_exec(&latest_version)?, client).await?; + + let old_exe_path = std::env::current_exe()?; + let new_exe_path = unpack(archive_data)?; + let permissions = fs::metadata(&old_exe_path)?.permissions(); + fs::set_permissions(&new_exe_path, permissions)?; + check_exe(&new_exe_path, &latest_version)?; + + if !dry_run { + replace_exe(&new_exe_path, &old_exe_path)?; + } + + println!("Upgrade done successfully") + } + Ok(()) +} + +fn download_package( + url: &Url, + client: Client, +) -> Pin, ErrBox>>>> { + println!("downloading {}", url); + let url = url.clone(); + let fut = async move { + match fetch_once(client.clone(), &url, None).await? { + FetchOnceResult::Code(source, _) => Ok(source), + FetchOnceResult::NotModified => unreachable!(), + FetchOnceResult::Redirect(_url, _) => { + download_package(&_url, client).await + } + } + }; + fut.boxed_local() +} + +fn compose_url_to_exec(version: &Version) -> Result { + let s = format!( + "https://github.com/denoland/deno/releases/download/v{}/{}", + version, ARCHIVE_NAME + ); + Ok(Url::parse(&s)?) +} + +fn find_version(text: &str) -> Result { + let re = Regex::new(r#"v([^\?]+)?""#)?; + if let Some(_mat) = re.find(text) { + let mat = _mat.as_str(); + return Ok(mat[1..mat.len() - 1].to_string()); + } + Err(OpError::other("Cannot read latest tag version".to_string()).into()) +} + +fn unpack(archive_data: Vec) -> Result { + // We use into_path so that the tempdir is not automatically deleted. This is + // useful for debugging upgrade, but also so this function can return a path + // to the newly uncompressed file without fear of the tempdir being deleted. + let temp_dir = TempDir::new()?.into_path(); + let exe_ext = if cfg!(windows) { "exe" } else { "" }; + let exe_path = temp_dir.join("deno").with_extension(exe_ext); + assert!(!exe_path.exists()); + + let archive_ext = Path::new(ARCHIVE_NAME) + .extension() + .and_then(|ext| ext.to_str()) + .unwrap(); + let unpack_status = match archive_ext { + "gz" => { + let exe_file = fs::File::create(&exe_path)?; + let mut cmd = Command::new("gunzip") + .arg("-c") + .stdin(Stdio::piped()) + .stdout(Stdio::from(exe_file)) + .spawn()?; + cmd.stdin.as_mut().unwrap().write_all(&archive_data)?; + cmd.wait()? + } + "zip" => { + if cfg!(windows) { + let archive_path = temp_dir.join("deno.zip"); + fs::write(&archive_path, &archive_data)?; + Command::new("powershell.exe") + .arg("-Command") + .arg("Expand-Archive") + .arg("-Path") + .arg(&archive_path) + .arg("-DestinationPath") + .arg(&temp_dir) + .spawn()? + .wait()? + } else { + let archive_path = temp_dir.join("deno.zip"); + fs::write(&archive_path, &archive_data)?; + Command::new("unzip") + .current_dir(&temp_dir) + .arg(archive_path) + .spawn()? + .wait()? + } + } + ext => panic!("Unsupported archive type: '{}'", ext), + }; + assert!(unpack_status.success()); + assert!(exe_path.exists()); + Ok(exe_path) +} + +fn replace_exe(new: &Path, old: &Path) -> Result<(), ErrBox> { + if cfg!(windows) { + // On windows you cannot replace the currently running executable. + // so first we rename it to deno.old.exe + fs::rename(old, old.with_extension("old.exe"))?; + } else { + fs::remove_file(old)?; + } + // Windows cannot rename files across device boundaries, so if rename fails, + // we try again with copy. + fs::rename(new, old).or_else(|_| fs::copy(new, old).map(|_| ()))?; + Ok(()) +} + +fn check_exe( + exe_path: &Path, + expected_version: &Version, +) -> Result<(), ErrBox> { + let output = Command::new(exe_path) + .arg("-V") + .stderr(std::process::Stdio::inherit()) + .output()?; + let stdout = String::from_utf8(output.stdout)?; + assert!(output.status.success()); + assert_eq!(stdout.trim(), format!("deno {}", expected_version)); + Ok(()) +} + +#[test] +fn test_find_version() { + let url = "You are being redirected."; + assert_eq!(find_version(url).unwrap(), "0.36.0".to_string()); +} + +#[test] +fn test_compose_url_to_exec() { + let v = semver_parse("0.0.1").unwrap(); + let url = compose_url_to_exec(&v).unwrap(); + #[cfg(windows)] + assert_eq!(url.as_str(), "https://github.com/denoland/deno/releases/download/v0.0.1/deno-x86_64-pc-windows-msvc.zip"); + #[cfg(target_os = "macos")] + assert_eq!( + url.as_str(), + "https://github.com/denoland/deno/releases/download/v0.0.1/deno-x86_64-apple-darwin.zip" + ); + #[cfg(target_os = "linux")] + assert_eq!(url.as_str(), "https://github.com/denoland/deno/releases/download/v0.0.1/deno-x86_64-unknown-linux-gnu.zip"); +} diff --git a/cli/worker.rs b/cli/worker.rs index 6593ade0b10cb8..994f22f04afc80 100644 --- a/cli/worker.rs +++ b/cli/worker.rs @@ -97,6 +97,7 @@ pub struct Worker { pub waker: AtomicWaker, pub(crate) internal_channels: WorkerChannelsInternal, external_channels: WorkerHandle, + inspector: Option>, } impl Worker { @@ -104,9 +105,15 @@ impl Worker { let loader = Rc::new(state.clone()); let mut isolate = deno_core::EsIsolate::new(loader, startup_data, false); - let global_state_ = state.borrow().global_state.clone(); + let global_state = state.borrow().global_state.clone(); + + let inspector = global_state + .inspector_server + .as_ref() + .map(|s| s.add_inspector(&mut *isolate)); + isolate.set_js_error_create_fn(move |core_js_error| { - JSError::create(core_js_error, &global_state_.ts_compiler) + JSError::create(core_js_error, &global_state.ts_compiler) }); let (internal_channels, external_channels) = create_channels(); @@ -118,6 +125,7 @@ impl Worker { waker: AtomicWaker::new(), internal_channels, external_channels, + inspector, } } @@ -175,11 +183,23 @@ impl Worker { } } +impl Drop for Worker { + fn drop(&mut self) { + // The Isolate object must outlive the Inspector object, but this is + // currently not enforced by the type system. + self.inspector.take(); + } +} + impl Future for Worker { type Output = Result<(), ErrBox>; fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { let inner = self.get_mut(); + if let Some(deno_inspector) = inner.inspector.as_mut() { + // We always poll the inspector if it exists. + let _ = deno_inspector.poll_unpin(cx); + } inner.waker.register(cx.waker()); inner.isolate.poll_unpin(cx) } diff --git a/core/Cargo.toml b/core/Cargo.toml index 48b41538b0c281..c84854f7a4c7e9 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_core" -version = "0.36.0" +version = "0.38.0" edition = "2018" description = "A secure JavaScript/TypeScript runtime built with V8, Rust, and Tokio" authors = ["the Deno authors"] @@ -19,7 +19,7 @@ futures = { version = "0.3.4", features = ["thread-pool", "compat"] } lazy_static = "1.4.0" libc = "0.2.68" log = "0.4.8" -rusty_v8 = "0.3.8" +rusty_v8 = "0.3.9" serde_json = "1.0.48" url = "2.1.1" diff --git a/core/examples/http_bench.js b/core/examples/http_bench.js index 72f53550d9482a..d9878cbe741d35 100644 --- a/core/examples/http_bench.js +++ b/core/examples/http_bench.js @@ -5,7 +5,7 @@ const requestBuf = new Uint8Array(64 * 1024); const responseBuf = new Uint8Array( "HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World\n" .split("") - .map(c => c.charCodeAt(0)) + .map((c) => c.charCodeAt(0)) ); const promiseMap = new Map(); let nextPromiseId = 1; diff --git a/core/isolate.rs b/core/isolate.rs index 3f4f897960fb3d..f876f2452245c7 100644 --- a/core/isolate.rs +++ b/core/isolate.rs @@ -159,11 +159,11 @@ type IsolateErrorHandleFn = dyn FnMut(ErrBox) -> Result<(), ErrBox>; /// as arguments. An async Op corresponds exactly to a Promise in JavaScript. #[allow(unused)] pub struct Isolate { - pub(crate) v8_isolate: Option, + pub v8_isolate: Option, snapshot_creator: Option, has_snapshotted: bool, snapshot: Option, - pub(crate) global_context: v8::Global, + pub global_context: v8::Global, pub(crate) shared_ab: v8::Global, pub(crate) js_recv_cb: v8::Global, pub(crate) js_macrotask_cb: v8::Global, diff --git a/core/lib.rs b/core/lib.rs index c4fbb33f4eec6f..d1776fb69846cc 100644 --- a/core/lib.rs +++ b/core/lib.rs @@ -21,7 +21,7 @@ mod plugins; mod resources; mod shared_queue; -use rusty_v8 as v8; +pub use rusty_v8 as v8; pub use crate::any_error::*; pub use crate::es_isolate::*; diff --git a/core/shared_queue.js b/core/shared_queue.js index 742a909953bea9..1750740d62f008 100644 --- a/core/shared_queue.js +++ b/core/shared_queue.js @@ -18,7 +18,7 @@ SharedQueue Binary Layout /* eslint-disable @typescript-eslint/no-use-before-define */ -(window => { +((window) => { const GLOBAL_NAMESPACE = "Deno"; const CORE_NAMESPACE = "core"; const MAX_RECORDS = 100; @@ -200,9 +200,9 @@ SharedQueue Binary Layout size, push, reset, - shift + shift, }, - ops + ops, }; assert(window[GLOBAL_NAMESPACE] != null); diff --git a/deno_typescript/Cargo.toml b/deno_typescript/Cargo.toml index 073bf185e1008f..86007b12850682 100644 --- a/deno_typescript/Cargo.toml +++ b/deno_typescript/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deno_typescript" -version = "0.36.0" +version = "0.38.0" license = "MIT" description = "To compile TypeScript to a snapshot during build.rs" repository = "https://github.com/denoland/deno" @@ -19,6 +19,6 @@ exclude = [ path = "lib.rs" [dependencies] -deno_core = { path = "../core", version = "0.36.0" } +deno_core = { path = "../core", version = "0.38.0" } serde_json = "1.0.48" serde = { version = "1.0.104", features = ["derive"] } diff --git a/deno_typescript/compiler_main.js b/deno_typescript/compiler_main.js index 78155024633cf9..234ed60029a281 100644 --- a/deno_typescript/compiler_main.js +++ b/deno_typescript/compiler_main.js @@ -93,7 +93,7 @@ function decodeAscii(ui8) { * @param {string} str */ function encode(str) { - const charCodes = str.split("").map(c => c.charCodeAt(0)); + const charCodes = str.split("").map((c) => c.charCodeAt(0)); const ui8 = new Uint8Array(charCodes); return ui8; } @@ -185,7 +185,7 @@ class Host { const { sourceCode } = dispatch("op_load_module", { moduleUrl, languageVersion, - shouldCreateNewSourceFile + shouldCreateNewSourceFile, }); const sourceFile = ts.createSourceFile( @@ -260,10 +260,10 @@ class Host { /** @type {string[]} */ const resolvedNames = dispatch("op_resolve_module_names", { moduleNames, - containingFile + containingFile, }); /** @type {ts.ResolvedModule[]} */ - const r = resolvedNames.map(resolvedFileName => { + const r = resolvedNames.map((resolvedFileName) => { const extension = getExtension(resolvedFileName); if (!moduleMap.has(resolvedFileName)) { // If we match the external specifier regex, we will then create an internal @@ -299,7 +299,7 @@ function configure(configurationText) { ); return { options, - diagnostics: errors.length ? errors : undefined + diagnostics: errors.length ? errors : undefined, }; } diff --git a/deno_typescript/system_loader.js b/deno_typescript/system_loader.js index 41748c46ec5224..b5b10af480c55c 100644 --- a/deno_typescript/system_loader.js +++ b/deno_typescript/system_loader.js @@ -12,14 +12,14 @@ let System, __instantiateAsync, __instantiate; System = { register(id, d, f) { r.set(id, { d, f, exp: {} }); - } + }, }; function gC(id, main) { return { id, - import: async id => r.get(id)?.exp, - meta: { url: id, main } + import: async (id) => r.get(id)?.exp, + meta: { url: id, main }, }; } @@ -30,7 +30,7 @@ let System, __instantiateAsync, __instantiate; Object.defineProperty(exp, id, { value, writable: true, - enumerable: true + enumerable: true, }); } }; @@ -73,13 +73,13 @@ let System, __instantiateAsync, __instantiate; return m.exp; } - __instantiateAsync = async m => { + __instantiateAsync = async (m) => { System = __instantiateAsync = __instantiate = undefined; rF(m); return gExpA(m); }; - __instantiate = m => { + __instantiate = (m) => { System = __instantiateAsync = __instantiate = undefined; rF(m); return gExp(m); diff --git a/std/archive/tar.ts b/std/archive/tar.ts index 2680bcff25f2fe..cafef8723a4c5f 100644 --- a/std/archive/tar.ts +++ b/std/archive/tar.ts @@ -104,68 +104,68 @@ struct posix_header { // byte offset const ustarStructure: Array<{ field: string; length: number }> = [ { field: "fileName", - length: 100 + length: 100, }, { field: "fileMode", - length: 8 + length: 8, }, { field: "uid", - length: 8 + length: 8, }, { field: "gid", - length: 8 + length: 8, }, { field: "fileSize", - length: 12 + length: 12, }, { field: "mtime", - length: 12 + length: 12, }, { field: "checksum", - length: 8 + length: 8, }, { field: "type", - length: 1 + length: 1, }, { field: "linkName", - length: 100 + length: 100, }, { field: "ustar", - length: 8 + length: 8, }, { field: "owner", - length: 32 + length: 32, }, { field: "group", - length: 32 + length: 32, }, { field: "majorNumber", - length: 8 + length: 8, }, { field: "minorNumber", - length: 8 + length: 8, }, { field: "fileNamePrefix", - length: 155 + length: 155, }, { field: "padding", - length: 12 - } + length: 12, + }, ]; /** @@ -175,7 +175,7 @@ function formatHeader(data: TarData): Uint8Array { const encoder = new TextEncoder(), buffer = clean(512); let offset = 0; - ustarStructure.forEach(function(value): void { + ustarStructure.forEach(function (value): void { const entry = encoder.encode(data[value.field as keyof TarData] || ""); buffer.set(entry, offset); offset += value.length; // space it out with nulls @@ -190,7 +190,7 @@ function formatHeader(data: TarData): Uint8Array { function parseHeader(buffer: Uint8Array): { [key: string]: Uint8Array } { const data: { [key: string]: Uint8Array } = {}; let offset = 0; - ustarStructure.forEach(function(value): void { + ustarStructure.forEach(function (value): void { const arr = buffer.subarray(offset, offset + value.length); data[value.field] = arr; offset += value.length; @@ -350,7 +350,7 @@ export class Tar { owner: opts.owner || "", group: opts.group || "", filePath: opts.filePath, - reader: opts.reader + reader: opts.reader, }; // calculate the checksum @@ -358,7 +358,7 @@ export class Tar { const encoder = new TextEncoder(); Object.keys(tarData) .filter((key): boolean => ["filePath", "reader"].indexOf(key) < 0) - .forEach(function(key): void { + .forEach(function (key): void { checksum += encoder .encode(tarData[key as keyof TarData]) .reduce((p, c): number => p + c, 0); @@ -424,7 +424,7 @@ export class Untar { decoder = new TextDecoder("ascii"); Object.keys(header) .filter((key): boolean => key !== "checksum") - .forEach(function(key): void { + .forEach(function (key): void { checksum += header[key].reduce((p, c): number => p + c, 0); }); checksum += encoder.encode(" ").reduce((p, c): number => p + c, 0); @@ -440,7 +440,7 @@ export class Untar { // get meta data const meta: UntarOptions = { - fileName: decoder.decode(trim(header.fileName)) + fileName: decoder.decode(trim(header.fileName)), }; const fileNamePrefix = trim(header.fileNamePrefix); if (fileNamePrefix.byteLength > 0) { diff --git a/std/archive/tar_test.ts b/std/archive/tar_test.ts index 1bac623b097818..ae3ee8138c0b58 100644 --- a/std/archive/tar_test.ts +++ b/std/archive/tar_test.ts @@ -23,7 +23,7 @@ Deno.test(async function createTarArchive(): Promise { const content = new TextEncoder().encode("hello tar world!"); await tar.append("output.txt", { reader: new Deno.Buffer(content), - contentSize: content.byteLength + contentSize: content.byteLength, }); // put a file @@ -49,7 +49,7 @@ Deno.test(async function deflateTarArchive(): Promise { const content = new TextEncoder().encode(text); await tar.append(fileName, { reader: new Deno.Buffer(content), - contentSize: content.byteLength + contentSize: content.byteLength, }); // read data from a tar archive @@ -73,7 +73,7 @@ Deno.test(async function appendFileWithLongNameToTarArchive(): Promise { const content = new TextEncoder().encode(text); await tar.append(fileName, { reader: new Deno.Buffer(content), - contentSize: content.byteLength + contentSize: content.byteLength, }); // read data from a tar archive diff --git a/std/bytes/mod.ts b/std/bytes/mod.ts index 0157b39a593970..88eb97710fef25 100644 --- a/std/bytes/mod.ts +++ b/std/bytes/mod.ts @@ -7,8 +7,8 @@ export function findIndex(a: Uint8Array, pat: Uint8Array): number { for (let i = 0; i < a.length; i++) { if (a[i] !== s) continue; const pin = i; - let matched = 1, - j = i; + let matched = 1; + let j = i; while (matched < pat.length) { j++; if (a[j] !== pat[j - pin]) { @@ -29,8 +29,8 @@ export function findLastIndex(a: Uint8Array, pat: Uint8Array): number { for (let i = a.length - 1; i >= 0; i--) { if (a[i] !== e) continue; const pin = i; - let matched = 1, - j = i; + let matched = 1; + let j = i; while (matched < pat.length) { j--; if (a[j] !== pat[pat.length - 1 - (pin - j)]) { @@ -94,3 +94,11 @@ export function repeat(b: Uint8Array, count: number): Uint8Array { return nb; } + +/** Concatenate two binary arrays and return new one */ +export function concat(a: Uint8Array, b: Uint8Array): Uint8Array { + const output = new Uint8Array(a.length + b.length); + output.set(a, 0); + output.set(b, a.length); + return output; +} diff --git a/std/bytes/test.ts b/std/bytes/test.ts index c1609ebdc39519..5efddf77f9662e 100644 --- a/std/bytes/test.ts +++ b/std/bytes/test.ts @@ -1,9 +1,17 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { findIndex, findLastIndex, equal, hasPrefix, repeat } from "./mod.ts"; -import { assertEquals, assertThrows } from "../testing/asserts.ts"; +import { + findIndex, + findLastIndex, + equal, + hasPrefix, + repeat, + concat, +} from "./mod.ts"; +import { assertEquals, assertThrows, assert } from "../testing/asserts.ts"; +import { encode, decode } from "../strings/mod.ts"; -Deno.test(function bytesfindIndex1(): void { +Deno.test("[bytes] findIndex1", () => { const i = findIndex( new Uint8Array([1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 3]), new Uint8Array([0, 1, 2]) @@ -11,12 +19,12 @@ Deno.test(function bytesfindIndex1(): void { assertEquals(i, 2); }); -Deno.test(function bytesfindIndex2(): void { +Deno.test("[bytes] findIndex2", () => { const i = findIndex(new Uint8Array([0, 0, 1]), new Uint8Array([0, 1])); assertEquals(i, 1); }); -Deno.test(function bytesfindLastIndex1(): void { +Deno.test("[bytes] findLastIndex1", () => { const i = findLastIndex( new Uint8Array([0, 1, 2, 0, 1, 2, 0, 1, 3]), new Uint8Array([0, 1, 2]) @@ -24,22 +32,22 @@ Deno.test(function bytesfindLastIndex1(): void { assertEquals(i, 3); }); -Deno.test(function bytesfindLastIndex2(): void { +Deno.test("[bytes] findLastIndex2", () => { const i = findLastIndex(new Uint8Array([0, 1, 1]), new Uint8Array([0, 1])); assertEquals(i, 0); }); -Deno.test(function bytesBytesequal(): void { +Deno.test("[bytes] equal", () => { const v = equal(new Uint8Array([0, 1, 2, 3]), new Uint8Array([0, 1, 2, 3])); assertEquals(v, true); }); -Deno.test(function byteshasPrefix(): void { +Deno.test("[bytes] hasPrefix", () => { const v = hasPrefix(new Uint8Array([0, 1, 2]), new Uint8Array([0, 1])); assertEquals(v, true); }); -Deno.test(function bytesrepeat(): void { +Deno.test("[bytes] repeat", () => { // input / output / count / error message const repeatTestCase = [ ["", "", 0], @@ -50,7 +58,7 @@ Deno.test(function bytesrepeat(): void { ["-", "", 0], ["-", "-", -1, "bytes: negative repeat count"], ["-", "----------", 10], - ["abc ", "abc abc abc ", 3] + ["abc ", "abc abc abc ", 3], ]; for (const [input, output, count, errMsg] of repeatTestCase) { if (errMsg) { @@ -71,3 +79,21 @@ Deno.test(function bytesrepeat(): void { } } }); + +Deno.test("[bytes] concat", () => { + const u1 = encode("Hello "); + const u2 = encode("World"); + const joined = concat(u1, u2); + assertEquals(decode(joined), "Hello World"); + assert(u1 !== joined); + assert(u2 !== joined); +}); + +Deno.test("[bytes] concat empty arrays", () => { + const u1 = new Uint8Array(); + const u2 = new Uint8Array(); + const joined = concat(u1, u2); + assertEquals(joined.byteLength, 0); + assert(u1 !== joined); + assert(u2 !== joined); +}); diff --git a/std/datetime/README.md b/std/datetime/README.md index e3d935bc0d35b8..6c29f65e49ac00 100644 --- a/std/datetime/README.md +++ b/std/datetime/README.md @@ -31,7 +31,7 @@ parseDateTime("16:34 01-20-2019", "hh:mm mm-dd-yyyy") // output : new Date(2019, ```ts import { dayOfYear, - currentDayOfYear + currentDayOfYear, } from "https://deno.land/std/datetime/mod.ts"; dayOfYear(new Date("2019-03-11T03:24:00")); // output: 70 diff --git a/std/datetime/mod.ts b/std/datetime/mod.ts index 124f7391169d9a..036cd2cc5524f3 100644 --- a/std/datetime/mod.ts +++ b/std/datetime/mod.ts @@ -145,7 +145,7 @@ export function toIMF(date: Date): string { "Sep", "Oct", "Nov", - "Dec" + "Dec", ]; return `${days[date.getUTCDay()]}, ${d} ${ months[date.getUTCMonth()] diff --git a/std/datetime/test.ts b/std/datetime/test.ts index 979fd34bec0197..dc93095f41b7ae 100644 --- a/std/datetime/test.ts +++ b/std/datetime/test.ts @@ -82,7 +82,7 @@ Deno.test({ const actual = datetime.toIMF(new Date(Date.UTC(1994, 3, 5, 15, 32))); const expected = "Tue, 05 Apr 1994 15:32:00 GMT"; assertEquals(actual, expected); - } + }, }); Deno.test({ @@ -91,5 +91,5 @@ Deno.test({ const actual = datetime.toIMF(new Date(0)); const expected = "Thu, 01 Jan 1970 00:00:00 GMT"; assertEquals(actual, expected); - } + }, }); diff --git a/std/encoding/README.md b/std/encoding/README.md index 2b2d416b19e511..e6604c60503536 100644 --- a/std/encoding/README.md +++ b/std/encoding/README.md @@ -39,7 +39,7 @@ const string = "a,b,c\nd,e,f"; console.log( await parseCsv(string, { - header: false + header: false, }) ); // output: @@ -161,9 +161,9 @@ import { stringify } from "./parser.ts"; const obj = { bin: [ { name: "deno", path: "cli/main.rs" }, - { name: "deno_core", path: "src/foo.rs" } + { name: "deno_core", path: "src/foo.rs" }, ], - nib: [{ name: "node", path: "not_found" }] + nib: [{ name: "node", path: "not_found" }], }; const tomlString = stringify(obj); ``` diff --git a/std/encoding/base32_test.ts b/std/encoding/base32_test.ts index 28550d57a523e7..2bd7acea1fb638 100644 --- a/std/encoding/base32_test.ts +++ b/std/encoding/base32_test.ts @@ -6,7 +6,7 @@ import { encode, decode } from "./base32.ts"; // Lifted from https://stackoverflow.com/questions/38987784 const fromHexString = (hexString: string): Uint8Array => - new Uint8Array(hexString.match(/.{1,2}/g)!.map(byte => parseInt(byte, 16))); + new Uint8Array(hexString.match(/.{1,2}/g)!.map((byte) => parseInt(byte, 16))); const toHexString = (bytes: Uint8Array): string => bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, "0"), ""); @@ -34,56 +34,56 @@ const testCases = [ ["ddf80ebe21bf1b1e12a64c5cc6a74b5d92dd", "3X4A5PRBX4NR4EVGJROMNJ2LLWJN2==="], [ "c0cae52c6f641ce04a7ee5b9a8fa8ded121bca", - "YDFOKLDPMQOOAST64W42R6UN5UJBXSQ=" + "YDFOKLDPMQOOAST64W42R6UN5UJBXSQ=", ], [ "872840a355c8c70586f462c9e669ee760cb3537e", - "Q4UEBI2VZDDQLBXUMLE6M2POOYGLGU36" + "Q4UEBI2VZDDQLBXUMLE6M2POOYGLGU36", ], [ "5773fe22662818a120c5688824c935fe018208a496", - "K5Z74ITGFAMKCIGFNCECJSJV7YAYECFESY======" + "K5Z74ITGFAMKCIGFNCECJSJV7YAYECFESY======", ], [ "416e23abc524d1b85736e2bea6cfecd5192789034a28", - "IFXCHK6FETI3QVZW4K7KNT7M2UMSPCIDJIUA====" + "IFXCHK6FETI3QVZW4K7KNT7M2UMSPCIDJIUA====", ], [ "83d2386ebdd7e8e818ec00e3ccd882aa933b905b7e2e44", - "QPJDQ3V527UOQGHMADR4ZWECVKJTXEC3PYXEI===" + "QPJDQ3V527UOQGHMADR4ZWECVKJTXEC3PYXEI===", ], [ "a2fa8b881f3b8024f52745763c4ae08ea12bdf8bef1a72f8", - "UL5IXCA7HOACJ5JHIV3DYSXAR2QSXX4L54NHF6A=" + "UL5IXCA7HOACJ5JHIV3DYSXAR2QSXX4L54NHF6A=", ], [ "b074ae8b9efde0f17f37bccadde006d039997b59c8efb05add", - "WB2K5C467XQPC7ZXXTFN3YAG2A4ZS62ZZDX3AWW5" + "WB2K5C467XQPC7ZXXTFN3YAG2A4ZS62ZZDX3AWW5", ], [ "764fef941aee7e416dc204ae5ab9c5b9ce644567798e6849aea9", - "OZH67FA25Z7EC3OCASXFVOOFXHHGIRLHPGHGQSNOVE======" + "OZH67FA25Z7EC3OCASXFVOOFXHHGIRLHPGHGQSNOVE======", ], [ "4995d9811f37f59797d7c3b9b9e5325aa78277415f70f4accf588c", - "JGK5TAI7G72ZPF6XYO43TZJSLKTYE52BL5YPJLGPLCGA====" + "JGK5TAI7G72ZPF6XYO43TZJSLKTYE52BL5YPJLGPLCGA====", ], [ "24f0812ca8eed58374c11a7008f0b262698b72fd2792709208eaacb2", - "ETYICLFI53KYG5GBDJYAR4FSMJUYW4X5E6JHBEQI5KWLE===" + "ETYICLFI53KYG5GBDJYAR4FSMJUYW4X5E6JHBEQI5KWLE===", ], [ "d70692543810d4bf50d81cf44a55801a557a388a341367c7ea077ca306", - "24DJEVBYCDKL6UGYDT2EUVMADJKXUOEKGQJWPR7KA56KGBQ=" + "24DJEVBYCDKL6UGYDT2EUVMADJKXUOEKGQJWPR7KA56KGBQ=", ], [ "6e08a89ca36b677ff8fe99e68a1241c8d8cef2570a5f60b6417d2538b30c", - "NYEKRHFDNNTX76H6THTIUESBZDMM54SXBJPWBNSBPUSTRMYM" + "NYEKRHFDNNTX76H6THTIUESBZDMM54SXBJPWBNSBPUSTRMYM", ], [ "f2fc2319bd29457ccd01e8e194ee9bd7e97298b6610df4ab0f3d5baa0b2d7ccf69829edb74edef", - "6L6CGGN5FFCXZTIB5DQZJ3U327UXFGFWMEG7JKYPHVN2UCZNPTHWTAU63N2O33Y=" - ] + "6L6CGGN5FFCXZTIB5DQZJ3U327UXFGFWMEG7JKYPHVN2UCZNPTHWTAU63N2O33Y=", + ], ]; Deno.test({ @@ -92,7 +92,7 @@ Deno.test({ for (const [bin, b32] of testCases) { assertEquals(encode(fromHexString(bin)), b32); } - } + }, }); Deno.test({ @@ -101,7 +101,7 @@ Deno.test({ for (const [bin, b32] of testCases) { assertEquals(toHexString(decode(b32)), bin); } - } + }, }); Deno.test({ @@ -117,7 +117,7 @@ Deno.test({ errorCaught = true; } assert(errorCaught); - } + }, }); Deno.test({ @@ -131,5 +131,5 @@ Deno.test({ errorCaught = true; } assert(errorCaught); - } + }, }); diff --git a/std/encoding/binary.ts b/std/encoding/binary.ts index 2eec9b4ab46715..cd338703b10921 100644 --- a/std/encoding/binary.ts +++ b/std/encoding/binary.ts @@ -34,7 +34,7 @@ const rawTypeSizes = { int64: 8, uint64: 8, float32: 4, - float64: 8 + float64: 8, }; /** Returns the number of bytes required to store the given data-type. */ diff --git a/std/encoding/binary_test.ts b/std/encoding/binary_test.ts index 54f8cbded5f3f0..084ca2fa49b925 100644 --- a/std/encoding/binary_test.ts +++ b/std/encoding/binary_test.ts @@ -11,7 +11,7 @@ import { varbig, varnum, writeVarbig, - writeVarnum + writeVarnum, } from "./binary.ts"; Deno.test(async function testGetNBytes(): Promise { diff --git a/std/encoding/csv.ts b/std/encoding/csv.ts index 12336b10ddccd6..c8c7719cab5624 100644 --- a/std/encoding/csv.ts +++ b/std/encoding/csv.ts @@ -118,7 +118,7 @@ export async function readMatrix( opt: ReadOptions = { comma: ",", trimLeadingSpace: false, - lazyQuotes: false + lazyQuotes: false, } ): Promise { const result: string[][] = []; @@ -195,7 +195,7 @@ export interface ParseOptions extends ReadOptions { export async function parse( input: string | BufReader, opt: ParseOptions = { - header: false + header: false, } ): Promise { let r: string[][]; @@ -215,7 +215,7 @@ export async function parse( headers = h.map( (e): HeaderOptions => { return { - name: e + name: e, }; } ); @@ -226,7 +226,7 @@ export async function parse( headers = head.map( (e): HeaderOptions => { return { - name: e + name: e, }; } ); diff --git a/std/encoding/csv_test.ts b/std/encoding/csv_test.ts index 74ad00c72ce74a..cb61de43394083 100644 --- a/std/encoding/csv_test.ts +++ b/std/encoding/csv_test.ts @@ -14,20 +14,20 @@ const testCases = [ { Name: "Simple", Input: "a,b,c\n", - Output: [["a", "b", "c"]] + Output: [["a", "b", "c"]], }, { Name: "CRLF", Input: "a,b\r\nc,d\r\n", Output: [ ["a", "b"], - ["c", "d"] - ] + ["c", "d"], + ], }, { Name: "BareCR", Input: "a,b\rc,d\r\n", - Output: [["a", "b\rc", "d"]] + Output: [["a", "b\rc", "d"]], }, { Name: "RFC4180test", @@ -41,20 +41,20 @@ zzz,yyy,xxx`, ["#field1", "field2", "field3"], ["aaa", "bbb", "ccc"], ["a,a", `bbb`, "ccc"], - ["zzz", "yyy", "xxx"] + ["zzz", "yyy", "xxx"], ], - ignore: true + ignore: true, }, { Name: "NoEOLTest", Input: "a,b,c", - Output: [["a", "b", "c"]] + Output: [["a", "b", "c"]], }, { Name: "Semicolon", Input: "a;b;c\n", Output: [["a", "b", "c"]], - Comma: ";" + Comma: ";", }, { Name: "MultiLine", @@ -63,103 +63,103 @@ line","one line","three line field"`, Output: [["two\nline"], ["one line"], ["three\nline\nfield"]], - ignore: true + ignore: true, }, { Name: "BlankLine", Input: "a,b,c\n\nd,e,f\n\n", Output: [ ["a", "b", "c"], - ["d", "e", "f"] - ] + ["d", "e", "f"], + ], }, { Name: "BlankLineFieldCount", Input: "a,b,c\n\nd,e,f\n\n", Output: [ ["a", "b", "c"], - ["d", "e", "f"] + ["d", "e", "f"], ], UseFieldsPerRecord: true, - FieldsPerRecord: 0 + FieldsPerRecord: 0, }, { Name: "TrimSpace", Input: " a, b, c\n", Output: [["a", "b", "c"]], - TrimLeadingSpace: true + TrimLeadingSpace: true, }, { Name: "LeadingSpace", Input: " a, b, c\n", - Output: [[" a", " b", " c"]] + Output: [[" a", " b", " c"]], }, { Name: "Comment", Input: "#1,2,3\na,b,c\n#comment", Output: [["a", "b", "c"]], - Comment: "#" + Comment: "#", }, { Name: "NoComment", Input: "#1,2,3\na,b,c", Output: [ ["#1", "2", "3"], - ["a", "b", "c"] - ] + ["a", "b", "c"], + ], }, { Name: "LazyQuotes", Input: `a "word","1"2",a","b`, Output: [[`a "word"`, `1"2`, `a"`, `b`]], - LazyQuotes: true + LazyQuotes: true, }, { Name: "BareQuotes", Input: `a "word","1"2",a"`, Output: [[`a "word"`, `1"2`, `a"`]], - LazyQuotes: true + LazyQuotes: true, }, { Name: "BareDoubleQuotes", Input: `a""b,c`, Output: [[`a""b`, `c`]], - LazyQuotes: true + LazyQuotes: true, }, { Name: "BadDoubleQuotes", Input: `a""b,c`, - Error: ErrBareQuote + Error: ErrBareQuote, // Error: &ParseError{StartLine: 1, Line: 1, Column: 1, Err: ErrBareQuote}, }, { Name: "TrimQuote", Input: ` "a"," b",c`, Output: [["a", " b", "c"]], - TrimLeadingSpace: true + TrimLeadingSpace: true, }, { Name: "BadBareQuote", Input: `a "word","b"`, - Error: ErrBareQuote + Error: ErrBareQuote, // &ParseError{StartLine: 1, Line: 1, Column: 2, Err: ErrBareQuote} }, { Name: "BadTrailingQuote", Input: `"a word",b"`, - Error: ErrBareQuote + Error: ErrBareQuote, }, { Name: "ExtraneousQuote", Input: `"a "word","b"`, - Error: ErrBareQuote + Error: ErrBareQuote, }, { Name: "BadFieldCount", Input: "a,b,c\nd,e", Error: ErrFieldCount, UseFieldsPerRecord: true, - FieldsPerRecord: 0 + FieldsPerRecord: 0, }, { Name: "BadFieldCount1", @@ -167,37 +167,37 @@ field"`, // Error: &ParseError{StartLine: 1, Line: 1, Err: ErrFieldCount}, UseFieldsPerRecord: true, FieldsPerRecord: 2, - Error: ErrFieldCount + Error: ErrFieldCount, }, { Name: "FieldCount", Input: "a,b,c\nd,e", Output: [ ["a", "b", "c"], - ["d", "e"] - ] + ["d", "e"], + ], }, { Name: "TrailingCommaEOF", Input: "a,b,c,", - Output: [["a", "b", "c", ""]] + Output: [["a", "b", "c", ""]], }, { Name: "TrailingCommaEOL", Input: "a,b,c,\n", - Output: [["a", "b", "c", ""]] + Output: [["a", "b", "c", ""]], }, { Name: "TrailingCommaSpaceEOF", Input: "a,b,c, ", Output: [["a", "b", "c", ""]], - TrimLeadingSpace: true + TrimLeadingSpace: true, }, { Name: "TrailingCommaSpaceEOL", Input: "a,b,c, \n", Output: [["a", "b", "c", ""]], - TrimLeadingSpace: true + TrimLeadingSpace: true, }, { Name: "TrailingCommaLine3", @@ -205,14 +205,14 @@ field"`, Output: [ ["a", "b", "c"], ["d", "e", "f"], - ["g", "hi", ""] + ["g", "hi", ""], ], - TrimLeadingSpace: true + TrimLeadingSpace: true, }, { Name: "NotTrailingComma3", Input: "a,b,c, \n", - Output: [["a", "b", "c", " "]] + Output: [["a", "b", "c", " "]], }, { Name: "CommaFieldTest", @@ -237,98 +237,98 @@ x,,, ["x", "y", "z", ""], ["x", "y", "", ""], ["x", "", "", ""], - ["", "", "", ""] - ] + ["", "", "", ""], + ], }, { Name: "TrailingCommaIneffective1", Input: "a,b,\nc,d,e", Output: [ ["a", "b", ""], - ["c", "d", "e"] + ["c", "d", "e"], ], - TrimLeadingSpace: true + TrimLeadingSpace: true, }, { Name: "ReadAllReuseRecord", Input: "a,b\nc,d", Output: [ ["a", "b"], - ["c", "d"] + ["c", "d"], ], - ReuseRecord: true + ReuseRecord: true, }, { Name: "StartLine1", // Issue 19019 Input: 'a,"b\nc"d,e', Error: true, // Error: &ParseError{StartLine: 1, Line: 2, Column: 1, Err: ErrQuote}, - ignore: true + ignore: true, }, { Name: "StartLine2", Input: 'a,b\n"d\n\n,e', Error: true, // Error: &ParseError{StartLine: 2, Line: 5, Column: 0, Err: ErrQuote}, - ignore: true + ignore: true, }, { Name: "CRLFInQuotedField", // Issue 21201 Input: 'A,"Hello\r\nHi",B\r\n', Output: [["A", "Hello\nHi", "B"]], - ignore: true + ignore: true, }, { Name: "BinaryBlobField", // Issue 19410 Input: "x09\x41\xb4\x1c,aktau", - Output: [["x09A\xb4\x1c", "aktau"]] + Output: [["x09A\xb4\x1c", "aktau"]], }, { Name: "TrailingCR", Input: "field1,field2\r", Output: [["field1", "field2"]], - ignore: true + ignore: true, }, { Name: "QuotedTrailingCR", Input: '"field"\r', Output: [['"field"']], - ignore: true + ignore: true, }, { Name: "QuotedTrailingCRCR", Input: '"field"\r\r', Error: true, // Error: &ParseError{StartLine: 1, Line: 1, Column: 6, Err: ErrQuote}, - ignore: true + ignore: true, }, { Name: "FieldCR", Input: "field\rfield\r", Output: [["field\rfield"]], - ignore: true + ignore: true, }, { Name: "FieldCRCR", Input: "field\r\rfield\r\r", Output: [["field\r\rfield\r"]], - ignore: true + ignore: true, }, { Name: "FieldCRCRLF", Input: "field\r\r\nfield\r\r\n", - Output: [["field\r"], ["field\r"]] + Output: [["field\r"], ["field\r"]], }, { Name: "FieldCRCRLFCR", Input: "field\r\r\n\rfield\r\r\n\r", - Output: [["field\r"], ["\rfield\r"]] + Output: [["field\r"], ["\rfield\r"]], }, { Name: "FieldCRCRLFCRCR", Input: "field\r\r\n\r\rfield\r\r\n\r\r", Output: [["field\r"], ["\r\rfield\r"], ["\r"]], - ignore: true + ignore: true, }, { Name: "MultiFieldCRCRLFCRCR", @@ -336,9 +336,9 @@ x,,, Output: [ ["field1", "field2\r"], ["\r\rfield1", "field2\r"], - ["\r\r", ""] + ["\r\r", ""], ], - ignore: true + ignore: true, }, { Name: "NonASCIICommaAndComment", @@ -346,14 +346,14 @@ x,,, Output: [["a", "b,c", "d,e"]], TrimLeadingSpace: true, Comma: "£", - Comment: "€" + Comment: "€", }, { Name: "NonASCIICommaAndCommentWithQuotes", Input: 'a€" b,"€ c\nλ comment\n', Output: [["a", " b,", " c"]], Comma: "€", - Comment: "λ" + Comment: "λ", }, { // λ and θ start with the same byte. @@ -362,24 +362,24 @@ x,,, Input: '"abθcd"λefθgh', Output: [["abθcd", "efθgh"]], Comma: "λ", - Comment: "€" + Comment: "€", }, { Name: "NonASCIICommentConfusion", Input: "λ\nλ\nθ\nλ\n", Output: [["λ"], ["λ"], ["λ"]], - Comment: "θ" + Comment: "θ", }, { Name: "QuotedFieldMultipleLF", Input: '"\n\n\n\n"', Output: [["\n\n\n\n"]], - ignore: true + ignore: true, }, { Name: "MultipleCRLF", Input: "\r\n\r\n\r\n\r\n", - ignore: true + ignore: true, }, /** * The implementation may read each line in several chunks if @@ -392,77 +392,77 @@ x,,, "#ignore\n".repeat(10000) + "@".repeat(5000) + "," + "*".repeat(5000), Output: [["@".repeat(5000), "*".repeat(5000)]], Comment: "#", - ignore: true + ignore: true, }, { Name: "QuoteWithTrailingCRLF", Input: '"foo"bar"\r\n', - Error: ErrBareQuote + Error: ErrBareQuote, // Error: &ParseError{StartLine: 1, Line: 1, Column: 4, Err: ErrQuote}, }, { Name: "LazyQuoteWithTrailingCRLF", Input: '"foo"bar"\r\n', Output: [[`foo"bar`]], - LazyQuotes: true + LazyQuotes: true, }, { Name: "DoubleQuoteWithTrailingCRLF", Input: '"foo""bar"\r\n', Output: [[`foo"bar`]], - ignore: true + ignore: true, }, { Name: "EvenQuotes", Input: `""""""""`, Output: [[`"""`]], - ignore: true + ignore: true, }, { Name: "OddQuotes", Input: `"""""""`, Error: true, // Error:" &ParseError{StartLine: 1, Line: 1, Column: 7, Err: ErrQuote}", - ignore: true + ignore: true, }, { Name: "LazyOddQuotes", Input: `"""""""`, Output: [[`"""`]], LazyQuotes: true, - ignore: true + ignore: true, }, { Name: "BadComma1", Comma: "\n", - Error: ErrInvalidDelim + Error: ErrInvalidDelim, }, { Name: "BadComma2", Comma: "\r", - Error: ErrInvalidDelim + Error: ErrInvalidDelim, }, { Name: "BadComma3", Comma: '"', - Error: ErrInvalidDelim + Error: ErrInvalidDelim, }, { Name: "BadComment1", Comment: "\n", - Error: ErrInvalidDelim + Error: ErrInvalidDelim, }, { Name: "BadComment2", Comment: "\r", - Error: ErrInvalidDelim + Error: ErrInvalidDelim, }, { Name: "BadCommaComment", Comma: "X", Comment: "X", - Error: ErrInvalidDelim - } + Error: ErrInvalidDelim, + }, ]; for (const t of testCases) { Deno.test({ @@ -500,7 +500,7 @@ for (const t of testCases) { comment: comment, trimLeadingSpace: trim, fieldsPerRecord: fieldsPerRec, - lazyQuotes: lazyquote + lazyQuotes: lazyquote, } ); } catch (e) { @@ -516,13 +516,13 @@ for (const t of testCases) { comment: comment, trimLeadingSpace: trim, fieldsPerRecord: fieldsPerRec, - lazyQuotes: lazyquote + lazyQuotes: lazyquote, } ); const expected = t.Output; assertEquals(actual, expected); } - } + }, }); } @@ -531,13 +531,13 @@ const parseTestCases = [ name: "simple", in: "a,b,c", header: false, - result: [["a", "b", "c"]] + result: [["a", "b", "c"]], }, { name: "simple Bufreader", in: new BufReader(new StringReader("a,b,c")), header: false, - result: [["a", "b", "c"]] + result: [["a", "b", "c"]], }, { name: "multiline", @@ -545,14 +545,14 @@ const parseTestCases = [ header: false, result: [ ["a", "b", "c"], - ["e", "f", "g"] - ] + ["e", "f", "g"], + ], }, { name: "header mapping boolean", in: "a,b,c\ne,f,g\n", header: true, - result: [{ a: "e", b: "f", c: "g" }] + result: [{ a: "e", b: "f", c: "g" }], }, { name: "header mapping array", @@ -560,8 +560,8 @@ const parseTestCases = [ header: ["this", "is", "sparta"], result: [ { this: "a", is: "b", sparta: "c" }, - { this: "e", is: "f", sparta: "g" } - ] + { this: "e", is: "f", sparta: "g" }, + ], }, { name: "header mapping object", @@ -569,8 +569,8 @@ const parseTestCases = [ header: [{ name: "this" }, { name: "is" }, { name: "sparta" }], result: [ { this: "a", is: "b", sparta: "c" }, - { this: "e", is: "f", sparta: "g" } - ] + { this: "e", is: "f", sparta: "g" }, + ], }, { name: "header mapping parse entry", @@ -580,25 +580,25 @@ const parseTestCases = [ name: "this", parse: (e: string): string => { return `b${e}$$`; - } + }, }, { name: "is", parse: (e: string): number => { return e.length; - } + }, }, { name: "sparta", parse: (e: string): unknown => { return { bim: `boom-${e}` }; - } - } + }, + }, ], result: [ { this: "ba$$", is: 1, sparta: { bim: `boom-c` } }, - { this: "be$$", is: 1, sparta: { bim: `boom-g` } } - ] + { this: "be$$", is: 1, sparta: { bim: `boom-g` } }, + ], }, { name: "multiline parse", @@ -609,8 +609,8 @@ const parseTestCases = [ header: false, result: [ { super: "a", street: "b", fighter: "c" }, - { super: "e", street: "f", fighter: "g" } - ] + { super: "e", street: "f", fighter: "g" }, + ], }, { name: "header mapping object parseline", @@ -621,9 +621,9 @@ const parseTestCases = [ }, result: [ { super: "a", street: "b", fighter: "c" }, - { super: "e", street: "f", fighter: "g" } - ] - } + { super: "e", street: "f", fighter: "g" }, + ], + }, ]; for (const testCase of parseTestCases) { @@ -632,9 +632,9 @@ for (const testCase of parseTestCases) { async fn(): Promise { const r = await parse(testCase.in, { header: testCase.header, - parse: testCase.parse as (input: unknown) => unknown + parse: testCase.parse as (input: unknown) => unknown, }); assertEquals(r, testCase.result); - } + }, }); } diff --git a/std/encoding/hex_test.ts b/std/encoding/hex_test.ts index f98fe5422d484c..56bdbf4f0bcb70 100644 --- a/std/encoding/hex_test.ts +++ b/std/encoding/hex_test.ts @@ -14,7 +14,7 @@ import { decode, decodeString, errLength, - errInvalidByte + errInvalidByte, } from "./hex.ts"; function toByte(s: string): number { @@ -29,7 +29,7 @@ const testCases = [ ["f0f1f2f3f4f5f6f7", [0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7]], ["f8f9fafbfcfdfeff", [0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff]], ["67", Array.from(new TextEncoder().encode("g"))], - ["e3a1", [0xe3, 0xa1]] + ["e3a1", [0xe3, 0xa1]], ]; const errCases = [ @@ -42,7 +42,7 @@ const errCases = [ ["0g", "", errInvalidByte(new TextEncoder().encode("g")[0])], ["00gg", "\x00", errInvalidByte(new TextEncoder().encode("g")[0])], ["0\x01", "", errInvalidByte(new TextEncoder().encode("\x01")[0])], - ["ffeed", "\xff\xee", errLength()] + ["ffeed", "\xff\xee", errLength()], ]; Deno.test({ @@ -53,7 +53,7 @@ Deno.test({ assertEquals(encodedLen(2), 4); assertEquals(encodedLen(3), 6); assertEquals(encodedLen(4), 8); - } + }, }); Deno.test({ @@ -88,7 +88,7 @@ Deno.test({ assertEquals(dest.length, n); assertEquals(new TextDecoder().decode(dest), enc); } - } + }, }); Deno.test({ @@ -97,7 +97,7 @@ Deno.test({ for (const [enc, dec] of testCases) { assertEquals(encodeToString(new Uint8Array(dec as number[])), enc); } - } + }, }); Deno.test({ @@ -108,7 +108,7 @@ Deno.test({ assertEquals(decodedLen(4), 2); assertEquals(decodedLen(6), 3); assertEquals(decodedLen(8), 4); - } + }, }); Deno.test({ @@ -117,7 +117,7 @@ Deno.test({ // Case for decoding uppercase hex characters, since // Encode always uses lowercase. const extraTestcase = [ - ["F8F9FAFBFCFDFEFF", [0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff]] + ["F8F9FAFBFCFDFEFF", [0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff]], ]; const cases = testCases.concat(extraTestcase); @@ -129,7 +129,7 @@ Deno.test({ assertEquals(err, undefined); assertEquals(Array.from(dest), Array.from(dec as number[])); } - } + }, }); Deno.test({ @@ -140,7 +140,7 @@ Deno.test({ assertEquals(dec, Array.from(dst)); } - } + }, }); Deno.test({ @@ -155,7 +155,7 @@ Deno.test({ ); assertEquals(err, expectedErr); } - } + }, }); Deno.test({ @@ -175,5 +175,5 @@ Deno.test({ assertEquals(new TextDecoder("ascii").decode(out), output as string); } } - } + }, }); diff --git a/std/encoding/mod.ts b/std/encoding/mod.ts index d63cf47f328a37..eaa28ae278e62d 100644 --- a/std/encoding/mod.ts +++ b/std/encoding/mod.ts @@ -2,13 +2,13 @@ export { HeaderOptions as CsvHeaderOptions, ParseError as CsvParseError, ParseOptions as ParseCsvOptions, - parse as parseCsv + parse as parseCsv, } from "./csv.ts"; export { decode as decodeHex, decodeString as decodeHexString, encode as encodeToHex, - encodeToString as encodeToHexString + encodeToString as encodeToHexString, } from "./hex.ts"; export { parse as parseToml, stringify as tomlStringify } from "./toml.ts"; export { parse as parseYaml, stringify as yamlStringify } from "./yaml.ts"; diff --git a/std/encoding/toml_test.ts b/std/encoding/toml_test.ts index 425b8a22c6681e..d272a29ffe526d 100644 --- a/std/encoding/toml_test.ts +++ b/std/encoding/toml_test.ts @@ -29,12 +29,12 @@ Deno.test({ str6: "The quick brown\nfox jumps over\nthe lazy dog.", lines: "The first newline is\ntrimmed in raw strings.\n All other " + - "whitespace\n is preserved." - } + "whitespace\n is preserved.", + }, }; const actual = parseFile(path.join(testFilesDir, "string.toml")); assertEquals(actual, expected); - } + }, }); Deno.test({ @@ -43,7 +43,7 @@ Deno.test({ const expected = { boolean: { bool1: true, bool2: false } }; const actual = parseFile(path.join(testFilesDir, "CRLF.toml")); assertEquals(actual, expected); - } + }, }); Deno.test({ @@ -52,7 +52,7 @@ Deno.test({ const expected = { boolean: { bool1: true, bool2: false } }; const actual = parseFile(path.join(testFilesDir, "boolean.toml")); assertEquals(actual, expected); - } + }, }); Deno.test({ @@ -72,12 +72,12 @@ Deno.test({ hex3: "0xdead_beef", oct1: "0o01234567", oct2: "0o755", - bin1: "0b11010110" - } + bin1: "0b11010110", + }, }; const actual = parseFile(path.join(testFilesDir, "integer.toml")); assertEquals(actual, expected); - } + }, }); Deno.test({ @@ -98,12 +98,12 @@ Deno.test({ sf3: -Infinity, sf4: NaN, sf5: NaN, - sf6: NaN - } + sf6: NaN, + }, }; const actual = parseFile(path.join(testFilesDir, "float.toml")); assertEquals(actual, expected); - } + }, }); Deno.test({ @@ -113,14 +113,14 @@ Deno.test({ arrays: { data: [ ["gamma", "delta"], - [1, 2] + [1, 2], ], - hosts: ["alpha", "omega"] - } + hosts: ["alpha", "omega"], + }, }; const actual = parseFile(path.join(testFilesDir, "arrays.toml")); assertEquals(actual, expected); - } + }, }); Deno.test({ @@ -133,27 +133,27 @@ Deno.test({ in: { the: { toml: { - name: "Tom Preston-Werner" - } - } - } - } - } + name: "Tom Preston-Werner", + }, + }, + }, + }, + }, }, servers: { alpha: { ip: "10.0.0.1", - dc: "eqdc10" + dc: "eqdc10", }, beta: { ip: "10.0.0.2", - dc: "eqdc20" - } - } + dc: "eqdc20", + }, + }, }; const actual = parseFile(path.join(testFilesDir, "table.toml")); assertEquals(actual, expected); - } + }, }); Deno.test({ @@ -164,11 +164,11 @@ Deno.test({ not: "[node]", regex: "", NANI: "何?!", - comment: "Comment inside # the comment" + comment: "Comment inside # the comment", }; const actual = parseFile(path.join(testFilesDir, "simple.toml")); assertEquals(actual, expected); - } + }, }); Deno.test({ @@ -182,12 +182,12 @@ Deno.test({ odt4: new Date("1979-05-27 07:32:00Z"), ld1: new Date("1979-05-27"), lt1: "07:32:00", - lt2: "00:32:00.999999" - } + lt2: "00:32:00.999999", + }, }; const actual = parseFile(path.join(testFilesDir, "datetime.toml")); assertEquals(actual, expected); - } + }, }); Deno.test({ @@ -200,39 +200,39 @@ Deno.test({ malevolant: { creation: { drum: { - kit: "Tama" - } - } - } + kit: "Tama", + }, + }, + }, }, derek: { - roddy: "drummer" - } + roddy: "drummer", + }, }, name: { first: "Tom", - last: "Preston-Werner" + last: "Preston-Werner", }, point: { x: 1, - y: 2 + y: 2, }, dog: { type: { - name: "pug" - } + name: "pug", + }, }, "tosin.abasi": "guitarist", animal: { as: { - leaders: "tosin" - } - } - } + leaders: "tosin", + }, + }, + }, }; const actual = parseFile(path.join(testFilesDir, "inlineTable.toml")); assertEquals(actual, expected); - } + }, }); Deno.test({ @@ -241,13 +241,13 @@ Deno.test({ const expected = { bin: [ { name: "deno", path: "cli/main.rs" }, - { name: "deno_core", path: "src/foo.rs" } + { name: "deno_core", path: "src/foo.rs" }, ], - nib: [{ name: "node", path: "not_found" }] + nib: [{ name: "node", path: "not_found" }], }; const actual = parseFile(path.join(testFilesDir, "arrayTable.toml")); assertEquals(actual, expected); - } + }, }); Deno.test({ @@ -286,14 +286,14 @@ Deno.test({ "tokio-io": "0.1.11", "tokio-process": "0.2.3", "tokio-threadpool": "0.1.11", - url: "1.7.2" + url: "1.7.2", }, - target: { "cfg(windows)": { dependencies: { winapi: "0.3.6" } } } + target: { "cfg(windows)": { dependencies: { winapi: "0.3.6" } } }, }; /* eslint-enable @typescript-eslint/camelcase */ const actual = parseFile(path.join(testFilesDir, "cargo.toml")); assertEquals(actual, expected); - } + }, }); Deno.test({ @@ -303,15 +303,15 @@ Deno.test({ foo: { bar: "deno" }, this: { is: { nested: "denonono" } }, "https://deno.land/std": { - $: "doller" + $: "doller", }, "##": { deno: { "https://deno.land": { proto: "https", - ":80": "port" - } - } + ":80": "port", + }, + }, }, arrayObjects: [{ stuff: "in" }, {}, { the: "array" }], deno: "is", @@ -347,9 +347,9 @@ Deno.test({ sf6: NaN, data: [ ["gamma", "delta"], - [1, 2] + [1, 2], ], - hosts: ["alpha", "omega"] + hosts: ["alpha", "omega"], }; const expected = `deno = "is" not = "[node]" @@ -408,5 +408,5 @@ the = "array" `; const actual = stringify(src); assertEquals(actual, expected); - } + }, }); diff --git a/std/encoding/yaml.ts b/std/encoding/yaml.ts index a8784319b35059..76b1b8379c18d9 100644 --- a/std/encoding/yaml.ts +++ b/std/encoding/yaml.ts @@ -6,6 +6,6 @@ export { ParseOptions, parse, parseAll } from "./yaml/parse.ts"; export { DumpOptions as StringifyOptions, - stringify + stringify, } from "./yaml/stringify.ts"; export * from "./yaml/schema/mod.ts"; diff --git a/std/encoding/yaml/dumper/dumper.ts b/std/encoding/yaml/dumper/dumper.ts index 3a34e14cc7d119..1280ee75729379 100644 --- a/std/encoding/yaml/dumper/dumper.ts +++ b/std/encoding/yaml/dumper/dumper.ts @@ -73,7 +73,7 @@ const DEPRECATED_BOOLEANS_SYNTAX = [ "NO", "off", "Off", - "OFF" + "OFF", ]; function encodeHex(character: number): string { diff --git a/std/encoding/yaml/dumper/dumper_state.ts b/std/encoding/yaml/dumper/dumper_state.ts index 88164a0d235d61..94cd84878fbdbe 100644 --- a/std/encoding/yaml/dumper/dumper_state.ts +++ b/std/encoding/yaml/dumper/dumper_state.ts @@ -121,7 +121,7 @@ export class DumperState extends State { lineWidth = 80, noRefs = false, noCompatMode = false, - condenseFlow = false + condenseFlow = false, }: DumperStateOptions) { super(schema); this.indent = Math.max(1, indent); diff --git a/std/encoding/yaml/example/dump.ts b/std/encoding/yaml/example/dump.ts index 746c3be01bf53d..db3647274ce1d2 100644 --- a/std/encoding/yaml/example/dump.ts +++ b/std/encoding/yaml/example/dump.ts @@ -10,13 +10,13 @@ console.log( "a", "b", { - a: false + a: false, }, { - a: false - } - ] + a: false, + }, + ], }, - test: "foobar" + test: "foobar", }) ); diff --git a/std/encoding/yaml/example/inout.ts b/std/encoding/yaml/example/inout.ts index 80cad82587159e..b0b47e3fe82562 100644 --- a/std/encoding/yaml/example/inout.ts +++ b/std/encoding/yaml/example/inout.ts @@ -9,14 +9,14 @@ const test = { "a", "b", { - a: false + a: false, }, { - a: false - } - ] + a: false, + }, + ], }, - test: "foobar" + test: "foobar", }; const string = stringify(test); diff --git a/std/encoding/yaml/loader/loader.ts b/std/encoding/yaml/loader/loader.ts index 1ab4fc7f5b5ea4..f0d53562469855 100644 --- a/std/encoding/yaml/loader/loader.ts +++ b/std/encoding/yaml/loader/loader.ts @@ -37,11 +37,11 @@ function _class(obj: unknown): string { } function isEOL(c: number): boolean { - return c === 0x0a /* LF */ || c === 0x0d /* CR */; + return c === 0x0a || /* LF */ c === 0x0d /* CR */; } function isWhiteSpace(c: number): boolean { - return c === 0x09 /* Tab */ || c === 0x20 /* Space */; + return c === 0x09 || /* Tab */ c === 0x20 /* Space */; } function isWsOrEol(c: number): boolean { @@ -64,13 +64,13 @@ function isFlowIndicator(c: number): boolean { } function fromHexCode(c: number): number { - if (0x30 /* 0 */ <= c && c <= 0x39 /* 9 */) { + if (0x30 <= /* 0 */ c && c <= 0x39 /* 9 */) { return c - 0x30; } const lc = c | 0x20; - if (0x61 /* a */ <= lc && lc <= 0x66 /* f */) { + if (0x61 <= /* a */ lc && lc <= 0x66 /* f */) { return lc - 0x61 + 10; } @@ -91,7 +91,7 @@ function escapedHexLen(c: number): number { } function fromDecimalCode(c: number): number { - if (0x30 /* 0 */ <= c && c <= 0x39 /* 9 */) { + if (0x30 <= /* 0 */ c && c <= 0x39 /* 9 */) { return c - 0x30; } @@ -251,7 +251,7 @@ const directiveHandlers: DirectiveHandlers = { state.tagMap = {}; } state.tagMap[handle] = prefix; - } + }, }; function captureSegment( @@ -414,7 +414,7 @@ function skipSeparationSpace( if (allowComments && ch === 0x23 /* # */) { do { ch = state.input.charCodeAt(++state.position); - } while (ch !== 0x0a /* LF */ && ch !== 0x0d /* CR */ && ch !== 0); + } while (ch !== 0x0a && /* LF */ ch !== 0x0d && /* CR */ ch !== 0); } if (isEOL(ch)) { @@ -451,7 +451,7 @@ function testDocumentSeparator(state: LoaderState): boolean { // Condition state.position === state.lineStart is tested // in parent on each call, for efficiency. No needs to test here again. if ( - (ch === 0x2d /* - */ || ch === 0x2e) /* . */ && + (ch === 0x2d || /* - */ ch === 0x2e) /* . */ && ch === state.input.charCodeAt(_position + 1) && ch === state.input.charCodeAt(_position + 2) ) { @@ -503,7 +503,7 @@ function readPlainScalar( } let following: number; - if (ch === 0x3f /* ? */ || ch === 0x2d /* - */) { + if (ch === 0x3f || /* ? */ ch === 0x2d /* - */) { following = state.input.charCodeAt(state.position + 1); if ( @@ -869,7 +869,7 @@ function readBlockScalar(state: LoaderState, nodeIndent: number): boolean { while (ch !== 0) { ch = state.input.charCodeAt(++state.position); - if (ch === 0x2b /* + */ || ch === 0x2d /* - */) { + if (ch === 0x2b || /* + */ ch === 0x2d /* - */) { if (CHOMPING_CLIP === chomping) { chomping = ch === 0x2b /* + */ ? CHOMPING_KEEP : CHOMPING_STRIP; } else { @@ -1103,7 +1103,7 @@ function readBlockMapping( // Explicit notation case. There are two separate blocks: // first for the key (denoted by "?") and second for the value (denoted by ":") // - if ((ch === 0x3f /* ? */ || ch === 0x3a) /* : */ && isWsOrEol(following)) { + if ((ch === 0x3f || /* ? */ ch === 0x3a) && /* : */ isWsOrEol(following)) { if (ch === 0x3f /* ? */) { if (atExplicitKey) { storeMappingPair( diff --git a/std/encoding/yaml/loader/loader_state.ts b/std/encoding/yaml/loader/loader_state.ts index 1e136025cf3742..ca50fcaf1dbd97 100644 --- a/std/encoding/yaml/loader/loader_state.ts +++ b/std/encoding/yaml/loader/loader_state.ts @@ -56,7 +56,7 @@ export class LoaderState extends State { onWarning, legacy = false, json = false, - listener = null + listener = null, }: LoaderStateOptions ) { super(schema); diff --git a/std/encoding/yaml/parse_test.ts b/std/encoding/yaml/parse_test.ts index bdcd8db629403c..21f1b893bda3fc 100644 --- a/std/encoding/yaml/parse_test.ts +++ b/std/encoding/yaml/parse_test.ts @@ -20,7 +20,7 @@ Deno.test({ const expected = { test: "toto", foo: { bar: true, baz: 1, qux: null } }; assertEquals(parse(yaml), expected); - } + }, }); Deno.test({ @@ -40,17 +40,17 @@ name: Eve const expected = [ { id: 1, - name: "Alice" + name: "Alice", }, { id: 2, - name: "Bob" + name: "Bob", }, { id: 3, - name: "Eve" - } + name: "Eve", + }, ]; assertEquals(parseAll(yaml), expected); - } + }, }); diff --git a/std/encoding/yaml/schema.ts b/std/encoding/yaml/schema.ts index 1968e34c1e57f2..579644dbb7c775 100644 --- a/std/encoding/yaml/schema.ts +++ b/std/encoding/yaml/schema.ts @@ -45,7 +45,7 @@ function compileMap(...typesList: Type[][]): TypeMap { fallback: {}, mapping: {}, scalar: {}, - sequence: {} + sequence: {}, }; for (const types of typesList) { diff --git a/std/encoding/yaml/schema/core.ts b/std/encoding/yaml/schema/core.ts index 82a512a1e1fe9e..4fadc9bfee9ee7 100644 --- a/std/encoding/yaml/schema/core.ts +++ b/std/encoding/yaml/schema/core.ts @@ -9,5 +9,5 @@ import { json } from "./json.ts"; // Standard YAML's Core schema. // http://www.yaml.org/spec/1.2/spec.html#id2804923 export const core = new Schema({ - include: [json] + include: [json], }); diff --git a/std/encoding/yaml/schema/default.ts b/std/encoding/yaml/schema/default.ts index 0fe1dbf1290cfa..4c5ceeba715368 100644 --- a/std/encoding/yaml/schema/default.ts +++ b/std/encoding/yaml/schema/default.ts @@ -12,5 +12,5 @@ import { core } from "./core.ts"; export const def = new Schema({ explicit: [binary, omap, pairs, set], implicit: [timestamp, merge], - include: [core] + include: [core], }); diff --git a/std/encoding/yaml/schema/failsafe.ts b/std/encoding/yaml/schema/failsafe.ts index 0fbb74ca9dc19f..74e1897be1e1b7 100644 --- a/std/encoding/yaml/schema/failsafe.ts +++ b/std/encoding/yaml/schema/failsafe.ts @@ -9,5 +9,5 @@ import { map, seq, str } from "../type/mod.ts"; // Standard YAML's Failsafe schema. // http://www.yaml.org/spec/1.2/spec.html#id2802346 export const failsafe = new Schema({ - explicit: [str, seq, map] + explicit: [str, seq, map], }); diff --git a/std/encoding/yaml/schema/json.ts b/std/encoding/yaml/schema/json.ts index dae469f350c76c..c30166fdf9c4c9 100644 --- a/std/encoding/yaml/schema/json.ts +++ b/std/encoding/yaml/schema/json.ts @@ -11,5 +11,5 @@ import { failsafe } from "./failsafe.ts"; // http://www.yaml.org/spec/1.2/spec.html#id2803231 export const json = new Schema({ implicit: [nil, bool, int, float], - include: [failsafe] + include: [failsafe], }); diff --git a/std/encoding/yaml/stringify_test.ts b/std/encoding/yaml/stringify_test.ts index 941beb789f3b8d..03a3090d96f40b 100644 --- a/std/encoding/yaml/stringify_test.ts +++ b/std/encoding/yaml/stringify_test.ts @@ -16,14 +16,14 @@ Deno.test({ "a", "b", { - a: false + a: false, }, { - a: false - } - ] + a: false, + }, + ], }, - test: "foobar" + test: "foobar", }; const ASSERTS = `foo: @@ -37,5 +37,5 @@ test: foobar `; assertEquals(stringify(FIXTURE), ASSERTS); - } + }, }); diff --git a/std/encoding/yaml/type/binary.ts b/std/encoding/yaml/type/binary.ts index 8cfe54f7965f8c..f4823b3f74e57e 100644 --- a/std/encoding/yaml/type/binary.ts +++ b/std/encoding/yaml/type/binary.ts @@ -135,5 +135,5 @@ export const binary = new Type("tag:yaml.org,2002:binary", { kind: "scalar", predicate: isBinary, represent: representYamlBinary, - resolve: resolveYamlBinary + resolve: resolveYamlBinary, }); diff --git a/std/encoding/yaml/type/bool.ts b/std/encoding/yaml/type/bool.ts index e39823872fab85..a5a85cf9e108e8 100644 --- a/std/encoding/yaml/type/bool.ts +++ b/std/encoding/yaml/type/bool.ts @@ -33,7 +33,7 @@ export const bool = new Type("tag:yaml.org,2002:bool", { }, camelcase(object: boolean): string { return object ? "True" : "False"; - } + }, }, - resolve: resolveYamlBoolean + resolve: resolveYamlBoolean, }); diff --git a/std/encoding/yaml/type/float.ts b/std/encoding/yaml/type/float.ts index acb12f5b0088f1..5ae0689b20a599 100644 --- a/std/encoding/yaml/type/float.ts +++ b/std/encoding/yaml/type/float.ts @@ -121,5 +121,5 @@ export const float = new Type("tag:yaml.org,2002:float", { kind: "scalar", predicate: isFloat, represent: representYamlFloat, - resolve: resolveYamlFloat + resolve: resolveYamlFloat, }); diff --git a/std/encoding/yaml/type/int.ts b/std/encoding/yaml/type/int.ts index 93ec8260e58bdb..6a86aafe9df66a 100644 --- a/std/encoding/yaml/type/int.ts +++ b/std/encoding/yaml/type/int.ts @@ -8,18 +8,18 @@ import { isNegativeZero, Any } from "../utils.ts"; function isHexCode(c: number): boolean { return ( - (0x30 /* 0 */ <= c && c <= 0x39) /* 9 */ || - (0x41 /* A */ <= c && c <= 0x46) /* F */ || - (0x61 /* a */ <= c && c <= 0x66) /* f */ + (0x30 <= /* 0 */ c && c <= 0x39) /* 9 */ || + (0x41 <= /* A */ c && c <= 0x46) /* F */ || + (0x61 <= /* a */ c && c <= 0x66) /* f */ ); } function isOctCode(c: number): boolean { - return 0x30 /* 0 */ <= c && c <= 0x37 /* 7 */; + return 0x30 <= /* 0 */ c && c <= 0x37 /* 7 */; } function isDecCode(c: number): boolean { - return 0x30 /* 0 */ <= c && c <= 0x39 /* 9 */; + return 0x30 <= /* 0 */ c && c <= 0x39 /* 9 */; } function resolveYamlInteger(data: string): boolean { @@ -175,17 +175,14 @@ export const int = new Type("tag:yaml.org,2002:int", { hexadecimal(obj: number): string { return obj >= 0 ? `0x${obj.toString(16).toUpperCase()}` - : `-0x${obj - .toString(16) - .toUpperCase() - .slice(1)}`; - } + : `-0x${obj.toString(16).toUpperCase().slice(1)}`; + }, }, resolve: resolveYamlInteger, styleAliases: { binary: [2, "bin"], decimal: [10, "dec"], hexadecimal: [16, "hex"], - octal: [8, "oct"] - } + octal: [8, "oct"], + }, }); diff --git a/std/encoding/yaml/type/map.ts b/std/encoding/yaml/type/map.ts index 60e6786572e2e5..dcd99abcac9711 100644 --- a/std/encoding/yaml/type/map.ts +++ b/std/encoding/yaml/type/map.ts @@ -10,5 +10,5 @@ export const map = new Type("tag:yaml.org,2002:map", { construct(data): Any { return data !== null ? data : {}; }, - kind: "mapping" + kind: "mapping", }); diff --git a/std/encoding/yaml/type/merge.ts b/std/encoding/yaml/type/merge.ts index 77b34025b59232..68314bf2e4521f 100644 --- a/std/encoding/yaml/type/merge.ts +++ b/std/encoding/yaml/type/merge.ts @@ -11,5 +11,5 @@ function resolveYamlMerge(data: string): boolean { export const merge = new Type("tag:yaml.org,2002:merge", { kind: "scalar", - resolve: resolveYamlMerge + resolve: resolveYamlMerge, }); diff --git a/std/encoding/yaml/type/nil.ts b/std/encoding/yaml/type/nil.ts index 00627514ccc97e..8a48d02fb637f1 100644 --- a/std/encoding/yaml/type/nil.ts +++ b/std/encoding/yaml/type/nil.ts @@ -39,7 +39,7 @@ export const nil = new Type("tag:yaml.org,2002:null", { }, camelcase(): string { return "Null"; - } + }, }, - resolve: resolveYamlNull + resolve: resolveYamlNull, }); diff --git a/std/encoding/yaml/type/omap.ts b/std/encoding/yaml/type/omap.ts index 541e31df624992..d6d7515058196b 100644 --- a/std/encoding/yaml/type/omap.ts +++ b/std/encoding/yaml/type/omap.ts @@ -42,5 +42,5 @@ function constructYamlOmap(data: Any): Any { export const omap = new Type("tag:yaml.org,2002:omap", { construct: constructYamlOmap, kind: "sequence", - resolve: resolveYamlOmap + resolve: resolveYamlOmap, }); diff --git a/std/encoding/yaml/type/pairs.ts b/std/encoding/yaml/type/pairs.ts index c964524b562a58..e999748ae73559 100644 --- a/std/encoding/yaml/type/pairs.ts +++ b/std/encoding/yaml/type/pairs.ts @@ -45,5 +45,5 @@ function constructYamlPairs(data: string): Any[] { export const pairs = new Type("tag:yaml.org,2002:pairs", { construct: constructYamlPairs, kind: "sequence", - resolve: resolveYamlPairs + resolve: resolveYamlPairs, }); diff --git a/std/encoding/yaml/type/seq.ts b/std/encoding/yaml/type/seq.ts index bd7ceb945388ce..b19565dbca8dfd 100644 --- a/std/encoding/yaml/type/seq.ts +++ b/std/encoding/yaml/type/seq.ts @@ -10,5 +10,5 @@ export const seq = new Type("tag:yaml.org,2002:seq", { construct(data): Any { return data !== null ? data : []; }, - kind: "sequence" + kind: "sequence", }); diff --git a/std/encoding/yaml/type/set.ts b/std/encoding/yaml/type/set.ts index 3b7fca0e9695fd..0bfe1c8db4e458 100644 --- a/std/encoding/yaml/type/set.ts +++ b/std/encoding/yaml/type/set.ts @@ -27,5 +27,5 @@ function constructYamlSet(data: string): Any { export const set = new Type("tag:yaml.org,2002:set", { construct: constructYamlSet, kind: "mapping", - resolve: resolveYamlSet + resolve: resolveYamlSet, }); diff --git a/std/encoding/yaml/type/str.ts b/std/encoding/yaml/type/str.ts index c7227743e3fed1..cd6e9430fc14a9 100644 --- a/std/encoding/yaml/type/str.ts +++ b/std/encoding/yaml/type/str.ts @@ -8,5 +8,5 @@ export const str = new Type("tag:yaml.org,2002:str", { construct(data): string { return data !== null ? data : ""; }, - kind: "scalar" + kind: "scalar", }); diff --git a/std/encoding/yaml/type/timestamp.ts b/std/encoding/yaml/type/timestamp.ts index 14d24077a887a4..eb03b382501b37 100644 --- a/std/encoding/yaml/type/timestamp.ts +++ b/std/encoding/yaml/type/timestamp.ts @@ -92,5 +92,5 @@ export const timestamp = new Type("tag:yaml.org,2002:timestamp", { instanceOf: Date, kind: "scalar", represent: representYamlTimestamp, - resolve: resolveYamlTimestamp + resolve: resolveYamlTimestamp, }); diff --git a/std/examples/chat/server.ts b/std/examples/chat/server.ts index 08aede05bbc6d4..eb5b2f7d4823b6 100644 --- a/std/examples/chat/server.ts +++ b/std/examples/chat/server.ts @@ -3,7 +3,7 @@ import { acceptWebSocket, acceptable, WebSocket, - isWebSocketCloseEvent + isWebSocketCloseEvent, } from "../../ws/mod.ts"; const clients = new Map(); @@ -29,19 +29,19 @@ async function wsHandler(ws: WebSocket): Promise { } } -listenAndServe({ port: 8080 }, async req => { +listenAndServe({ port: 8080 }, async (req) => { if (req.method === "GET" && req.url === "/") { //Serve with hack const u = new URL("./index.html", import.meta.url); if (u.protocol.startsWith("http")) { // server launched by deno run http(s)://.../server.ts, - fetch(u.href).then(resp => { + fetch(u.href).then((resp) => { return req.respond({ status: resp.status, headers: new Headers({ - "content-type": "text/html" + "content-type": "text/html", }), - body: resp.body + body: resp.body, }); }); } else { @@ -50,9 +50,9 @@ listenAndServe({ port: 8080 }, async req => { req.respond({ status: 200, headers: new Headers({ - "content-type": "text/html" + "content-type": "text/html", }), - body: file + body: file, }); } } @@ -60,8 +60,8 @@ listenAndServe({ port: 8080 }, async req => { req.respond({ status: 302, headers: new Headers({ - location: "https://deno.land/favicon.ico" - }) + location: "https://deno.land/favicon.ico", + }), }); } if (req.method === "GET" && req.url === "/ws") { @@ -70,7 +70,7 @@ listenAndServe({ port: 8080 }, async req => { conn: req.conn, bufReader: req.r, bufWriter: req.w, - headers: req.headers + headers: req.headers, }).then(wsHandler); } } diff --git a/std/examples/chat/server_test.ts b/std/examples/chat/server_test.ts index 0d21b3787833bd..673b6117419098 100644 --- a/std/examples/chat/server_test.ts +++ b/std/examples/chat/server_test.ts @@ -9,9 +9,9 @@ const { test, build } = Deno; async function startServer(): Promise { const server = Deno.run({ - args: [Deno.execPath(), "--allow-net", "--allow-read", "server.ts"], + cmd: [Deno.execPath(), "--allow-net", "--allow-read", "server.ts"], cwd: "examples/chat", - stdout: "piped" + stdout: "piped", }); try { assert(server.stdout != null); @@ -45,7 +45,7 @@ test({ server.stdout!.close(); } await delay(10); - } + }, }); test({ @@ -65,5 +65,5 @@ test({ server.stdout!.close(); ws!.conn.close(); } - } + }, }); diff --git a/std/examples/gist.ts b/std/examples/gist.ts index 15f00ff5d04d26..a11a92383598b7 100755 --- a/std/examples/gist.ts +++ b/std/examples/gist.ts @@ -35,7 +35,7 @@ for (const filename of parsedArgs._) { const content = { description: parsedArgs.title || parsedArgs.t || "Example", public: false, - files: files + files: files, }; const body = JSON.stringify(content); @@ -44,9 +44,9 @@ const res = await fetch("https://api.github.com/gists", { headers: [ ["Content-Type", "application/json"], ["User-Agent", "Deno-Gist"], - ["Authorization", `token ${token}`] + ["Authorization", `token ${token}`], ], - body + body, }); if (res.ok) { diff --git a/std/examples/test.ts b/std/examples/test.ts index 1c817dfd11ec59..6e26407fb0bc00 100644 --- a/std/examples/test.ts +++ b/std/examples/test.ts @@ -14,15 +14,15 @@ Deno.test(function t2(): void { /** A more complicated test that runs a subprocess. */ Deno.test(async function catSmoke(): Promise { const p = run({ - args: [ + cmd: [ Deno.execPath(), "run", "--allow-read", "examples/cat.ts", - "README.md" + "README.md", ], stdout: "null", - stderr: "null" + stderr: "null", }); const s = await p.status(); assertEquals(s.code, 0); diff --git a/std/examples/tests/cat_test.ts b/std/examples/tests/cat_test.ts index 34b60bc5d9c174..b12a6916f6b827 100644 --- a/std/examples/tests/cat_test.ts +++ b/std/examples/tests/cat_test.ts @@ -4,15 +4,15 @@ import { assertStrictEq } from "../../testing/asserts.ts"; Deno.test("[examples/cat] print multiple files", async () => { const decoder = new TextDecoder(); const process = Deno.run({ - args: [ + cmd: [ Deno.execPath(), "--allow-read", "cat.ts", "testdata/cat/hello.txt", - "testdata/cat/world.txt" + "testdata/cat/world.txt", ], cwd: "examples", - stdout: "piped" + stdout: "piped", }); try { diff --git a/std/examples/tests/catj_test.ts b/std/examples/tests/catj_test.ts index 2d667daccc88e6..53b36bef83b1f4 100644 --- a/std/examples/tests/catj_test.ts +++ b/std/examples/tests/catj_test.ts @@ -12,7 +12,7 @@ Deno.test("[examples/catj] print an array", async () => { ".[1] = 100", '.[2].key = "value"', '.[2].array[0] = "foo"', - '.[2].array[1] = "bar"' + '.[2].array[1] = "bar"', ].join("\n"); assertStrictEq(actual, expected); @@ -31,7 +31,7 @@ Deno.test("[examples/catj] print an object", async () => { const expected = [ '.string = "foobar"', ".number = 123", - '.array[0].message = "hello"' + '.array[0].message = "hello"', ].join("\n"); assertStrictEq(actual, expected); @@ -77,10 +77,10 @@ Deno.test("[examples/catj] read from stdin", async () => { function catj(...files: string[]): Deno.Process { return Deno.run({ - args: [Deno.execPath(), "--allow-read", "catj.ts", ...files], + cmd: [Deno.execPath(), "--allow-read", "catj.ts", ...files], cwd: "examples", stdin: "piped", stdout: "piped", - env: { NO_COLOR: "true" } + env: { NO_COLOR: "true" }, }); } diff --git a/std/examples/tests/colors_test.ts b/std/examples/tests/colors_test.ts index e01e4d558a22b0..ac779adb8d3da7 100644 --- a/std/examples/tests/colors_test.ts +++ b/std/examples/tests/colors_test.ts @@ -4,9 +4,9 @@ import { assertStrictEq } from "../../testing/asserts.ts"; Deno.test("[examples/colors] print a colored text", async () => { const decoder = new TextDecoder(); const process = Deno.run({ - args: [Deno.execPath(), "colors.ts"], + cmd: [Deno.execPath(), "colors.ts"], cwd: "examples", - stdout: "piped" + stdout: "piped", }); try { const output = await process.output(); diff --git a/std/examples/tests/curl_test.ts b/std/examples/tests/curl_test.ts index bc413b23f572f3..9b2870216f5174 100644 --- a/std/examples/tests/curl_test.ts +++ b/std/examples/tests/curl_test.ts @@ -4,12 +4,9 @@ import { assertStrictEq } from "../../testing/asserts.ts"; Deno.test({ name: "[examples/curl] send a request to a specified url", - // FIXME(bartlomieju): this test is leaking both resources and ops, - // and causes interference with other tests - ignore: true, fn: async () => { const server = serve({ port: 8081 }); - (async (): Promise => { + const serverPromise = (async (): Promise => { for await (const req of server) { req.respond({ body: "Hello world" }); } @@ -17,14 +14,9 @@ Deno.test({ const decoder = new TextDecoder(); const process = Deno.run({ - args: [ - Deno.execPath(), - "--allow-net", - "curl.ts", - "http://localhost:8081" - ], + cmd: [Deno.execPath(), "--allow-net", "curl.ts", "http://localhost:8081"], cwd: "examples", - stdout: "piped" + stdout: "piped", }); try { @@ -34,8 +26,9 @@ Deno.test({ assertStrictEq(actual, expected); } finally { - process.close(); server.close(); + process.close(); + await serverPromise; } - } + }, }); diff --git a/std/examples/tests/echo_server_test.ts b/std/examples/tests/echo_server_test.ts index 20fd7479c24894..fecc7d6a666cf9 100644 --- a/std/examples/tests/echo_server_test.ts +++ b/std/examples/tests/echo_server_test.ts @@ -6,9 +6,9 @@ Deno.test("[examples/echo_server]", async () => { const encoder = new TextEncoder(); const decoder = new TextDecoder(); const process = Deno.run({ - args: [Deno.execPath(), "--allow-net", "echo_server.ts"], + cmd: [Deno.execPath(), "--allow-net", "echo_server.ts"], cwd: "examples", - stdout: "piped" + stdout: "piped", }); let conn: Deno.Conn | undefined; diff --git a/std/examples/tests/welcome_test.ts b/std/examples/tests/welcome_test.ts index 304a5786826393..cacb77ab9db4e1 100644 --- a/std/examples/tests/welcome_test.ts +++ b/std/examples/tests/welcome_test.ts @@ -4,9 +4,9 @@ import { assertStrictEq } from "../../testing/asserts.ts"; Deno.test("[examples/welcome] print a welcome message", async () => { const decoder = new TextDecoder(); const process = Deno.run({ - args: [Deno.execPath(), "welcome.ts"], + cmd: [Deno.execPath(), "welcome.ts"], cwd: "examples", - stdout: "piped" + stdout: "piped", }); try { const output = await process.output(); diff --git a/std/examples/tests/xeval_test.ts b/std/examples/tests/xeval_test.ts index db11c215c4bd76..25f99c9f0bca7e 100644 --- a/std/examples/tests/xeval_test.ts +++ b/std/examples/tests/xeval_test.ts @@ -5,7 +5,7 @@ import { decode, encode } from "../../strings/mod.ts"; import { assertEquals, assertStrContains, - assert + assert, } from "../../testing/asserts.ts"; const { execPath, run } = Deno; @@ -18,7 +18,7 @@ Deno.test(async function xevalSuccess(): Promise { Deno.test(async function xevalDelimiter(): Promise { const chunks: string[] = []; await xeval(stringsReader("!MADMADAMADAM!"), ($): number => chunks.push($), { - delimiter: "MADAM" + delimiter: "MADAM", }); assertEquals(chunks, ["!MAD", "ADAM!"]); }); @@ -27,12 +27,12 @@ const xevalPath = "examples/xeval.ts"; Deno.test({ name: "xevalCliReplvar", - fn: async function(): Promise { + fn: async function (): Promise { const p = run({ - args: [execPath(), xevalPath, "--replvar=abc", "console.log(abc)"], + cmd: [execPath(), xevalPath, "--replvar=abc", "console.log(abc)"], stdin: "piped", stdout: "piped", - stderr: "null" + stderr: "null", }); assert(p.stdin != null); await p.stdin.write(encode("hello")); @@ -40,15 +40,15 @@ Deno.test({ assertEquals(await p.status(), { code: 0, success: true }); assertEquals(decode(await p.output()).trimEnd(), "hello"); p.close(); - } + }, }); Deno.test(async function xevalCliSyntaxError(): Promise { const p = run({ - args: [execPath(), xevalPath, "("], + cmd: [execPath(), xevalPath, "("], stdin: "null", stdout: "piped", - stderr: "piped" + stderr: "piped", }); assertEquals(await p.status(), { code: 1, success: false }); assertEquals(decode(await p.output()), ""); diff --git a/std/examples/xeval.ts b/std/examples/xeval.ts index 16ce37fb4ff0a9..6589fec168a036 100644 --- a/std/examples/xeval.ts +++ b/std/examples/xeval.ts @@ -5,7 +5,7 @@ type Reader = Deno.Reader; /* eslint-disable-next-line max-len */ // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncFunction. -const AsyncFunction = Object.getPrototypeOf(async function(): Promise {}) +const AsyncFunction = Object.getPrototypeOf(async function (): Promise {}) .constructor; /* eslint-disable max-len */ @@ -59,12 +59,12 @@ async function main(): Promise { alias: { delim: ["d"], replvar: ["I"], - help: ["h"] + help: ["h"], }, default: { delim: DEFAULT_DELIMITER, - replvar: "$" - } + replvar: "$", + }, }); if (parsedArgs._.length != 1) { console.error(HELP_MSG); diff --git a/std/flags/all_bool_test.ts b/std/flags/all_bool_test.ts index 6516f48ed5a851..cb5a36710ee03d 100755 --- a/std/flags/all_bool_test.ts +++ b/std/flags/all_bool_test.ts @@ -5,12 +5,12 @@ import { parse } from "./mod.ts"; // flag boolean true (default all --args to boolean) Deno.test(function flagBooleanTrue(): void { const argv = parse(["moo", "--honk", "cow"], { - boolean: true + boolean: true, }); assertEquals(argv, { honk: true, - _: ["moo", "cow"] + _: ["moo", "cow"], }); assertEquals(typeof argv.honk, "boolean"); @@ -19,14 +19,14 @@ Deno.test(function flagBooleanTrue(): void { // flag boolean true only affects double hyphen arguments without equals signs Deno.test(function flagBooleanTrueOnlyAffectsDoubleDash(): void { const argv = parse(["moo", "--honk", "cow", "-p", "55", "--tacos=good"], { - boolean: true + boolean: true, }); assertEquals(argv, { honk: true, tacos: "good", p: 55, - _: ["moo", "cow"] + _: ["moo", "cow"], }); assertEquals(typeof argv.honk, "boolean"); diff --git a/std/flags/bool_test.ts b/std/flags/bool_test.ts index 2d6a8b93800056..f2d88e617a0795 100755 --- a/std/flags/bool_test.ts +++ b/std/flags/bool_test.ts @@ -5,13 +5,13 @@ import { parse } from "./mod.ts"; Deno.test(function flagBooleanDefaultFalse(): void { const argv = parse(["moo"], { boolean: ["t", "verbose"], - default: { verbose: false, t: false } + default: { verbose: false, t: false }, }); assertEquals(argv, { verbose: false, t: false, - _: ["moo"] + _: ["moo"], }); assertEquals(typeof argv.verbose, "boolean"); @@ -20,14 +20,14 @@ Deno.test(function flagBooleanDefaultFalse(): void { Deno.test(function booleanGroups(): void { const argv = parse(["-x", "-z", "one", "two", "three"], { - boolean: ["x", "y", "z"] + boolean: ["x", "y", "z"], }); assertEquals(argv, { x: true, y: false, z: true, - _: ["one", "two", "three"] + _: ["one", "two", "three"], }); assertEquals(typeof argv.x, "boolean"); @@ -40,16 +40,16 @@ Deno.test(function booleanAndAliasWithChainableApi(): void { const regular = ["--herp", "derp"]; const aliasedArgv = parse(aliased, { boolean: "herp", - alias: { h: "herp" } + alias: { h: "herp" }, }); const propertyArgv = parse(regular, { boolean: "herp", - alias: { h: "herp" } + alias: { h: "herp" }, }); const expected = { herp: true, h: true, - _: ["derp"] + _: ["derp"], }; assertEquals(aliasedArgv, expected); @@ -61,14 +61,14 @@ Deno.test(function booleanAndAliasWithOptionsHash(): void { const regular = ["--herp", "derp"]; const opts = { alias: { h: "herp" }, - boolean: "herp" + boolean: "herp", }; const aliasedArgv = parse(aliased, opts); const propertyArgv = parse(regular, opts); const expected = { herp: true, h: true, - _: ["derp"] + _: ["derp"], }; assertEquals(aliasedArgv, expected); assertEquals(propertyArgv, expected); @@ -80,7 +80,7 @@ Deno.test(function booleanAndAliasArrayWithOptionsHash(): void { const alt = ["--harp", "derp"]; const opts = { alias: { h: ["herp", "harp"] }, - boolean: "h" + boolean: "h", }; const aliasedArgv = parse(aliased, opts); const propertyArgv = parse(regular, opts); @@ -89,7 +89,7 @@ Deno.test(function booleanAndAliasArrayWithOptionsHash(): void { harp: true, herp: true, h: true, - _: ["derp"] + _: ["derp"], }; assertEquals(aliasedArgv, expected); assertEquals(propertyArgv, expected); @@ -101,14 +101,14 @@ Deno.test(function booleanAndAliasUsingExplicitTrue(): void { const regular = ["--herp", "true"]; const opts = { alias: { h: "herp" }, - boolean: "h" + boolean: "h", }; const aliasedArgv = parse(aliased, opts); const propertyArgv = parse(regular, opts); const expected = { herp: true, h: true, - _: [] + _: [], }; assertEquals(aliasedArgv, expected); @@ -119,14 +119,14 @@ Deno.test(function booleanAndAliasUsingExplicitTrue(): void { // boolean and --x=true Deno.test(function booleanAndNonBoolean(): void { const parsed = parse(["--boool", "--other=true"], { - boolean: "boool" + boolean: "boool", }); assertEquals(parsed.boool, true); assertEquals(parsed.other, "true"); const parsed2 = parse(["--boool", "--other=false"], { - boolean: "boool" + boolean: "boool", }); assertEquals(parsed2.boool, true); @@ -136,9 +136,9 @@ Deno.test(function booleanAndNonBoolean(): void { Deno.test(function booleanParsingTrue(): void { const parsed = parse(["--boool=true"], { default: { - boool: false + boool: false, }, - boolean: ["boool"] + boolean: ["boool"], }); assertEquals(parsed.boool, true); @@ -147,9 +147,9 @@ Deno.test(function booleanParsingTrue(): void { Deno.test(function booleanParsingFalse(): void { const parsed = parse(["--boool=false"], { default: { - boool: true + boool: true, }, - boolean: ["boool"] + boolean: ["boool"], }); assertEquals(parsed.boool, false); @@ -187,7 +187,7 @@ Deno.test(function latestFlagIsBooleanNegation(): void { assertEquals(parsed.foo, false); const parsed2 = parse(["--no-foo", "--foo", "--no-foo", "123"], { - boolean: ["foo"] + boolean: ["foo"], }); assertEquals(parsed2.foo, false); }); @@ -197,7 +197,7 @@ Deno.test(function latestFlagIsBoolean(): void { assertEquals(parsed.foo, true); const parsed2 = parse(["--foo", "--no-foo", "--foo", "123"], { - boolean: ["foo"] + boolean: ["foo"], }); assertEquals(parsed2.foo, true); }); diff --git a/std/flags/dash_test.ts b/std/flags/dash_test.ts index bdf8f502df2a78..3df169291a3f7b 100755 --- a/std/flags/dash_test.ts +++ b/std/flags/dash_test.ts @@ -22,7 +22,7 @@ Deno.test(function moveArgsAfterDoubleDashIntoOwnArray(): void { { name: "John", _: ["before"], - "--": ["after"] + "--": ["after"], } ); }); diff --git a/std/flags/default_bool_test.ts b/std/flags/default_bool_test.ts index 813b6870b931f4..4376038feca024 100755 --- a/std/flags/default_bool_test.ts +++ b/std/flags/default_bool_test.ts @@ -5,7 +5,7 @@ import { parse } from "./mod.ts"; Deno.test(function booleanDefaultTrue(): void { const argv = parse([], { boolean: "sometrue", - default: { sometrue: true } + default: { sometrue: true }, }); assertEquals(argv.sometrue, true); }); @@ -13,7 +13,7 @@ Deno.test(function booleanDefaultTrue(): void { Deno.test(function booleanDefaultFalse(): void { const argv = parse([], { boolean: "somefalse", - default: { somefalse: false } + default: { somefalse: false }, }); assertEquals(argv.somefalse, false); }); @@ -21,12 +21,12 @@ Deno.test(function booleanDefaultFalse(): void { Deno.test(function booleanDefaultNull(): void { const argv = parse([], { boolean: "maybe", - default: { maybe: null } + default: { maybe: null }, }); assertEquals(argv.maybe, null); const argv2 = parse(["--maybe"], { boolean: "maybe", - default: { maybe: null } + default: { maybe: null }, }); assertEquals(argv2.maybe, true); }); diff --git a/std/flags/dotted_test.ts b/std/flags/dotted_test.ts index 93dd3031f6e4da..c86392f2aff881 100755 --- a/std/flags/dotted_test.ts +++ b/std/flags/dotted_test.ts @@ -5,7 +5,7 @@ import { parse } from "./mod.ts"; Deno.test(function dottedAlias(): void { const argv = parse(["--a.b", "22"], { default: { "a.b": 11 }, - alias: { "a.b": "aa.bb" } + alias: { "a.b": "aa.bb" }, }); assertEquals(argv.a.b, 22); assertEquals(argv.aa.bb, 22); diff --git a/std/flags/long_test.ts b/std/flags/long_test.ts index e5b68f8c00ee80..f0f4d7545abeeb 100755 --- a/std/flags/long_test.ts +++ b/std/flags/long_test.ts @@ -9,11 +9,11 @@ Deno.test(function longOpts(): void { assertEquals(parse(["--host", "localhost", "--port", "555"]), { host: "localhost", port: 555, - _: [] + _: [], }); assertEquals(parse(["--host=localhost", "--port=555"]), { host: "localhost", port: 555, - _: [] + _: [], }); }); diff --git a/std/flags/mod.ts b/std/flags/mod.ts index 18727a66544b90..b334cb5b8aafb7 100644 --- a/std/flags/mod.ts +++ b/std/flags/mod.ts @@ -85,7 +85,7 @@ function isNumber(x: unknown): boolean { function hasKey(obj: NestedMapping, keys: string[]): boolean { let o = obj; - keys.slice(0, -1).forEach(key => { + keys.slice(0, -1).forEach((key) => { o = (get(o, key) ?? {}) as NestedMapping; }); @@ -107,14 +107,14 @@ export function parse( default: defaults = {}, stopEarly = false, string = [], - unknown = (i: unknown): unknown => i + unknown = (i: unknown): unknown => i, }: ArgParsingOptions = {} ): Args { const flags: Flags = { bools: {}, strings: {}, unknownFn: unknown, - allBools: false + allBools: false, }; if (boolean !== undefined) { @@ -139,7 +139,7 @@ export function parse( aliases[key] = val; } for (const alias of getForce(aliases, key)) { - aliases[alias] = [key].concat(aliases[key].filter(y => alias !== y)); + aliases[alias] = [key].concat(aliases[key].filter((y) => alias !== y)); } } } @@ -171,7 +171,7 @@ export function parse( function setKey(obj: NestedMapping, keys: string[], value: unknown): void { let o = obj; - keys.slice(0, -1).forEach(function(key): void { + keys.slice(0, -1).forEach(function (key): void { if (get(o, key) === undefined) { o[key] = {}; } @@ -214,7 +214,7 @@ export function parse( function aliasIsBoolean(key: string): boolean { return getForce(aliases, key).some( - x => typeof get(flags.bools, x) === "boolean" + (x) => typeof get(flags.bools, x) === "boolean" ); } diff --git a/std/flags/num_test.ts b/std/flags/num_test.ts index 0d6b634b9da5ee..f8a0d11ac5daa9 100755 --- a/std/flags/num_test.ts +++ b/std/flags/num_test.ts @@ -14,7 +14,7 @@ Deno.test(function nums(): void { "10f", "--hex", "0xdeadbeef", - "789" + "789", ]); assertEquals(argv, { x: 1234, @@ -22,7 +22,7 @@ Deno.test(function nums(): void { z: 1e7, w: "10f", hex: 0xdeadbeef, - _: [789] + _: [789], }); assertEquals(typeof argv.x, "number"); assertEquals(typeof argv.y, "number"); diff --git a/std/flags/parse_test.ts b/std/flags/parse_test.ts index cd93c1f810b18a..abba42e16b8ece 100755 --- a/std/flags/parse_test.ts +++ b/std/flags/parse_test.ts @@ -6,7 +6,7 @@ Deno.test(function parseArgs(): void { assertEquals(parse(["--no-moo"]), { moo: false, _: [] }); assertEquals(parse(["-v", "a", "-v", "b", "-v", "c"]), { v: ["a", "b", "c"], - _: [] + _: [], }); }); @@ -28,7 +28,7 @@ Deno.test(function comprehensive(): void { "--multi=baz", "--", "--not-a-flag", - "eek" + "eek", ]), { c: true, @@ -42,7 +42,7 @@ Deno.test(function comprehensive(): void { multi: ["quux", "baz"], meep: false, name: "meowmers", - _: ["bare", "--not-a-flag", "eek"] + _: ["bare", "--not-a-flag", "eek"], } ); }); @@ -56,13 +56,13 @@ Deno.test(function flagBoolean(): void { Deno.test(function flagBooleanValue(): void { const argv = parse(["--verbose", "false", "moo", "-t", "true"], { boolean: ["t", "verbose"], - default: { verbose: true } + default: { verbose: true }, }); assertEquals(argv, { verbose: false, t: true, - _: ["moo"] + _: ["moo"], }); assertEquals(typeof argv.verbose, "boolean"); @@ -110,7 +110,7 @@ Deno.test(function emptyStrings(): void { assertEquals(typeof str, "string"); const letters = parse(["-art"], { - string: ["a", "t"] + string: ["a", "t"], }); assertEquals(letters.a, ""); @@ -121,7 +121,7 @@ Deno.test(function emptyStrings(): void { Deno.test(function stringAndAlias(): void { const x = parse(["--str", "000123"], { string: "s", - alias: { s: "str" } + alias: { s: "str" }, }); assertEquals(x.str, "000123"); @@ -131,7 +131,7 @@ Deno.test(function stringAndAlias(): void { const y = parse(["-s", "000123"], { string: "str", - alias: { str: "s" } + alias: { str: "s" }, }); assertEquals(y.str, "000123"); @@ -146,13 +146,13 @@ Deno.test(function slashBreak(): void { x: true, y: true, z: "/foo/bar/baz", - _: [] + _: [], }); }); Deno.test(function alias(): void { const argv = parse(["-f", "11", "--zoom", "55"], { - alias: { z: "zoom" } + alias: { z: "zoom" }, }); assertEquals(argv.zoom, 55); assertEquals(argv.z, argv.zoom); @@ -161,7 +161,7 @@ Deno.test(function alias(): void { Deno.test(function multiAlias(): void { const argv = parse(["-f", "11", "--zoom", "55"], { - alias: { z: ["zm", "zoom"] } + alias: { z: ["zm", "zoom"] }, }); assertEquals(argv.zoom, 55); assertEquals(argv.z, argv.zoom); @@ -178,7 +178,7 @@ Deno.test(function nestedDottedObjects(): void { "--foo.quux.quibble", "5", "--foo.quux.oO", - "--beep.boop" + "--beep.boop", ]); assertEquals(argv.foo, { @@ -186,8 +186,8 @@ Deno.test(function nestedDottedObjects(): void { baz: 4, quux: { quibble: 5, - oO: true - } + oO: true, + }, }); assertEquals(argv.beep, { boop: true }); }); diff --git a/std/flags/short_test.ts b/std/flags/short_test.ts index d7171b920d99a4..6305bbb94423ff 100755 --- a/std/flags/short_test.ts +++ b/std/flags/short_test.ts @@ -16,13 +16,13 @@ Deno.test(function short(): void { a: true, t: true, s: "meow", - _: [] + _: [], }); assertEquals(parse(["-h", "localhost"]), { h: "localhost", _: [] }); assertEquals(parse(["-h", "localhost", "-p", "555"]), { h: "localhost", p: 555, - _: [] + _: [], }); }); @@ -31,7 +31,7 @@ Deno.test(function mixedShortBoolAndCapture(): void { f: true, p: 555, h: "localhost", - _: ["script.js"] + _: ["script.js"], }); }); @@ -40,6 +40,6 @@ Deno.test(function shortAndLong(): void { f: true, p: 555, h: "localhost", - _: ["script.js"] + _: ["script.js"], }); }); diff --git a/std/flags/stop_early_test.ts b/std/flags/stop_early_test.ts index d1996e7aa04a57..4b7eac097f6b57 100755 --- a/std/flags/stop_early_test.ts +++ b/std/flags/stop_early_test.ts @@ -5,11 +5,11 @@ import { parse } from "./mod.ts"; // stops parsing on the first non-option when stopEarly is set Deno.test(function stopParsing(): void { const argv = parse(["--aaa", "bbb", "ccc", "--ddd"], { - stopEarly: true + stopEarly: true, }); assertEquals(argv, { aaa: "bbb", - _: ["ccc", "--ddd"] + _: ["ccc", "--ddd"], }); }); diff --git a/std/flags/unknown_test.ts b/std/flags/unknown_test.ts index acbb131ee6be8c..90c638b67b8618 100755 --- a/std/flags/unknown_test.ts +++ b/std/flags/unknown_test.ts @@ -13,7 +13,7 @@ Deno.test(function booleanAndAliasIsNotUnknown(): void { const opts = { alias: { h: "herp" }, boolean: "h", - unknown: unknownFn + unknown: unknownFn, }; parse(aliased, opts); parse(regular, opts); @@ -29,12 +29,12 @@ Deno.test(function flagBooleanTrueAnyDoubleHyphenArgumentIsNotUnknown(): void { } const argv = parse(["--honk", "--tacos=good", "cow", "-p", "55"], { boolean: true, - unknown: unknownFn + unknown: unknownFn, }); assertEquals(unknown, ["--tacos=good", "cow", "-p"]); assertEquals(argv, { honk: true, - _: [] + _: [], }); }); @@ -49,7 +49,7 @@ Deno.test(function stringAndAliasIsNotUnkown(): void { const opts = { alias: { h: "herp" }, string: "h", - unknown: unknownFn + unknown: unknownFn, }; parse(aliased, opts); parse(regular, opts); @@ -68,7 +68,7 @@ Deno.test(function defaultAndAliasIsNotUnknown(): void { const opts = { default: { h: "bar" }, alias: { h: "herp" }, - unknown: unknownFn + unknown: unknownFn, }; parse(aliased, opts); parse(regular, opts); @@ -85,13 +85,13 @@ Deno.test(function valueFollowingDoubleHyphenIsNotUnknown(): void { const aliased = ["--bad", "--", "good", "arg"]; const opts = { "--": true, - unknown: unknownFn + unknown: unknownFn, }; const argv = parse(aliased, opts); assertEquals(unknown, ["--bad"]); assertEquals(argv, { "--": ["good", "arg"], - _: [] + _: [], }); }); diff --git a/std/fmt/colors.ts b/std/fmt/colors.ts index 9476ce076a28da..ad2a6a1bea54c6 100644 --- a/std/fmt/colors.ts +++ b/std/fmt/colors.ts @@ -37,7 +37,7 @@ function code(open: number, close: number): Code { return { open: `\x1b[${open}m`, close: `\x1b[${close}m`, - regexp: new RegExp(`\\x1b\\[${close}m`, "g") + regexp: new RegExp(`\\x1b\\[${close}m`, "g"), }; } diff --git a/std/fmt/sprintf.ts b/std/fmt/sprintf.ts index dd7ac7f55e4f36..d79b9095e1ef4e 100644 --- a/std/fmt/sprintf.ts +++ b/std/fmt/sprintf.ts @@ -3,11 +3,11 @@ enum State { PERCENT, POSITIONAL, PRECISION, - WIDTH + WIDTH, } enum WorP { WIDTH, - PRECISION + PRECISION, } class Flags { @@ -34,7 +34,7 @@ enum F { mantissa, fractional, esign, - exponent + exponent, } class Printf { diff --git a/std/fmt/sprintf_test.ts b/std/fmt/sprintf_test.ts index 917878bc169a41..24d0b4727c78f2 100644 --- a/std/fmt/sprintf_test.ts +++ b/std/fmt/sprintf_test.ts @@ -229,7 +229,6 @@ const tests: Array<[string, any, string]> = [ ["%d", 12345, "12345"], ["%v", 12345, "12345"], ["%t", true, "true"], - // basic string ["%s", "abc", "abc"], // ["%q", "abc", `"abc"`], // TODO: need %q? @@ -248,7 +247,6 @@ const tests: Array<[string, any, string]> = [ ["%#X", "xyz", "0X78797A"], ["%# x", "xyz", "0x78 0x79 0x7a"], ["%# X", "xyz", "0X78 0X79 0X7A"], - // basic bytes : TODO special handling for Buffer? other std types? // escaped strings : TODO decide whether to have %q @@ -261,7 +259,6 @@ const tests: Array<[string, any, string]> = [ ["%.0c", "⌘".charCodeAt(0), "⌘"], ["%3c", "⌘".charCodeAt(0), " ⌘"], ["%-3c", "⌘".charCodeAt(0), "⌘ "], - // Runes that are not printable. // {"%c", '\U00000e00', "\u0e00"}, // TODO check if \U escape exists in js //["%c", '\U0010ffff'.codePointAt(0), "\U0010ffff"], @@ -273,7 +270,6 @@ const tests: Array<[string, any, string]> = [ // ["%c", 0xDC80, "�"], ["%c", 0x110000, "�"], ["%c", 0xfffffffff, "�"], - // TODO // escaped characters // Runes that are not printable. @@ -351,7 +347,6 @@ const tests: Array<[string, any, string]> = [ ["%-#20.8x", 0x1234abc, "0x01234abc "], ["%-#20.8X", 0x1234abc, "0X01234ABC "], ["%-#20.8o", parseInt("01234", 8), "00001234 "], - // Test correct f.intbuf overflow checks. // TODO, lazy // unicode format // TODO, decide whether unicode verb makes sense %U @@ -433,7 +428,6 @@ const tests: Array<[string, any, string]> = [ ["%+020e", Number.POSITIVE_INFINITY, " +Inf"], ["%-020f", Number.NEGATIVE_INFINITY, "-Inf "], ["%-020E", NaN, "NaN "], - // complex values // go specific // old test/fmt_test.go ["%e", 1.0, "1.000000e+00"], @@ -490,7 +484,6 @@ const tests: Array<[string, any, string]> = [ ["%g", 1.23456789e-3, "0.00123457"], // see above prec6 = precdef6 - (-3+1) //["%g", 1.23456789e20, "1.23456789e+20"], ["%g", 1.23456789e20, "1.23457e+20"], - // arrays // TODO // slice : go specific @@ -527,7 +520,6 @@ const tests: Array<[string, any, string]> = [ ["% -010X", "\xab", "AB "], ["%#-10X", "\xab\xcd", "0XABCD "], ["%# -010X", "\xab\xcd", "0XAB 0XCD "], - // renamings // Formatter // GoStringer @@ -541,7 +533,6 @@ const tests: Array<[string, any, string]> = [ ["%T", S, "function"], ["%T", true, "boolean"], ["%T", Symbol(), "symbol"], - // %p with pointers // erroneous things @@ -582,7 +573,7 @@ const tests: Array<[string, any, string]> = [ ["%+07.2f", 1.0, "+001.00"], ["%+07.2f", -1.0, "-001.00"], ["% +07.2f", 1.0, "+001.00"], - ["% +07.2f", -1.0, "-001.00"] + ["% +07.2f", -1.0, "-001.00"], ]; Deno.test(function testThorough(): void { diff --git a/std/fs/README.md b/std/fs/README.md index 56c190ccc14849..8c69faa7635e0e 100644 --- a/std/fs/README.md +++ b/std/fs/README.md @@ -52,7 +52,7 @@ created. ```ts import { ensureSymlink, - ensureSymlinkSync + ensureSymlinkSync, } from "https://deno.land/std/fs/mod.ts"; ensureSymlink( @@ -110,7 +110,7 @@ import { globToRegExp } from "https://deno.land/std/fs/mod.ts"; globToRegExp("foo/**/*.json", { flags: "g", extended: true, - globstar: true + globstar: true, }); // returns the regex to find all .json files in the folder foo ``` @@ -212,7 +212,7 @@ Write the string to file. ```ts import { writeFileStr, - writeFileStrSync + writeFileStrSync, } from "https://deno.land/std/fs/mod.ts"; writeFileStr("./target.dat", "file content"); // returns a promise diff --git a/std/fs/copy_test.ts b/std/fs/copy_test.ts index 9ba5f2b2135def..0fbc905792796c 100644 --- a/std/fs/copy_test.ts +++ b/std/fs/copy_test.ts @@ -3,7 +3,7 @@ import { assertEquals, assertThrows, assertThrowsAsync, - assert + assert, } from "../testing/asserts.ts"; import * as path from "../path/mod.ts"; import { copy, copySync } from "./copy.ts"; @@ -22,11 +22,11 @@ function testCopy(name: string, cb: (tempDir: string) => Promise): void { name, async fn(): Promise { const tempDir = await Deno.makeTempDir({ - prefix: "deno_std_copy_async_test_" + prefix: "deno_std_copy_async_test_", }); await cb(tempDir); await Deno.remove(tempDir, { recursive: true }); - } + }, }); } @@ -35,11 +35,11 @@ function testCopySync(name: string, cb: (tempDir: string) => void): void { name, fn: (): void => { const tempDir = Deno.makeTempDirSync({ - prefix: "deno_std_copy_sync_test_" + prefix: "deno_std_copy_sync_test_", }); cb(tempDir); Deno.removeSync(tempDir, { recursive: true }); - } + }, }); } @@ -149,7 +149,7 @@ testCopy( // Copy with overwrite and preserve timestamps options. await copy(srcFile, destFile, { overwrite: true, - preserveTimestamps: true + preserveTimestamps: true, }); const destStatInfo = await Deno.stat(destFile); @@ -333,7 +333,7 @@ testCopySync( // Copy with overwrite and preserve timestamps options. copySync(srcFile, destFile, { overwrite: true, - preserveTimestamps: true + preserveTimestamps: true, }); const destStatInfo = Deno.statSync(destFile); diff --git a/std/fs/empty_dir_test.ts b/std/fs/empty_dir_test.ts index 553d630015eaa5..f30f434dfa812b 100644 --- a/std/fs/empty_dir_test.ts +++ b/std/fs/empty_dir_test.ts @@ -4,7 +4,7 @@ import { assertEquals, assertStrContains, assertThrows, - assertThrowsAsync + assertThrowsAsync, } from "../testing/asserts.ts"; import * as path from "../path/mod.ts"; import { emptyDir, emptyDirSync } from "./empty_dir.ts"; @@ -137,59 +137,59 @@ const scenes: Scenes[] = [ read: false, write: false, async: true, - output: "run again with the --allow-read flag" + output: "run again with the --allow-read flag", }, { read: false, write: false, async: false, - output: "run again with the --allow-read flag" + output: "run again with the --allow-read flag", }, // 2 { read: true, write: false, async: true, - output: "run again with the --allow-write flag" + output: "run again with the --allow-write flag", }, { read: true, write: false, async: false, - output: "run again with the --allow-write flag" + output: "run again with the --allow-write flag", }, // 3 { read: false, write: true, async: true, - output: "run again with the --allow-read flag" + output: "run again with the --allow-read flag", }, { read: false, write: true, async: false, - output: "run again with the --allow-read flag" + output: "run again with the --allow-read flag", }, // 4 { read: true, write: true, async: true, - output: "success" + output: "success", }, { read: true, write: true, async: false, - output: "success" - } + output: "success", + }, ]; for (const s of scenes) { let title = `test ${s.async ? "emptyDir" : "emptyDirSync"}`; title += `("testdata/testfolder") ${s.read ? "with" : "without"}`; title += ` --allow-read & ${s.write ? "with" : "without"} --allow-write`; - Deno.test(`[fs] emptyDirPermission ${title}`, async function(): Promise< + Deno.test(`[fs] emptyDirPermission ${title}`, async function (): Promise< void > { const testfolder = path.join(testdataDir, "testfolder"); @@ -221,7 +221,7 @@ for (const s of scenes) { const p = Deno.run({ stdout: "piped", cwd: testdataDir, - args: args + cmd: args, }); assert(p.stdout); diff --git a/std/fs/ensure_link_test.ts b/std/fs/ensure_link_test.ts index 7549814a25d945..3c7720dc0b6648 100644 --- a/std/fs/ensure_link_test.ts +++ b/std/fs/ensure_link_test.ts @@ -3,7 +3,7 @@ import { assertEquals, assertThrows, - assertThrowsAsync + assertThrowsAsync, } from "../testing/asserts.ts"; import * as path from "../path/mod.ts"; import { ensureLink, ensureLinkSync } from "./ensure_link.ts"; diff --git a/std/fs/ensure_symlink_test.ts b/std/fs/ensure_symlink_test.ts index f0dc4fbe491b71..5188dc0354e5e6 100644 --- a/std/fs/ensure_symlink_test.ts +++ b/std/fs/ensure_symlink_test.ts @@ -3,7 +3,7 @@ import { assertEquals, assertThrows, - assertThrowsAsync + assertThrowsAsync, } from "../testing/asserts.ts"; import * as path from "../path/mod.ts"; import { ensureSymlink, ensureSymlinkSync } from "./ensure_symlink.ts"; diff --git a/std/fs/eol.ts b/std/fs/eol.ts index d4bb8032c6a456..2f15be269e00e1 100644 --- a/std/fs/eol.ts +++ b/std/fs/eol.ts @@ -3,7 +3,7 @@ /** EndOfLine character enum */ export enum EOL { LF = "\n", - CRLF = "\r\n" + CRLF = "\r\n", } const regDetect = /(?:\r?\n)/g; diff --git a/std/fs/eol_test.ts b/std/fs/eol_test.ts index aa2dcf3953edf3..35b3e0d9ae80bb 100644 --- a/std/fs/eol_test.ts +++ b/std/fs/eol_test.ts @@ -12,21 +12,21 @@ Deno.test({ name: "[EOL] Detect CR LF", fn(): void { assertEquals(detect(CRLFinput), EOL.CRLF); - } + }, }); Deno.test({ name: "[EOL] Detect LF", fn(): void { assertEquals(detect(LFinput), EOL.LF); - } + }, }); Deno.test({ name: "[EOL] Detect No New Line", fn(): void { assertEquals(detect(NoNLinput), null); - } + }, }); Deno.test({ @@ -34,7 +34,7 @@ Deno.test({ fn(): void { assertEquals(detect(Mixedinput), EOL.CRLF); assertEquals(detect(Mixedinput2), EOL.CRLF); - } + }, }); Deno.test({ @@ -50,5 +50,5 @@ Deno.test({ assertEquals(format(Mixedinput, EOL.LF), LFinput); assertEquals(format(Mixedinput2, EOL.CRLF), CRLFinput); assertEquals(format(Mixedinput2, EOL.LF), LFinput); - } + }, }); diff --git a/std/fs/exists_test.ts b/std/fs/exists_test.ts index 4202f2734b0a07..04c58d8d65691f 100644 --- a/std/fs/exists_test.ts +++ b/std/fs/exists_test.ts @@ -5,7 +5,7 @@ import { exists, existsSync } from "./exists.ts"; const testdataDir = path.resolve("fs", "testdata"); -Deno.test("[fs] existsFile", async function(): Promise { +Deno.test("[fs] existsFile", async function (): Promise { assertEquals( await exists(path.join(testdataDir, "not_exist_file.ts")), false @@ -13,12 +13,12 @@ Deno.test("[fs] existsFile", async function(): Promise { assertEquals(await existsSync(path.join(testdataDir, "0.ts")), true); }); -Deno.test("[fs] existsFileSync", function(): void { +Deno.test("[fs] existsFileSync", function (): void { assertEquals(existsSync(path.join(testdataDir, "not_exist_file.ts")), false); assertEquals(existsSync(path.join(testdataDir, "0.ts")), true); }); -Deno.test("[fs] existsDirectory", async function(): Promise { +Deno.test("[fs] existsDirectory", async function (): Promise { assertEquals( await exists(path.join(testdataDir, "not_exist_directory")), false @@ -26,7 +26,7 @@ Deno.test("[fs] existsDirectory", async function(): Promise { assertEquals(existsSync(testdataDir), true); }); -Deno.test("[fs] existsDirectorySync", function(): void { +Deno.test("[fs] existsDirectorySync", function (): void { assertEquals( existsSync(path.join(testdataDir, "not_exist_directory")), false @@ -34,16 +34,16 @@ Deno.test("[fs] existsDirectorySync", function(): void { assertEquals(existsSync(testdataDir), true); }); -Deno.test("[fs] existsLinkSync", function(): void { +Deno.test("[fs] existsLinkSync", function (): void { // TODO(axetroy): generate link file use Deno api instead of set a link file // in repository - assertEquals(existsSync(path.join(testdataDir, "0-link.ts")), true); + assertEquals(existsSync(path.join(testdataDir, "0-link")), true); }); -Deno.test("[fs] existsLink", async function(): Promise { +Deno.test("[fs] existsLink", async function (): Promise { // TODO(axetroy): generate link file use Deno api instead of set a link file // in repository - assertEquals(await exists(path.join(testdataDir, "0-link.ts")), true); + assertEquals(await exists(path.join(testdataDir, "0-link")), true); }); interface Scenes { @@ -59,59 +59,59 @@ const scenes: Scenes[] = [ read: false, async: true, output: "run again with the --allow-read flag", - file: "0.ts" + file: "0.ts", }, { read: false, async: false, output: "run again with the --allow-read flag", - file: "0.ts" + file: "0.ts", }, // 2 { read: true, async: true, output: "exist", - file: "0.ts" + file: "0.ts", }, { read: true, async: false, output: "exist", - file: "0.ts" + file: "0.ts", }, // 3 { read: false, async: true, output: "run again with the --allow-read flag", - file: "no_exist_file_for_test.ts" + file: "no_exist_file_for_test.ts", }, { read: false, async: false, output: "run again with the --allow-read flag", - file: "no_exist_file_for_test.ts" + file: "no_exist_file_for_test.ts", }, // 4 { read: true, async: true, output: "not exist", - file: "no_exist_file_for_test.ts" + file: "no_exist_file_for_test.ts", }, { read: true, async: false, output: "not exist", - file: "no_exist_file_for_test.ts" - } + file: "no_exist_file_for_test.ts", + }, ]; for (const s of scenes) { let title = `test ${s.async ? "exists" : "existsSync"}("testdata/${s.file}")`; title += ` ${s.read ? "with" : "without"} --allow-read`; - Deno.test(`[fs] existsPermission ${title}`, async function(): Promise { + Deno.test(`[fs] existsPermission ${title}`, async function (): Promise { const args = [Deno.execPath(), "run"]; if (s.read) { @@ -124,7 +124,7 @@ for (const s of scenes) { const p = Deno.run({ stdout: "piped", cwd: testdataDir, - args: args + cmd: args, }); const output = await p.output(); diff --git a/std/fs/expand_glob.ts b/std/fs/expand_glob.ts index c6653eda123584..10a8c2c520ef2b 100644 --- a/std/fs/expand_glob.ts +++ b/std/fs/expand_glob.ts @@ -6,7 +6,7 @@ import { isGlob, isWindows, joinGlobs, - normalize + normalize, } from "../path/mod.ts"; import { WalkInfo, walk, walkSync } from "./walk.ts"; import { assert } from "../testing/asserts.ts"; @@ -38,7 +38,7 @@ function split(path: string): SplitPath { segments, isAbsolute: isAbsolute_, hasTrailingSep: !!path.match(new RegExp(`${s}$`)), - winRoot: isWindows && isAbsolute_ ? segments.shift() : undefined + winRoot: isWindows && isAbsolute_ ? segments.shift() : undefined, }; } @@ -59,7 +59,7 @@ export async function* expandGlob( exclude = [], includeDirs = true, extended = false, - globstar = false + globstar = false, }: ExpandGlobOptions = {} ): AsyncIterableIterator { const globOptions: GlobOptions = { extended, globstar }; @@ -110,7 +110,7 @@ export async function* expandGlob( } else if (globSegment == "**") { return yield* walk(walkInfo.filename, { includeFiles: false, - skip: excludePatterns + skip: excludePatterns, }); } yield* walk(walkInfo.filename, { @@ -119,9 +119,9 @@ export async function* expandGlob( globToRegExp( joinGlobs([walkInfo.filename, globSegment], globOptions), globOptions - ) + ), ], - skip: excludePatterns + skip: excludePatterns, }); } @@ -138,7 +138,7 @@ export async function* expandGlob( currentMatches = [...nextMatchMap].sort().map( ([filename, info]): WalkInfo => ({ filename, - info + info, }) ); } @@ -163,7 +163,7 @@ export function* expandGlobSync( exclude = [], includeDirs = true, extended = false, - globstar = false + globstar = false, }: ExpandGlobOptions = {} ): IterableIterator { const globOptions: GlobOptions = { extended, globstar }; @@ -214,7 +214,7 @@ export function* expandGlobSync( } else if (globSegment == "**") { return yield* walkSync(walkInfo.filename, { includeFiles: false, - skip: excludePatterns + skip: excludePatterns, }); } yield* walkSync(walkInfo.filename, { @@ -223,9 +223,9 @@ export function* expandGlobSync( globToRegExp( joinGlobs([walkInfo.filename, globSegment], globOptions), globOptions - ) + ), ], - skip: excludePatterns + skip: excludePatterns, }); } @@ -242,7 +242,7 @@ export function* expandGlobSync( currentMatches = [...nextMatchMap].sort().map( ([filename, info]): WalkInfo => ({ filename, - info + info, }) ); } diff --git a/std/fs/expand_glob_test.ts b/std/fs/expand_glob_test.ts index 6bdb772668c4d7..6be9c518f41107 100644 --- a/std/fs/expand_glob_test.ts +++ b/std/fs/expand_glob_test.ts @@ -6,12 +6,12 @@ import { join, joinGlobs, normalize, - relative + relative, } from "../path/mod.ts"; import { ExpandGlobOptions, expandGlob, - expandGlobSync + expandGlobSync, } from "./expand_glob.ts"; async function expandGlobArray( @@ -48,7 +48,7 @@ const EG_OPTIONS: ExpandGlobOptions = { root: urlToFilePath(new URL(join("testdata", "glob"), import.meta.url)), includeDirs: true, extended: false, - globstar: false + globstar: false, }; Deno.test(async function expandGlobWildcard(): Promise { @@ -57,7 +57,7 @@ Deno.test(async function expandGlobWildcard(): Promise { "abc", "abcdef", "abcdefghi", - "subdir" + "subdir", ]); }); @@ -72,7 +72,7 @@ Deno.test(async function expandGlobParent(): Promise { "abc", "abcdef", "abcdefghi", - "subdir" + "subdir", ]); }); @@ -80,16 +80,16 @@ Deno.test(async function expandGlobExt(): Promise { const options = { ...EG_OPTIONS, extended: true }; assertEquals(await expandGlobArray("abc?(def|ghi)", options), [ "abc", - "abcdef" + "abcdef", ]); assertEquals(await expandGlobArray("abc*(def|ghi)", options), [ "abc", "abcdef", - "abcdefghi" + "abcdefghi", ]); assertEquals(await expandGlobArray("abc+(def|ghi)", options), [ "abcdef", - "abcdefghi" + "abcdefghi", ]); assertEquals(await expandGlobArray("abc@(def|ghi)", options), ["abcdef"]); assertEquals(await expandGlobArray("abc{def,ghi}", options), ["abcdef"]); @@ -120,10 +120,10 @@ Deno.test(async function expandGlobIncludeDirs(): Promise { Deno.test(async function expandGlobPermError(): Promise { const exampleUrl = new URL("testdata/expand_wildcard.js", import.meta.url); const p = run({ - args: [execPath(), exampleUrl.toString()], + cmd: [execPath(), exampleUrl.toString()], stdin: "null", stdout: "piped", - stderr: "piped" + stderr: "piped", }); assertEquals(await p.status(), { code: 1, success: false }); assertEquals(decode(await p.output()), ""); diff --git a/std/fs/move_test.ts b/std/fs/move_test.ts index b835e6dfa7ca06..999b67cf061058 100644 --- a/std/fs/move_test.ts +++ b/std/fs/move_test.ts @@ -2,7 +2,7 @@ import { assertEquals, assertThrows, - assertThrowsAsync + assertThrowsAsync, } from "../testing/asserts.ts"; import * as path from "../path/mod.ts"; import { move, moveSync } from "./move.ts"; @@ -68,7 +68,7 @@ Deno.test(async function moveFileIfDestExists(): Promise { // write file content await Promise.all([ Deno.writeFile(srcFile, srcContent), - Deno.writeFile(destFile, destContent) + Deno.writeFile(destFile, destContent), ]); // make sure the test file have been created @@ -100,7 +100,7 @@ Deno.test(async function moveFileIfDestExists(): Promise { // clean up await Promise.all([ Deno.remove(srcDir, { recursive: true }), - Deno.remove(destDir, { recursive: true }) + Deno.remove(destDir, { recursive: true }), ]); }); @@ -141,13 +141,13 @@ Deno.test(async function moveIfSrcAndDestDirectoryExistsAndOverwrite(): Promise< await Promise.all([ Deno.mkdir(srcDir, { recursive: true }), - Deno.mkdir(destDir, { recursive: true }) + Deno.mkdir(destDir, { recursive: true }), ]); assertEquals(await exists(srcDir), true); assertEquals(await exists(destDir), true); await Promise.all([ Deno.writeFile(srcFile, srcContent), - Deno.writeFile(destFile, destContent) + Deno.writeFile(destFile, destContent), ]); await move(srcDir, destDir, { overwrite: true }); diff --git a/std/fs/read_json_test.ts b/std/fs/read_json_test.ts index c394963b0fb05d..bdb5edbe5b685e 100644 --- a/std/fs/read_json_test.ts +++ b/std/fs/read_json_test.ts @@ -2,7 +2,7 @@ import { assertEquals, assertThrowsAsync, - assertThrows + assertThrows, } from "../testing/asserts.ts"; import * as path from "../path/mod.ts"; import { readJson, readJsonSync } from "./read_json.ts"; diff --git a/std/fs/testdata/0-link b/std/fs/testdata/0-link new file mode 120000 index 00000000000000..937f1e899f79a7 --- /dev/null +++ b/std/fs/testdata/0-link @@ -0,0 +1 @@ +0.ts \ No newline at end of file diff --git a/std/fs/testdata/0-link.ts b/std/fs/testdata/0-link.ts deleted file mode 120000 index 24c6b8053c8e01..00000000000000 --- a/std/fs/testdata/0-link.ts +++ /dev/null @@ -1 +0,0 @@ -./fs/testdata/0.ts \ No newline at end of file diff --git a/std/fs/testdata/empty_dir.ts b/std/fs/testdata/empty_dir.ts index aa9cf60a175ed6..f8fcc1cebee618 100644 --- a/std/fs/testdata/empty_dir.ts +++ b/std/fs/testdata/empty_dir.ts @@ -2,8 +2,8 @@ import { emptyDir } from "../empty_dir.ts"; emptyDir(Deno.args[0]) .then(() => { - Deno.stdout.write(new TextEncoder().encode("success")) + Deno.stdout.write(new TextEncoder().encode("success")); }) .catch((err) => { - Deno.stdout.write(new TextEncoder().encode(err.message)) - }) \ No newline at end of file + Deno.stdout.write(new TextEncoder().encode(err.message)); + }); diff --git a/std/fs/testdata/exists_sync.ts b/std/fs/testdata/exists_sync.ts index 27dee268b63b15..8cc51e9f8a3305 100644 --- a/std/fs/testdata/exists_sync.ts +++ b/std/fs/testdata/exists_sync.ts @@ -1,10 +1,8 @@ import { existsSync } from "../exists.ts"; try { - const isExist = existsSync(Deno.args[0]) - Deno.stdout.write(new TextEncoder().encode(isExist ? 'exist' :'not exist')) + const isExist = existsSync(Deno.args[0]); + Deno.stdout.write(new TextEncoder().encode(isExist ? "exist" : "not exist")); } catch (err) { - Deno.stdout.write(new TextEncoder().encode(err.message)) + Deno.stdout.write(new TextEncoder().encode(err.message)); } - - diff --git a/std/fs/utils_test.ts b/std/fs/utils_test.ts index 93f4664e7df75f..95686d8243c527 100644 --- a/std/fs/utils_test.ts +++ b/std/fs/utils_test.ts @@ -17,10 +17,10 @@ Deno.test(function _isSubdir(): void { ["first", "first/second", true, path.posix.sep], ["../first", "../first/second", true, path.posix.sep], ["c:\\first", "c:\\first", false, path.win32.sep], - ["c:\\first", "c:\\first\\second", true, path.win32.sep] + ["c:\\first", "c:\\first\\second", true, path.win32.sep], ]; - pairs.forEach(function(p): void { + pairs.forEach(function (p): void { const src = p[0] as string; const dest = p[1] as string; const expected = p[2] as boolean; @@ -36,10 +36,10 @@ Deno.test(function _isSubdir(): void { Deno.test(function _getFileInfoType(): void { const pairs = [ [path.join(testdataDir, "file_type_1"), "file"], - [path.join(testdataDir, "file_type_dir_1"), "dir"] + [path.join(testdataDir, "file_type_dir_1"), "dir"], ]; - pairs.forEach(function(p): void { + pairs.forEach(function (p): void { const filePath = p[0] as string; const type = p[1] as PathType; switch (type) { diff --git a/std/fs/walk.ts b/std/fs/walk.ts index fbd14740b68e88..3f178c0c568ff8 100644 --- a/std/fs/walk.ts +++ b/std/fs/walk.ts @@ -67,7 +67,7 @@ export async function* walk( followSymlinks = false, exts = undefined, match = undefined, - skip = undefined + skip = undefined, }: WalkOptions = {} ): AsyncIterableIterator { if (maxDepth < 0) { @@ -105,7 +105,7 @@ export async function* walk( followSymlinks, exts, match, - skip + skip, }); } } @@ -121,7 +121,7 @@ export function* walkSync( followSymlinks = false, exts = undefined, match = undefined, - skip = undefined + skip = undefined, }: WalkOptions = {} ): IterableIterator { if (maxDepth < 0) { @@ -158,7 +158,7 @@ export function* walkSync( followSymlinks, exts, match, - skip + skip, }); } } diff --git a/std/fs/write_json_test.ts b/std/fs/write_json_test.ts index 09fa05d604a9e4..335d35bfe06c1e 100644 --- a/std/fs/write_json_test.ts +++ b/std/fs/write_json_test.ts @@ -2,7 +2,7 @@ import { assertEquals, assertThrowsAsync, - assertThrows + assertThrows, } from "../testing/asserts.ts"; import * as path from "../path/mod.ts"; import { writeJson, writeJsonSync } from "./write_json.ts"; @@ -108,7 +108,7 @@ Deno.test(async function writeJsonWithReplacer(): Promise { existsJsonFile, { a: "1", b: "2", c: "3" }, { - replacer: ["a"] + replacer: ["a"], } ); throw new Error("should write success"); @@ -226,7 +226,7 @@ Deno.test(function writeJsonWithReplacer(): void { existsJsonFile, { a: "1", b: "2", c: "3" }, { - replacer: ["a"] + replacer: ["a"], } ); throw new Error("should write success"); diff --git a/std/http/cookie.ts b/std/http/cookie.ts index 10c9bd689a0264..062019f14eeaca 100644 --- a/std/http/cookie.ts +++ b/std/http/cookie.ts @@ -130,6 +130,6 @@ export function delCookie(res: Response, name: string): void { setCookie(res, { name: name, value: "", - expires: new Date(0) + expires: new Date(0), }); } diff --git a/std/http/cookie_test.ts b/std/http/cookie_test.ts index 8ab862bb3a2a36..1b78b2bff2a9b5 100644 --- a/std/http/cookie_test.ts +++ b/std/http/cookie_test.ts @@ -27,9 +27,9 @@ test({ assertEquals(getCookies(req), { PREF: "al=en-GB&f1=123", wide: "1", - SID: "123" + SID: "123", }); - } + }, }); test({ @@ -41,7 +41,7 @@ test({ res.headers?.get("Set-Cookie"), "deno=; Expires=Thu, 01 Jan 1970 00:00:00 GMT" ); - } + }, }); test({ @@ -66,7 +66,7 @@ test({ name: "Space", value: "Cat", httpOnly: true, - secure: true + secure: true, }); assertEquals(res.headers.get("Set-Cookie"), "Space=Cat; Secure; HttpOnly"); @@ -76,7 +76,7 @@ test({ value: "Cat", httpOnly: true, secure: true, - maxAge: 2 + maxAge: 2, }); assertEquals( res.headers.get("Set-Cookie"), @@ -91,7 +91,7 @@ test({ value: "Cat", httpOnly: true, secure: true, - maxAge: 0 + maxAge: 0, }); } catch (e) { error = true; @@ -105,7 +105,7 @@ test({ httpOnly: true, secure: true, maxAge: 2, - domain: "deno.land" + domain: "deno.land", }); assertEquals( res.headers.get("Set-Cookie"), @@ -120,7 +120,7 @@ test({ secure: true, maxAge: 2, domain: "deno.land", - sameSite: "Strict" + sameSite: "Strict", }); assertEquals( res.headers.get("Set-Cookie"), @@ -136,7 +136,7 @@ test({ secure: true, maxAge: 2, domain: "deno.land", - sameSite: "Lax" + sameSite: "Lax", }); assertEquals( res.headers.get("Set-Cookie"), @@ -151,7 +151,7 @@ test({ secure: true, maxAge: 2, domain: "deno.land", - path: "/" + path: "/", }); assertEquals( res.headers.get("Set-Cookie"), @@ -167,7 +167,7 @@ test({ maxAge: 2, domain: "deno.land", path: "/", - unparsed: ["unparsed=keyvalue", "batman=Bruce"] + unparsed: ["unparsed=keyvalue", "batman=Bruce"], }); assertEquals( res.headers.get("Set-Cookie"), @@ -184,7 +184,7 @@ test({ maxAge: 2, domain: "deno.land", path: "/", - expires: new Date(Date.UTC(1983, 0, 7, 15, 32)) + expires: new Date(Date.UTC(1983, 0, 7, 15, 32)), }); assertEquals( res.headers.get("Set-Cookie"), @@ -200,11 +200,11 @@ test({ setCookie(res, { name: "__Host-Kitty", value: "Meow", - domain: "deno.land" + domain: "deno.land", }); assertEquals( res.headers.get("Set-Cookie"), "__Host-Kitty=Meow; Secure; Path=/" ); - } + }, }); diff --git a/std/http/file_server.ts b/std/http/file_server.ts index 20d5d61e64ec74..5582afd076f388 100755 --- a/std/http/file_server.ts +++ b/std/http/file_server.ts @@ -108,7 +108,7 @@ async function serveFile( const res = { status: 200, body: file, - headers + headers, }; return res; } @@ -137,7 +137,7 @@ async function serveDir( mode: modeToString(fileInfo.isDirectory(), mode), size: fileInfo.isFile() ? fileLenToString(fileInfo.size) : "", name: fileInfo.name ?? "", - url: fileUrl + url: fileUrl, }); } listEntry.sort((a, b) => @@ -152,7 +152,7 @@ async function serveDir( const res = { status: 200, body: page, - headers + headers, }; setContentLength(res); return res; @@ -162,12 +162,12 @@ function serveFallback(req: ServerRequest, e: Error): Promise { if (e instanceof Deno.errors.NotFound) { return Promise.resolve({ status: 404, - body: encoder.encode("Not found") + body: encoder.encode("Not found"), }); } else { return Promise.resolve({ status: 500, - body: encoder.encode("Internal server error") + body: encoder.encode("Internal server error"), }); } } @@ -258,19 +258,20 @@ function dirViewerTemplate(dirname: string, entries: EntryInfo[]): string { Name ${entries.map( - entry => html` - - - ${entry.mode} - - - ${entry.size} - - - ${entry.name} - - - ` + (entry) => + html` + + + ${entry.mode} + + + ${entry.size} + + + ${entry.name} + + + ` )} diff --git a/std/http/file_server_test.ts b/std/http/file_server_test.ts index 1fbe3ba970f903..3a3817ce066266 100644 --- a/std/http/file_server_test.ts +++ b/std/http/file_server_test.ts @@ -7,17 +7,17 @@ let fileServer: Deno.Process; async function startFileServer(): Promise { fileServer = Deno.run({ - args: [ + cmd: [ Deno.execPath(), "run", "--allow-read", "--allow-net", "http/file_server.ts", ".", - "--cors" + "--cors", ], stdout: "piped", - stderr: "null" + stderr: "null", }); // Once fileServer is ready it will write to its stdout. assert(fileServer.stdout != null); @@ -104,9 +104,9 @@ test(async function serveWithUnorthodoxFilename(): Promise { test(async function servePermissionDenied(): Promise { const deniedServer = Deno.run({ - args: [Deno.execPath(), "run", "--allow-net", "http/file_server.ts"], + cmd: [Deno.execPath(), "run", "--allow-net", "http/file_server.ts"], stdout: "piped", - stderr: "piped" + stderr: "piped", }); assert(deniedServer.stdout != null); const reader = new TextProtoReader(new BufReader(deniedServer.stdout)); @@ -131,8 +131,8 @@ test(async function servePermissionDenied(): Promise { test(async function printHelp(): Promise { const helpProcess = Deno.run({ - args: [Deno.execPath(), "run", "http/file_server.ts", "--help"], - stdout: "piped" + cmd: [Deno.execPath(), "run", "http/file_server.ts", "--help"], + stdout: "piped", }); assert(helpProcess.stdout != null); const r = new TextProtoReader(new BufReader(helpProcess.stdout)); diff --git a/std/http/http_bench.ts b/std/http/http_bench.ts index 9d191283170cd0..15f2233233e4f4 100644 --- a/std/http/http_bench.ts +++ b/std/http/http_bench.ts @@ -9,7 +9,7 @@ console.log(`http://${addr}/`); for await (const req of server) { const res = { body, - headers: new Headers() + headers: new Headers(), }; res.headers.set("Date", new Date().toUTCString()); res.headers.set("Connection", "keep-alive"); diff --git a/std/http/http_status.ts b/std/http/http_status.ts index ead1e1ff0e2ce0..ce4338705c1411 100644 --- a/std/http/http_status.ts +++ b/std/http/http_status.ts @@ -125,14 +125,13 @@ export enum Status { /** RFC 2774, 7 */ NotExtended = 510, /** RFC 6585, 6 */ - NetworkAuthenticationRequired = 511 + NetworkAuthenticationRequired = 511, } export const STATUS_TEXT = new Map([ [Status.Continue, "Continue"], [Status.SwitchingProtocols, "Switching Protocols"], [Status.Processing, "Processing"], - [Status.OK, "OK"], [Status.Created, "Created"], [Status.Accepted, "Accepted"], @@ -143,7 +142,6 @@ export const STATUS_TEXT = new Map([ [Status.MultiStatus, "Multi-Status"], [Status.AlreadyReported, "Already Reported"], [Status.IMUsed, "IM Used"], - [Status.MultipleChoices, "Multiple Choices"], [Status.MovedPermanently, "Moved Permanently"], [Status.Found, "Found"], @@ -152,7 +150,6 @@ export const STATUS_TEXT = new Map([ [Status.UseProxy, "Use Proxy"], [Status.TemporaryRedirect, "Temporary Redirect"], [Status.PermanentRedirect, "Permanent Redirect"], - [Status.BadRequest, "Bad Request"], [Status.Unauthorized, "Unauthorized"], [Status.PaymentRequired, "Payment Required"], @@ -181,7 +178,6 @@ export const STATUS_TEXT = new Map([ [Status.TooManyRequests, "Too Many Requests"], [Status.RequestHeaderFieldsTooLarge, "Request Header Fields Too Large"], [Status.UnavailableForLegalReasons, "Unavailable For Legal Reasons"], - [Status.InternalServerError, "Internal Server Error"], [Status.NotImplemented, "Not Implemented"], [Status.BadGateway, "Bad Gateway"], @@ -192,5 +188,5 @@ export const STATUS_TEXT = new Map([ [Status.InsufficientStorage, "Insufficient Storage"], [Status.LoopDetected, "Loop Detected"], [Status.NotExtended, "Not Extended"], - [Status.NetworkAuthenticationRequired, "Network Authentication Required"] + [Status.NetworkAuthenticationRequired, "Network Authentication Required"], ]); diff --git a/std/http/io.ts b/std/http/io.ts index 6d5d1f66537c85..2875be44fd652c 100644 --- a/std/http/io.ts +++ b/std/http/io.ts @@ -9,7 +9,7 @@ export function emptyReader(): Deno.Reader { return { read(_: Uint8Array): Promise { return Promise.resolve(Deno.EOF); - } + }, }; } @@ -83,7 +83,7 @@ export function chunkedBodyReader(h: Headers, r: BufReader): Deno.Reader { } else { chunks.push({ offset: 0, - data: restChunk + data: restChunk, }); } return buf.byteLength; @@ -116,7 +116,7 @@ export function chunkedBodyReader(h: Headers, r: BufReader): Deno.Reader { const kProhibitedTrailerHeaders = [ "transfer-encoding", "content-length", - "trailer" + "trailer", ]; /** @@ -147,7 +147,7 @@ function parseTrailer(field: string | null): Set | undefined { if (field == null) { return undefined; } - const keys = field.split(",").map(v => v.trim()); + const keys = field.split(",").map((v) => v.trim()); if (keys.length === 0) { throw new Error("Empty trailer"); } @@ -196,7 +196,7 @@ export async function writeTrailers( const writer = BufWriter.create(w); const trailerHeaderFields = trailer .split(",") - .map(s => s.trim().toLowerCase()); + .map((s) => s.trim().toLowerCase()); for (const f of trailerHeaderFields) { assert( !kProhibitedTrailerHeaders.includes(f), diff --git a/std/http/io_test.ts b/std/http/io_test.ts index 6c96d0b95f70dc..7261964d07da8f 100644 --- a/std/http/io_test.ts +++ b/std/http/io_test.ts @@ -4,7 +4,7 @@ import { assertEquals, assert, assertNotEOF, - assertNotEquals + assertNotEquals, } from "../testing/asserts.ts"; import { bodyReader, @@ -12,7 +12,7 @@ import { readTrailers, parseHTTPVersion, readRequest, - writeResponse + writeResponse, } from "./io.ts"; import { encode, decode } from "../strings/mod.ts"; import { BufReader, ReadLineResult } from "../io/bufio.ts"; @@ -39,7 +39,7 @@ test("chunkedBodyReader", async () => { chunkify(5, "b"), chunkify(11, "c"), chunkify(22, "d"), - chunkify(0, "") + chunkify(0, ""), ].join(""); const h = new Headers(); const r = chunkedBodyReader(h, new BufReader(new Buffer(encode(body)))); @@ -64,10 +64,10 @@ test("chunkedBodyReader with trailers", async () => { chunkify(0, ""), "deno: land\r\n", "node: js\r\n", - "\r\n" + "\r\n", ].join(""); const h = new Headers({ - trailer: "deno,node" + trailer: "deno,node", }); const r = chunkedBodyReader(h, new BufReader(new Buffer(encode(body)))); assertEquals(h.has("trailer"), true); @@ -83,7 +83,7 @@ test("chunkedBodyReader with trailers", async () => { test("readTrailers", async () => { const h = new Headers({ - trailer: "deno,node" + trailer: "deno,node", }); const trailer = ["deno: land", "node: js", "", ""].join("\r\n"); await readTrailers(h, new BufReader(new Buffer(encode(trailer)))); @@ -96,11 +96,11 @@ test("readTrailer should throw if undeclared headers found in trailer", async () const patterns = [ ["deno,node", "deno: land\r\nnode: js\r\ngo: lang\r\n\r\n"], ["deno", "node: js\r\n\r\n"], - ["deno", "node:js\r\ngo: lang\r\n\r\n"] + ["deno", "node:js\r\ngo: lang\r\n\r\n"], ]; for (const [header, trailer] of patterns) { const h = new Headers({ - trailer: header + trailer: header, }); await assertThrowsAsync( async () => { @@ -115,7 +115,7 @@ test("readTrailer should throw if undeclared headers found in trailer", async () test("readTrailer should throw if trailer contains prohibited fields", async () => { for (const f of ["content-length", "trailer", "transfer-encoding"]) { const h = new Headers({ - trailer: f + trailer: f, }); await assertThrowsAsync( async () => { @@ -192,7 +192,7 @@ test("parseHttpVersion", (): void => { { in: "HTTP/-1.0", err: true }, { in: "HTTP/0.-1", err: true }, { in: "HTTP/", err: true }, - { in: "HTTP/1,0", err: true } + { in: "HTTP/1,0", err: true }, ]; for (const t of testCases) { let r, err; @@ -320,10 +320,10 @@ test("writeResponse with trailer", async () => { status: 200, headers: new Headers({ "transfer-encoding": "chunked", - trailer: "deno,node" + trailer: "deno,node", }), body, - trailers: () => new Headers({ deno: "land", node: "js" }) + trailers: () => new Headers({ deno: "land", node: "js" }), }); const ret = w.toString(); const exp = [ @@ -338,7 +338,7 @@ test("writeResponse with trailer", async () => { "deno: land", "node: js", "", - "" + "", ].join("\r\n"); assertEquals(ret, exp); }); @@ -365,20 +365,20 @@ test(async function testReadRequestError(): Promise { const testCases = [ { in: "GET / HTTP/1.1\r\nheader: foo\r\n\r\n", - headers: [{ key: "header", value: "foo" }] + headers: [{ key: "header", value: "foo" }], }, { in: "GET / HTTP/1.1\r\nheader:foo\r\n", - err: Deno.errors.UnexpectedEof + err: Deno.errors.UnexpectedEof, }, { in: "", err: Deno.EOF }, { in: "HEAD / HTTP/1.1\r\nContent-Length:4\r\n\r\n", - err: "http: method cannot contain a Content-Length" + err: "http: method cannot contain a Content-Length", }, { in: "HEAD / HTTP/1.1\r\n\r\n", - headers: [] + headers: [], }, // Multiple Content-Length values should either be // deduplicated if same or reject otherwise @@ -387,23 +387,23 @@ test(async function testReadRequestError(): Promise { in: "POST / HTTP/1.1\r\nContent-Length: 10\r\nContent-Length: 0\r\n\r\n" + "Gopher hey\r\n", - err: "cannot contain multiple Content-Length headers" + err: "cannot contain multiple Content-Length headers", }, { in: "POST / HTTP/1.1\r\nContent-Length: 10\r\nContent-Length: 6\r\n\r\n" + "Gopher\r\n", - err: "cannot contain multiple Content-Length headers" + err: "cannot contain multiple Content-Length headers", }, { in: "PUT / HTTP/1.1\r\nContent-Length: 6 \r\nContent-Length: 6\r\n" + "Content-Length:6\r\n\r\nGopher\r\n", - headers: [{ key: "Content-Length", value: "6" }] + headers: [{ key: "Content-Length", value: "6" }], }, { in: "PUT / HTTP/1.1\r\nContent-Length: 1\r\nContent-Length: 6 \r\n\r\n", - err: "cannot contain multiple Content-Length headers" + err: "cannot contain multiple Content-Length headers", }, // Setting an empty header is swallowed by textproto // see: readMIMEHeader() @@ -413,15 +413,15 @@ test(async function testReadRequestError(): Promise { // }, { in: "HEAD / HTTP/1.1\r\nContent-Length:0\r\nContent-Length: 0\r\n\r\n", - headers: [{ key: "Content-Length", value: "0" }] + headers: [{ key: "Content-Length", value: "0" }], }, { in: "POST / HTTP/1.1\r\nContent-Length:0\r\ntransfer-encoding: " + "chunked\r\n\r\n", headers: [], - err: "http: Transfer-Encoding and Content-Length cannot be send together" - } + err: "http: Transfer-Encoding and Content-Length cannot be send together", + }, ]; for (const test of testCases) { const reader = new BufReader(new StringReader(test.in)); diff --git a/std/http/mock.ts b/std/http/mock.ts index cee697bed89919..64bd3fcb99c9bd 100644 --- a/std/http/mock.ts +++ b/std/http/mock.ts @@ -4,12 +4,12 @@ export function mockConn(base: Partial = {}): Deno.Conn { localAddr: { transport: "tcp", hostname: "", - port: 0 + port: 0, }, remoteAddr: { transport: "tcp", hostname: "", - port: 0 + port: 0, }, rid: -1, closeRead: (): void => {}, @@ -21,6 +21,6 @@ export function mockConn(base: Partial = {}): Deno.Conn { return Promise.resolve(-1); }, close: (): void => {}, - ...base + ...base, }; } diff --git a/std/http/racing_server_test.ts b/std/http/racing_server_test.ts index d82acebabff5bf..037e91ef97807a 100644 --- a/std/http/racing_server_test.ts +++ b/std/http/racing_server_test.ts @@ -6,8 +6,8 @@ const { connect, run, test } = Deno; let server: Deno.Process; async function startServer(): Promise { server = run({ - args: [Deno.execPath(), "run", "-A", "http/racing_server.ts"], - stdout: "piped" + cmd: [Deno.execPath(), "run", "-A", "http/racing_server.ts"], + stdout: "piped", }); // Once racing server is ready it will write to its stdout. assert(server.stdout != null); @@ -27,7 +27,7 @@ const input = [ "POST / HTTP/1.1\r\ncontent-length: 4\r\n\r\ndeno", "POST / HTTP/1.1\r\ntransfer-encoding: chunked\r\n\r\n4\r\ndeno\r\n0\r\n\r\n", "POST / HTTP/1.1\r\ntransfer-encoding: chunked\r\ntrailer: deno\r\n\r\n4\r\ndeno\r\n0\r\n\r\ndeno: land\r\n\r\n", - "GET / HTTP/1.1\r\n\r\n" + "GET / HTTP/1.1\r\n\r\n", ].join(""); const HUGE_BODY_SIZE = 1024 * 1024; const output = `HTTP/1.1 200 OK diff --git a/std/http/server.ts b/std/http/server.ts index 2cd51b005136b2..00f401f62731bc 100644 --- a/std/http/server.ts +++ b/std/http/server.ts @@ -7,7 +7,7 @@ import { chunkedBodyReader, emptyReader, writeResponse, - readRequest + readRequest, } from "./io.ts"; import Listener = Deno.Listener; import Conn = Deno.Conn; @@ -298,7 +298,7 @@ export type HTTPSOptions = Omit; export function serveTLS(options: HTTPSOptions): Server { const tlsOptions: Deno.ListenTLSOptions = { ...options, - transport: "tcp" + transport: "tcp", }; const listener = listenTLS(tlsOptions); return new Server(listener); diff --git a/std/http/server_test.ts b/std/http/server_test.ts index 2a7c46134b8db7..d6b2be053cdf16 100644 --- a/std/http/server_test.ts +++ b/std/http/server_test.ts @@ -11,7 +11,7 @@ import { assertEquals, assertNotEOF, assertStrContains, - assertThrowsAsync + assertThrowsAsync, } from "../testing/asserts.ts"; import { Response, ServerRequest, Server, serve } from "./server.ts"; import { BufReader, BufWriter } from "../io/bufio.ts"; @@ -30,27 +30,27 @@ const responseTests: ResponseTest[] = [ // Default response { response: {}, - raw: "HTTP/1.1 200 OK\r\n" + "content-length: 0" + "\r\n\r\n" + raw: "HTTP/1.1 200 OK\r\n" + "content-length: 0" + "\r\n\r\n", }, // Empty body with status { response: { - status: 404 + status: 404, }, - raw: "HTTP/1.1 404 Not Found\r\n" + "content-length: 0" + "\r\n\r\n" + raw: "HTTP/1.1 404 Not Found\r\n" + "content-length: 0" + "\r\n\r\n", }, // HTTP/1.1, chunked coding; empty trailer; close { response: { status: 200, - body: new Buffer(new TextEncoder().encode("abcdef")) + body: new Buffer(new TextEncoder().encode("abcdef")), }, raw: "HTTP/1.1 200 OK\r\n" + "transfer-encoding: chunked\r\n\r\n" + - "6\r\nabcdef\r\n0\r\n\r\n" - } + "6\r\nabcdef\r\n0\r\n\r\n", + }, ]; test(async function responseWrite(): Promise { @@ -118,7 +118,7 @@ function totalReader(r: Deno.Reader): TotalReader { read, get total(): number { return _total; - } + }, }; } test(async function requestBodyWithContentLength(): Promise { @@ -169,7 +169,7 @@ test("ServerRequest.finalize() should consume unread body / chunked, trailers", "deno: land", "node: js", "", - "" + "", ].join("\r\n"); const req = new ServerRequest(); req.headers = new Headers(); @@ -356,8 +356,8 @@ test({ fn: async (): Promise => { // Runs a simple server as another process const p = Deno.run({ - args: [Deno.execPath(), "--allow-net", "http/testdata/simple_server.ts"], - stdout: "piped" + cmd: [Deno.execPath(), "--allow-net", "http/testdata/simple_server.ts"], + stdout: "piped", }); let serverIsRunning = true; @@ -387,7 +387,7 @@ test({ p.stdout!.close(); p.close(); } - } + }, }); test({ @@ -397,13 +397,13 @@ test({ fn: async (): Promise => { // Runs a simple server as another process const p = Deno.run({ - args: [ + cmd: [ Deno.execPath(), "--allow-net", "--allow-read", - "http/testdata/simple_https_server.ts" + "http/testdata/simple_https_server.ts", ], - stdout: "piped" + stdout: "piped", }); let serverIsRunning = true; @@ -425,7 +425,7 @@ test({ const conn = await Deno.connectTLS({ hostname: "localhost", port: 4503, - certFile: "http/testdata/tls/RootCA.pem" + certFile: "http/testdata/tls/RootCA.pem", }); await Deno.writeAll( conn, @@ -444,7 +444,7 @@ test({ p.stdout!.close(); p.close(); } - } + }, }); test("close server while iterating", async (): Promise => { @@ -485,7 +485,7 @@ test({ const resources = Deno.resources(); assertEquals(resources[conn.rid], "tcpStream"); conn.close(); - } + }, }); test({ @@ -498,7 +498,7 @@ test({ await assertThrowsAsync(async () => { await req.respond({ status: 12345, - body: new TextEncoder().encode("Hello World") + body: new TextEncoder().encode("Hello World"), }); }, Deno.errors.InvalidData); // The connection should be destroyed @@ -509,7 +509,7 @@ test({ const p = serverRoutine(); const conn = await Deno.connect({ hostname: "127.0.0.1", - port: 8124 + port: 8124, }); await Deno.writeAll( conn, @@ -517,5 +517,5 @@ test({ ); conn.close(); await p; - } + }, }); diff --git a/std/io/bufio.ts b/std/io/bufio.ts index a944adfed4cb51..87613e3418c00c 100644 --- a/std/io/bufio.ts +++ b/std/io/bufio.ts @@ -212,8 +212,9 @@ export class BufReader implements Reader { * For simple uses, a Scanner may be more convenient. */ async readString(delim: string): Promise { - if (delim.length !== 1) + if (delim.length !== 1) { throw new Error("Delimiter should be a single character"); + } const buffer = await this.readSlice(delim.charCodeAt(0)); if (buffer == Deno.EOF) return Deno.EOF; return new TextDecoder().decode(buffer); diff --git a/std/io/bufio_test.ts b/std/io/bufio_test.ts index ae38f66673f389..c1b1b856b7a51c 100644 --- a/std/io/bufio_test.ts +++ b/std/io/bufio_test.ts @@ -9,7 +9,7 @@ import { assert, assertEquals, fail, - assertNotEOF + assertNotEOF, } from "../testing/asserts.ts"; import { BufReader, @@ -17,7 +17,7 @@ import { BufferFullError, PartialReadError, readStringDelim, - readLines + readLines, } from "./bufio.ts"; import * as iotest from "./iotest.ts"; import { charCode, copyBytes, stringsReader } from "./util.ts"; @@ -55,9 +55,9 @@ const readMakers: ReadMaker[] = [ { name: "full", fn: (r): Reader => r }, { name: "byte", - fn: (r): iotest.OneByteReader => new iotest.OneByteReader(r) + fn: (r): iotest.OneByteReader => new iotest.OneByteReader(r), }, - { name: "half", fn: (r): iotest.HalfReader => new iotest.HalfReader(r) } + { name: "half", fn: (r): iotest.HalfReader => new iotest.HalfReader(r) }, // TODO { name: "data+err", r => new iotest.DataErrReader(r) }, // { name: "timeout", fn: r => new iotest.TimeoutReader(r) }, ]; @@ -89,7 +89,7 @@ const bufreaders: NamedBufReader[] = [ { name: "4", fn: (b: BufReader): Promise => reads(b, 4) }, { name: "5", fn: (b: BufReader): Promise => reads(b, 5) }, { name: "7", fn: (b: BufReader): Promise => reads(b, 7) }, - { name: "bytes", fn: readBytes } + { name: "bytes", fn: readBytes }, // { name: "lines", fn: readLines }, ]; @@ -104,7 +104,7 @@ const bufsizes: number[] = [ 93, 128, 1024, - 4096 + 4096, ]; Deno.test(async function bufioBufReader(): Promise { diff --git a/std/io/ioutil_test.ts b/std/io/ioutil_test.ts index 3d85a0fa174a1a..d00986da5c1d22 100644 --- a/std/io/ioutil_test.ts +++ b/std/io/ioutil_test.ts @@ -7,7 +7,7 @@ import { readInt, readLong, readShort, - sliceLongToBytes + sliceLongToBytes, } from "./ioutil.ts"; import { BufReader } from "./bufio.ts"; import { stringsReader } from "./util.ts"; diff --git a/std/io/util_test.ts b/std/io/util_test.ts index 2fcad930576e66..17f11b94566935 100644 --- a/std/io/util_test.ts +++ b/std/io/util_test.ts @@ -4,7 +4,7 @@ import { assert, assertEquals } from "../testing/asserts.ts"; import * as path from "../path/mod.ts"; import { copyBytes, tempFile } from "./util.ts"; -test("[io/tuil] copyBytes", function(): void { +test("[io/tuil] copyBytes", function (): void { const dst = new Uint8Array(4); dst.fill(0); @@ -40,14 +40,14 @@ test("[io/tuil] copyBytes", function(): void { test({ name: "[io/util] tempfile", - fn: async function(): Promise { + fn: async function (): Promise { const f = await tempFile(".", { prefix: "prefix-", - postfix: "-postfix" + postfix: "-postfix", }); const base = path.basename(f.filepath); assert(!!base.match(/^prefix-.+?-postfix$/)); f.file.close(); await remove(f.filepath); - } + }, }); diff --git a/std/log/README.md b/std/log/README.md index 613e69922e56c1..dea1e5fe7e230a 100644 --- a/std/log/README.md +++ b/std/log/README.md @@ -21,22 +21,22 @@ await log.setup({ file: new log.handlers.FileHandler("WARNING", { filename: "./log.txt", // you can change format of output message - formatter: "{levelName} {msg}" - }) + formatter: "{levelName} {msg}", + }), }, loggers: { // configure default logger available via short-hand methods above default: { level: "DEBUG", - handlers: ["console", "file"] + handlers: ["console", "file"], }, tasks: { level: "ERROR", - handlers: ["console"] - } - } + handlers: ["console"], + }, + }, }); let logger; diff --git a/std/log/handlers_test.ts b/std/log/handlers_test.ts index 693d2a48554dde..4feffdaf944310 100644 --- a/std/log/handlers_test.ts +++ b/std/log/handlers_test.ts @@ -21,8 +21,8 @@ test(function simpleHandler(): void { "INFO info-test", "WARNING warning-test", "ERROR error-test", - "CRITICAL critical-test" - ] + "CRITICAL critical-test", + ], ], [ LogLevel.INFO, @@ -30,15 +30,15 @@ test(function simpleHandler(): void { "INFO info-test", "WARNING warning-test", "ERROR error-test", - "CRITICAL critical-test" - ] + "CRITICAL critical-test", + ], ], [ LogLevel.WARNING, - ["WARNING warning-test", "ERROR error-test", "CRITICAL critical-test"] + ["WARNING warning-test", "ERROR error-test", "CRITICAL critical-test"], ], [LogLevel.ERROR, ["ERROR error-test", "CRITICAL critical-test"]], - [LogLevel.CRITICAL, ["CRITICAL critical-test"]] + [LogLevel.CRITICAL, ["CRITICAL critical-test"]], ]); for (const [testCase, messages] of cases.entries()) { @@ -52,7 +52,7 @@ test(function simpleHandler(): void { args: [], datetime: new Date(), level: level, - levelName: levelName + levelName: levelName, }); } @@ -64,7 +64,7 @@ test(function simpleHandler(): void { test(function testFormatterAsString(): void { const handler = new TestHandler("DEBUG", { - formatter: "test {levelName} {msg}" + formatter: "test {levelName} {msg}", }); handler.handle({ @@ -72,7 +72,7 @@ test(function testFormatterAsString(): void { args: [], datetime: new Date(), level: LogLevel.DEBUG, - levelName: "DEBUG" + levelName: "DEBUG", }); assertEquals(handler.messages, ["test DEBUG Hello, world!"]); @@ -81,7 +81,7 @@ test(function testFormatterAsString(): void { test(function testFormatterAsFunction(): void { const handler = new TestHandler("DEBUG", { formatter: (logRecord): string => - `fn formmatter ${logRecord.levelName} ${logRecord.msg}` + `fn formmatter ${logRecord.levelName} ${logRecord.msg}`, }); handler.handle({ @@ -89,7 +89,7 @@ test(function testFormatterAsFunction(): void { args: [], datetime: new Date(), level: LogLevel.ERROR, - levelName: "ERROR" + levelName: "ERROR", }); assertEquals(handler.messages, ["fn formmatter ERROR Hello, world!"]); diff --git a/std/log/levels.ts b/std/log/levels.ts index 599629f858ed6f..be960dd572d00e 100644 --- a/std/log/levels.ts +++ b/std/log/levels.ts @@ -5,7 +5,7 @@ export const LogLevel: Record = { INFO: 20, WARNING: 30, ERROR: 40, - CRITICAL: 50 + CRITICAL: 50, }; const byLevel = { @@ -14,7 +14,7 @@ const byLevel = { [LogLevel.INFO]: "INFO", [LogLevel.WARNING]: "WARNING", [LogLevel.ERROR]: "ERROR", - [LogLevel.CRITICAL]: "CRITICAL" + [LogLevel.CRITICAL]: "CRITICAL", }; export function getLevelByName(name: string): number { diff --git a/std/log/logger.ts b/std/log/logger.ts index 99d17ef48f018b..226b8dba61177c 100644 --- a/std/log/logger.ts +++ b/std/log/logger.ts @@ -34,7 +34,7 @@ export class Logger { args: args, datetime: new Date(), level: level, - levelName: getLevelName(level) + levelName: getLevelName(level), }; this.handlers.forEach((handler): void => { handler.handle(record); diff --git a/std/log/logger_test.ts b/std/log/logger_test.ts index 76ff4cf9559020..3e8898afaabeb4 100644 --- a/std/log/logger_test.ts +++ b/std/log/logger_test.ts @@ -67,7 +67,7 @@ test(function logFunctions(): void { "INFO bar", "WARNING baz", "ERROR boo", - "CRITICAL doo" + "CRITICAL doo", ]); handler = doLog("INFO"); @@ -76,7 +76,7 @@ test(function logFunctions(): void { "INFO bar", "WARNING baz", "ERROR boo", - "CRITICAL doo" + "CRITICAL doo", ]); handler = doLog("WARNING"); diff --git a/std/log/mod.ts b/std/log/mod.ts index b89896264f7560..333e90fb9a69c3 100644 --- a/std/log/mod.ts +++ b/std/log/mod.ts @@ -4,7 +4,7 @@ import { BaseHandler, ConsoleHandler, WriterHandler, - FileHandler + FileHandler, } from "./handlers.ts"; import { assert } from "../testing/asserts.ts"; @@ -25,28 +25,28 @@ export interface LogConfig { const DEFAULT_LEVEL = "INFO"; const DEFAULT_CONFIG: LogConfig = { handlers: { - default: new ConsoleHandler(DEFAULT_LEVEL) + default: new ConsoleHandler(DEFAULT_LEVEL), }, loggers: { default: { level: DEFAULT_LEVEL, - handlers: ["default"] - } - } + handlers: ["default"], + }, + }, }; const state = { handlers: new Map(), loggers: new Map(), - config: DEFAULT_CONFIG + config: DEFAULT_CONFIG, }; export const handlers = { BaseHandler, ConsoleHandler, WriterHandler, - FileHandler + FileHandler, }; export function getLogger(name?: string): Logger { @@ -81,7 +81,7 @@ export const critical = (msg: string, ...args: unknown[]): void => export async function setup(config: LogConfig): Promise { state.config = { handlers: { ...DEFAULT_CONFIG.handlers, ...config.handlers }, - loggers: { ...DEFAULT_CONFIG.loggers, ...config.loggers } + loggers: { ...DEFAULT_CONFIG.loggers, ...config.loggers }, }; // tear down existing handlers diff --git a/std/log/test.ts b/std/log/test.ts index d4385968c61679..858f722e273f2b 100644 --- a/std/log/test.ts +++ b/std/log/test.ts @@ -20,7 +20,7 @@ test(async function defaultHandlers(): Promise { INFO: log.info, WARNING: log.warning, ERROR: log.error, - CRITICAL: log.critical + CRITICAL: log.critical, }; for (const levelName in LogLevel) { @@ -33,14 +33,14 @@ test(async function defaultHandlers(): Promise { await log.setup({ handlers: { - default: handler + default: handler, }, loggers: { default: { level: levelName, - handlers: ["default"] - } - } + handlers: ["default"], + }, + }, }); logger("foo"); @@ -55,14 +55,14 @@ test(async function getLogger(): Promise { await log.setup({ handlers: { - default: handler + default: handler, }, loggers: { default: { level: "DEBUG", - handlers: ["default"] - } - } + handlers: ["default"], + }, + }, }); const logger = log.getLogger(); @@ -76,14 +76,14 @@ test(async function getLoggerWithName(): Promise { await log.setup({ handlers: { - foo: fooHandler + foo: fooHandler, }, loggers: { bar: { level: "INFO", - handlers: ["foo"] - } - } + handlers: ["foo"], + }, + }, }); const logger = log.getLogger("bar"); @@ -95,7 +95,7 @@ test(async function getLoggerWithName(): Promise { test(async function getLoggerUnknown(): Promise { await log.setup({ handlers: {}, - loggers: {} + loggers: {}, }); const logger = log.getLogger("nonexistent"); diff --git a/std/manual.md b/std/manual.md index 3d74259ef0e251..1e8fefcb106d55 100644 --- a/std/manual.md +++ b/std/manual.md @@ -366,7 +366,7 @@ Example: ```ts // create subprocess const p = Deno.run({ - args: ["echo", "hello"] + cmd: ["echo", "hello"], }); // await its completion @@ -393,15 +393,15 @@ you can use `"piped"` option. const fileNames = Deno.args; const p = Deno.run({ - args: [ + cmd: [ "deno", "run", "--allow-read", "https://deno.land/std/examples/cat.ts", - ...fileNames + ...fileNames, ], stdout: "piped", - stderr: "piped" + stderr: "piped", }); const { code } = await p.status(); @@ -557,7 +557,7 @@ assertion library across a large project. Rather than importing export { assert, assertEquals, - assertStrContains + assertStrContains, } from "https://deno.land/std/testing/asserts.ts"; ``` @@ -676,10 +676,10 @@ TypeScript `"dom"` library: const [errors, emitted] = await Deno.compile( "main.ts", { - "main.ts": `document.getElementById("foo");\n` + "main.ts": `document.getElementById("foo");\n`, }, { - lib: ["dom", "esnext"] + lib: ["dom", "esnext"], } ); ``` @@ -716,10 +716,10 @@ lib in the array. For example: const [errors, emitted] = await Deno.compile( "main.ts", { - "main.ts": `document.getElementById("foo");\n` + "main.ts": `document.getElementById("foo");\n`, }, { - lib: ["dom", "esnext", "deno.ns"] + lib: ["dom", "esnext", "deno.ns"], } ); ``` @@ -745,7 +745,7 @@ It would compiler without errors like this: ```ts const [errors, emitted] = await Deno.compile("./main.ts", undefined, { - lib: ["esnext"] + lib: ["esnext"], }); ``` @@ -1059,7 +1059,7 @@ An example of providing sources: ```ts const [diagnostics, emitMap] = await Deno.compile("/foo.ts", { "/foo.ts": `import * as bar from "./bar.ts";\nconsole.log(bar);\n`, - "/bar.ts": `export const bar = "bar";\n` + "/bar.ts": `export const bar = "bar";\n`, }); assert(diagnostics == null); // ensuring no diagnostics are returned @@ -1104,7 +1104,7 @@ An example of providing sources: ```ts const [diagnostics, emit] = await Deno.bundle("/foo.ts", { "/foo.ts": `import * as bar from "./bar.ts";\nconsole.log(bar);\n`, - "/bar.ts": `export const bar = "bar";\n` + "/bar.ts": `export const bar = "bar";\n`, }); assert(diagnostics == null); // ensuring no diagnostics are returned @@ -1145,7 +1145,7 @@ An example: ```ts const result = await Deno.transpileOnly({ - "/foo.ts": `enum Foo { Foo, Bar, Baz };\n` + "/foo.ts": `enum Foo { Foo, Bar, Baz };\n`, }); console.log(result["/foo.ts"].source); @@ -1512,13 +1512,13 @@ Extra steps for Windows users: The easiest way to build Deno is by using a precompiled version of V8: ``` -V8_BINARY=1 cargo build -vv +cargo build -vv ``` However if you want to build Deno and V8 from source code: ``` -cargo build -vv +V8_FROM_SOURCE=1 cargo build -vv ``` When building V8 from source, there are more dependencies: @@ -1587,8 +1587,7 @@ cargo test js_unit_tests Test `std/`: ```bash -cd std -cargo run -- -A testing/runner.ts --exclude "**/testdata" +cargo test std_tests ``` Lint the code: diff --git a/std/media_types/test.ts b/std/media_types/test.ts index 3a9a7d9fefb8f0..c3caf71df13213 100644 --- a/std/media_types/test.ts +++ b/std/media_types/test.ts @@ -8,7 +8,7 @@ import { extension, charset, extensions, - types + types, } from "./mod.ts"; test(function testLookup(): void { diff --git a/std/mime/multipart.ts b/std/mime/multipart.ts index d4bd693fd0de63..a0f40f3b09142e 100644 --- a/std/mime/multipart.ts +++ b/std/mime/multipart.ts @@ -305,7 +305,7 @@ export class MultipartReader { const ext = extname(p.fileName); const { file, filepath } = await tempFile(".", { prefix: "multipart-", - postfix: ext + postfix: ext, }); try { const size = await copyN( @@ -318,7 +318,7 @@ export class MultipartReader { filename: p.fileName, type: contentType, tempfile: filepath, - size + size, }; } catch (e) { await remove(filepath); @@ -328,7 +328,7 @@ export class MultipartReader { filename: p.fileName, type: contentType, content: buf.bytes(), - size: buf.length + size: buf.length, }; maxMemory -= n; maxValueBytes -= n; diff --git a/std/mime/multipart_test.ts b/std/mime/multipart_test.ts index 7c383d4472c853..9b96a2f4cfa47c 100644 --- a/std/mime/multipart_test.ts +++ b/std/mime/multipart_test.ts @@ -5,7 +5,7 @@ import { assert, assertEquals, assertThrows, - assertThrowsAsync + assertThrowsAsync, } from "../testing/asserts.ts"; const { test } = Deno; import * as path from "../path/mod.ts"; @@ -15,7 +15,7 @@ import { MultipartWriter, isFormFile, matchAfterPrefix, - scanUntilBoundary + scanUntilBoundary, } from "./multipart.ts"; import { StringWriter } from "../io/writers.ts"; diff --git a/std/node/_fs/_fs_appendFile.ts b/std/node/_fs/_fs_appendFile.ts index 49a4fc29f0ead5..f3b44dd7b7220f 100644 --- a/std/node/_fs/_fs_appendFile.ts +++ b/std/node/_fs/_fs_appendFile.ts @@ -55,7 +55,7 @@ export function appendFile( closeRidIfNecessary(typeof pathOrRid === "string", rid); callbackFn(); }) - .catch(err => { + .catch((err) => { closeRidIfNecessary(typeof pathOrRid === "string", rid); callbackFn(err); }); diff --git a/std/node/_fs/_fs_appendFile_test.ts b/std/node/_fs/_fs_appendFile_test.ts index 47d55274063905..ca48dc5d3b5c8f 100644 --- a/std/node/_fs/_fs_appendFile_test.ts +++ b/std/node/_fs/_fs_appendFile_test.ts @@ -15,7 +15,7 @@ test({ Error, "No callback function supplied" ); - } + }, }); test({ @@ -48,12 +48,12 @@ test({ assertThrows( () => appendFileSync("some/path", "some data", { - encoding: "made-up-encoding" + encoding: "made-up-encoding", }), Error, "Only 'utf8' encoding is currently supported" ); - } + }, }); test({ @@ -63,10 +63,10 @@ test({ const file: Deno.File = await Deno.open(tempFile, { create: true, write: true, - read: true + read: true, }); await new Promise((resolve, reject) => { - appendFile(file.rid, "hello world", err => { + appendFile(file.rid, "hello world", (err) => { if (err) reject(); else resolve(); }); @@ -82,7 +82,7 @@ test({ Deno.close(file.rid); await Deno.remove(tempFile); }); - } + }, }); test({ @@ -90,7 +90,7 @@ test({ async fn() { const openResourcesBeforeAppend: Deno.ResourceMap = Deno.resources(); await new Promise((resolve, reject) => { - appendFile("_fs_appendFile_test_file.txt", "hello world", err => { + appendFile("_fs_appendFile_test_file.txt", "hello world", (err) => { if (err) reject(err); else resolve(); }); @@ -100,13 +100,13 @@ test({ const data = await Deno.readFile("_fs_appendFile_test_file.txt"); assertEquals(decoder.decode(data), "hello world"); }) - .catch(err => { + .catch((err) => { fail("No error was expected: " + err); }) .finally(async () => { await Deno.remove("_fs_appendFile_test_file.txt"); }); - } + }, }); test({ @@ -116,7 +116,7 @@ test({ const openResourcesBeforeAppend: Deno.ResourceMap = Deno.resources(); const tempFile: string = await Deno.makeTempFile(); await new Promise((resolve, reject) => { - appendFile(tempFile, "hello world", { flag: "ax" }, err => { + appendFile(tempFile, "hello world", { flag: "ax" }, (err) => { if (err) reject(err); else resolve(); }); @@ -130,7 +130,7 @@ test({ .finally(async () => { await Deno.remove(tempFile); }); - } + }, }); test({ @@ -140,14 +140,14 @@ test({ const file: Deno.File = Deno.openSync(tempFile, { create: true, write: true, - read: true + read: true, }); appendFileSync(file.rid, "hello world"); Deno.close(file.rid); const data = Deno.readFileSync(tempFile); assertEquals(decoder.decode(data), "hello world"); Deno.removeSync(tempFile); - } + }, }); test({ @@ -159,7 +159,7 @@ test({ const data = Deno.readFileSync("_fs_appendFile_test_file_sync.txt"); assertEquals(decoder.decode(data), "hello world"); Deno.removeSync("_fs_appendFile_test_file_sync.txt"); - } + }, }); test({ @@ -175,5 +175,5 @@ test({ ); assertEquals(Deno.resources(), openResourcesBeforeAppend); Deno.removeSync(tempFile); - } + }, }); diff --git a/std/node/_fs/_fs_chmod.ts b/std/node/_fs/_fs_chmod.ts index cecb878eca3065..0eb01a8a6f4fb2 100644 --- a/std/node/_fs/_fs_chmod.ts +++ b/std/node/_fs/_fs_chmod.ts @@ -24,7 +24,7 @@ export function chmod( .then(() => { callback(); }) - .catch(err => { + .catch((err) => { callback(err); }); } diff --git a/std/node/_fs/_fs_chmod_test.ts b/std/node/_fs/_fs_chmod_test.ts index 04be00cc2369ad..1867fc564d6c43 100644 --- a/std/node/_fs/_fs_chmod_test.ts +++ b/std/node/_fs/_fs_chmod_test.ts @@ -10,7 +10,7 @@ test({ const tempFile: string = await Deno.makeTempFile(); const originalFileMode: number | null = (await Deno.lstat(tempFile)).mode; await new Promise((resolve, reject) => { - chmod(tempFile, 0o777, err => { + chmod(tempFile, 0o777, (err) => { if (err) reject(err); else resolve(); }); @@ -26,7 +26,7 @@ test({ .finally(() => { Deno.removeSync(tempFile); }); - } + }, }); test({ @@ -41,5 +41,5 @@ test({ assert(newFileMode && originalFileMode); assert(newFileMode === 0o777 && newFileMode > originalFileMode); Deno.removeSync(tempFile); - } + }, }); diff --git a/std/node/_fs/_fs_chown.ts b/std/node/_fs/_fs_chown.ts index 008b30c47e3542..94b7401d08fa8d 100644 --- a/std/node/_fs/_fs_chown.ts +++ b/std/node/_fs/_fs_chown.ts @@ -23,7 +23,7 @@ export function chown( .then(() => { callback(); }) - .catch(err => { + .catch((err) => { callback(err); }); } diff --git a/std/node/_fs/_fs_chown_test.ts b/std/node/_fs/_fs_chown_test.ts index bdf2ae09af6cfe..fd31a8c62e77c5 100644 --- a/std/node/_fs/_fs_chown_test.ts +++ b/std/node/_fs/_fs_chown_test.ts @@ -14,7 +14,7 @@ test({ const originalUserId: number | null = (await Deno.lstat(tempFile)).uid; const originalGroupId: number | null = (await Deno.lstat(tempFile)).gid; await new Promise((resolve, reject) => { - chown(tempFile, originalUserId!, originalGroupId!, err => { + chown(tempFile, originalUserId!, originalGroupId!, (err) => { if (err) reject(err); else resolve(); }); @@ -31,7 +31,7 @@ test({ .finally(() => { Deno.removeSync(tempFile); }); - } + }, }); test({ @@ -48,5 +48,5 @@ test({ assertEquals(newUserId, originalUserId); assertEquals(newGroupId, originalGroupId); Deno.removeSync(tempFile); - } + }, }); diff --git a/std/node/_fs/_fs_close.ts b/std/node/_fs/_fs_close.ts index 4ec10eefb8d63c..469bdc77b62444 100644 --- a/std/node/_fs/_fs_close.ts +++ b/std/node/_fs/_fs_close.ts @@ -14,7 +14,7 @@ export function close(fd: number, callback: CallbackWithError): void { .then(() => { callback(); }) - .catch(err => { + .catch((err) => { callback(err); }); } diff --git a/std/node/_fs/_fs_close_test.ts b/std/node/_fs/_fs_close_test.ts index 7c6dd684cd8067..8bcd662c96f7b4 100644 --- a/std/node/_fs/_fs_close_test.ts +++ b/std/node/_fs/_fs_close_test.ts @@ -11,7 +11,7 @@ test({ assert(Deno.resources()[file.rid]); await new Promise((resolve, reject) => { - close(file.rid, err => { + close(file.rid, (err) => { if (err) reject(); else resolve(); }); @@ -25,7 +25,7 @@ test({ .finally(async () => { await Deno.remove(tempFile); }); - } + }, }); test({ @@ -38,5 +38,5 @@ test({ closeSync(file.rid); assert(!Deno.resources()[file.rid]); Deno.removeSync(tempFile); - } + }, }); diff --git a/std/node/_fs/_fs_dir.ts b/std/node/_fs/_fs_dir.ts index e3830bb317eff4..c5bb368c9460cb 100644 --- a/std/node/_fs/_fs_dir.ts +++ b/std/node/_fs/_fs_dir.ts @@ -30,7 +30,7 @@ export default class Dir { try { if (this.initializationOfDirectoryFilesIsRequired()) { const denoFiles: Deno.FileInfo[] = await Deno.readdir(this.path); - this.files = denoFiles.map(file => new Dirent(file)); + this.files = denoFiles.map((file) => new Dirent(file)); } const nextFile = this.files.pop(); if (nextFile) { @@ -55,7 +55,7 @@ export default class Dir { readSync(): Dirent | null { if (this.initializationOfDirectoryFilesIsRequired()) { this.files.push( - ...Deno.readdirSync(this.path).map(file => new Dirent(file)) + ...Deno.readdirSync(this.path).map((file) => new Dirent(file)) ); } const dirent: Dirent | undefined = this.files.pop(); diff --git a/std/node/_fs/_fs_dir_test.ts b/std/node/_fs/_fs_dir_test.ts index be276887bde1bb..6ee04439134e26 100644 --- a/std/node/_fs/_fs_dir_test.ts +++ b/std/node/_fs/_fs_dir_test.ts @@ -13,21 +13,21 @@ test({ calledBack = true; }); assert(calledBack); - } + }, }); test({ name: "Closing current directory without callback returns void Promise", async fn() { await new Dir(".").close(); - } + }, }); test({ name: "Closing current directory synchronously works", fn() { new Dir(".").closeSync(); - } + }, }); test({ @@ -37,7 +37,7 @@ test({ const enc: Uint8Array = new TextEncoder().encode("std/node"); assertEquals(new Dir(enc).path, "std/node"); - } + }, }); test({ @@ -64,7 +64,7 @@ test({ } finally { Deno.removeSync(testDir); } - } + }, }); test({ @@ -103,7 +103,7 @@ test({ } finally { Deno.removeSync(testDir, { recursive: true }); } - } + }, }); test({ @@ -132,7 +132,7 @@ test({ } finally { Deno.removeSync(testDir, { recursive: true }); } - } + }, }); test({ @@ -158,5 +158,5 @@ test({ } finally { Deno.removeSync(testDir, { recursive: true }); } - } + }, }); diff --git a/std/node/_fs/_fs_dirent_test.ts b/std/node/_fs/_fs_dirent_test.ts index c9a26690fadb8e..d5307bbeabb46d 100644 --- a/std/node/_fs/_fs_dirent_test.ts +++ b/std/node/_fs/_fs_dirent_test.ts @@ -41,7 +41,7 @@ test({ fileInfo.blocks = 5; assert(new Dirent(fileInfo).isBlockDevice()); assert(!new Dirent(fileInfo).isCharacterDevice()); - } + }, }); test({ @@ -51,7 +51,7 @@ test({ fileInfo.blocks = null; assert(new Dirent(fileInfo).isCharacterDevice()); assert(!new Dirent(fileInfo).isBlockDevice()); - } + }, }); test({ @@ -64,7 +64,7 @@ test({ assert(new Dirent(fileInfo).isDirectory()); assert(!new Dirent(fileInfo).isFile()); assert(!new Dirent(fileInfo).isSymbolicLink()); - } + }, }); test({ @@ -77,7 +77,7 @@ test({ assert(!new Dirent(fileInfo).isDirectory()); assert(new Dirent(fileInfo).isFile()); assert(!new Dirent(fileInfo).isSymbolicLink()); - } + }, }); test({ @@ -90,7 +90,7 @@ test({ assert(!new Dirent(fileInfo).isDirectory()); assert(!new Dirent(fileInfo).isFile()); assert(new Dirent(fileInfo).isSymbolicLink()); - } + }, }); test({ @@ -99,7 +99,7 @@ test({ const fileInfo: FileInfoMock = new FileInfoMock(); fileInfo.name = "my_file"; assertEquals(new Dirent(fileInfo).name, "my_file"); - } + }, }); test({ @@ -120,5 +120,5 @@ test({ Error, "does not yet support" ); - } + }, }); diff --git a/std/node/_fs/_fs_readFile.ts b/std/node/_fs/_fs_readFile.ts index 05bad6f3df7bed..13e82bfe1dcc4e 100644 --- a/std/node/_fs/_fs_readFile.ts +++ b/std/node/_fs/_fs_readFile.ts @@ -3,7 +3,7 @@ import { notImplemented, intoCallbackAPIWithIntercept, - MaybeEmpty + MaybeEmpty, } from "../_utils.ts"; const { readFile: denoReadFile, readFileSync: denoReadFileSync } = Deno; diff --git a/std/node/_fs/_fs_readlink.ts b/std/node/_fs/_fs_readlink.ts index d1cb69f517b063..1fd7e3c148f8d8 100644 --- a/std/node/_fs/_fs_readlink.ts +++ b/std/node/_fs/_fs_readlink.ts @@ -2,7 +2,7 @@ import { intoCallbackAPIWithIntercept, MaybeEmpty, - notImplemented + notImplemented, } from "../_utils.ts"; const { readlink: denoReadlink, readlinkSync: denoReadlinkSync } = Deno; diff --git a/std/node/_fs/_fs_readlink_test.ts b/std/node/_fs/_fs_readlink_test.ts index 653d1a59886caf..151d3f78269c8b 100644 --- a/std/node/_fs/_fs_readlink_test.ts +++ b/std/node/_fs/_fs_readlink_test.ts @@ -25,7 +25,7 @@ test({ assertEquals(typeof data, "string"); assertEquals(data as string, oldname); - } + }, }); test({ @@ -43,7 +43,7 @@ test({ assert(data instanceof Uint8Array); assertEquals(new TextDecoder().decode(data as Uint8Array), oldname); - } + }, }); test({ @@ -53,7 +53,7 @@ test({ const data = readlinkSync(newname); assertEquals(typeof data, "string"); assertEquals(data as string, oldname); - } + }, }); test({ @@ -63,5 +63,5 @@ test({ const data = readlinkSync(newname, { encoding: "buffer" }); assert(data instanceof Uint8Array); assertEquals(new TextDecoder().decode(data as Uint8Array), oldname); - } + }, }); diff --git a/std/node/_utils.ts b/std/node/_utils.ts index f0808e82b1dd3d..ec89d11a8ee48a 100644 --- a/std/node/_utils.ts +++ b/std/node/_utils.ts @@ -17,8 +17,8 @@ export function intoCallbackAPI( ...args: any[] ): void { func(...args) - .then(value => cb && cb(null, value)) - .catch(err => cb && cb(err, null)); + .then((value) => cb && cb(null, value)) + .catch((err) => cb && cb(err, null)); } export function intoCallbackAPIWithIntercept( @@ -30,6 +30,6 @@ export function intoCallbackAPIWithIntercept( ...args: any[] ): void { func(...args) - .then(value => cb && cb(null, interceptor(value))) - .catch(err => cb && cb(err, null)); + .then((value) => cb && cb(null, interceptor(value))) + .catch((err) => cb && cb(err, null)); } diff --git a/std/node/events.ts b/std/node/events.ts index b2f1d60260dddd..aa62e4d432360a 100644 --- a/std/node/events.ts +++ b/std/node/events.ts @@ -219,7 +219,7 @@ export default class EventEmitter { eventName: string | symbol, listener: Function ): WrappedFunction { - const wrapper = function( + const wrapper = function ( this: { eventName: string | symbol; listener: Function; @@ -235,7 +235,7 @@ export default class EventEmitter { eventName: eventName, listener: listener, rawListener: (wrapper as unknown) as WrappedFunction, - context: this + context: this, }; const wrapped = (wrapper.bind( wrapperContext @@ -462,7 +462,7 @@ export function on( } // Wait until an event happens - return new Promise(function(resolve, reject) { + return new Promise(function (resolve, reject) { unconsumedPromises.push({ resolve, reject }); }); }, @@ -489,7 +489,7 @@ export function on( // eslint-disable-next-line @typescript-eslint/no-explicit-any [Symbol.asyncIterator](): any { return this; - } + }, }; emitter.on(event, eventHandler); diff --git a/std/node/events_test.ts b/std/node/events_test.ts index b0b74e499c1f14..5960290afc6317 100644 --- a/std/node/events_test.ts +++ b/std/node/events_test.ts @@ -3,7 +3,7 @@ import { assert, assertEquals, fail, - assertThrows + assertThrows, } from "../testing/asserts.ts"; import EventEmitter, { WrappedFunction, once, on } from "./events.ts"; @@ -29,7 +29,7 @@ test({ eventsFired = []; testEmitter.emit("event"); assertEquals(eventsFired, ["event"]); - } + }, }); test({ @@ -41,7 +41,7 @@ test({ testEmitter.on("removeListener", () => { eventsFired.push("removeListener"); }); - const eventFunction = function(): void { + const eventFunction = function (): void { eventsFired.push("event"); }; testEmitter.on("event", eventFunction); @@ -49,7 +49,7 @@ test({ assertEquals(eventsFired, []); testEmitter.removeListener("event", eventFunction); assertEquals(eventsFired, ["removeListener"]); - } + }, }); test({ @@ -62,7 +62,7 @@ test({ EventEmitter.defaultMaxListeners = 20; assertEquals(EventEmitter.defaultMaxListeners, 20); EventEmitter.defaultMaxListeners = 10; //reset back to original value - } + }, }); test({ @@ -73,7 +73,7 @@ test({ assertEquals(1, testEmitter.listenerCount("event")); testEmitter.on("event", shouldNeverBeEmitted); assertEquals(2, testEmitter.listenerCount("event")); - } + }, }); test({ @@ -100,7 +100,7 @@ test({ ); testEmitter.emit("event", 1, 2, 3); assertEquals(eventsFired, ["event(1)", "event(1, 2)", "event(1, 2, 3)"]); - } + }, }); test({ @@ -112,7 +112,7 @@ test({ const sym = Symbol("symbol"); testEmitter.on(sym, shouldNeverBeEmitted); assertEquals(testEmitter.eventNames(), ["event", sym]); - } + }, }); test({ @@ -122,7 +122,7 @@ test({ assertEquals(testEmitter.getMaxListeners(), 10); testEmitter.setMaxListeners(20); assertEquals(testEmitter.getMaxListeners(), 20); - } + }, }); test({ @@ -135,9 +135,9 @@ test({ testEmitter.on("event", testFunction); assertEquals(testEmitter.listeners("event"), [ shouldNeverBeEmitted, - testFunction + testFunction, ]); - } + }, }); test({ @@ -148,7 +148,7 @@ test({ assertEquals(testEmitter.listenerCount("event"), 1); testEmitter.off("event", shouldNeverBeEmitted); assertEquals(testEmitter.listenerCount("event"), 0); - } + }, }); test({ @@ -159,7 +159,7 @@ test({ .on("event", shouldNeverBeEmitted) .on("event", shouldNeverBeEmitted); assertEquals(testEmitter.listenerCount("event"), 2); - } + }, }); test({ @@ -183,7 +183,7 @@ test({ testEmitter.emit("single event"); testEmitter.emit("single event"); assertEquals(eventsFired, ["single event"]); - } + }, }); test({ @@ -203,7 +203,7 @@ test({ }); testEmitter.emit("event"); assertEquals(eventsFired, ["third", "first", "second"]); - } + }, }); test({ @@ -223,7 +223,7 @@ test({ testEmitter.emit("event"); testEmitter.emit("event"); assertEquals(eventsFired, ["third", "first", "second", "first", "second"]); - } + }, }); test({ @@ -242,7 +242,7 @@ test({ assertEquals(testEmitter.listenerCount("event"), 0); assertEquals(testEmitter.listenerCount("other event"), 0); - } + }, }); test({ @@ -265,7 +265,7 @@ test({ assertEquals(testEmitter.listenerCount("event"), 0); assertEquals(testEmitter.listenerCount("other event"), 0); - } + }, }); test({ @@ -284,7 +284,7 @@ test({ testEmitter.removeListener("non-existant event", madeUpEvent); assertEquals(testEmitter.listenerCount("event"), 1); - } + }, }); test({ @@ -307,7 +307,7 @@ test({ eventsProcessed = []; testEmitter.emit("event"); assertEquals(eventsProcessed, ["A"]); - } + }, }); test({ @@ -330,7 +330,7 @@ test({ (rawListenersForOnceEvent[0] as WrappedFunction).listener, listenerB ); - } + }, }); test({ @@ -353,7 +353,7 @@ test({ wrappedFn(); // executing the wrapped listener function will remove it from the event assertEquals(eventsProcessed, ["A"]); assertEquals(testEmitter.listeners("once-event").length, 0); - } + }, }); test({ @@ -366,7 +366,7 @@ test({ // eslint-disable-next-line @typescript-eslint/no-explicit-any const valueArr: any[] = await once(ee, "event"); assertEquals(valueArr, [42, "foo"]); - } + }, }); test({ @@ -380,7 +380,7 @@ test({ // eslint-disable-next-line @typescript-eslint/no-explicit-any const eventObj: any[] = await once(et, "event"); assert(!eventObj[0].isTrusted); - } + }, }); test({ @@ -402,7 +402,7 @@ test({ Error, "must be 'an integer'" ); - } + }, }); test({ @@ -440,7 +440,7 @@ test({ }); ee.emit("error"); assertEquals(events, ["errorMonitor event", "error"]); - } + }, }); test({ @@ -468,7 +468,7 @@ test({ } assertEquals(ee.listenerCount("foo"), 0); assertEquals(ee.listenerCount("error"), 0); - } + }, }); test({ @@ -493,7 +493,7 @@ test({ assertEquals(err, _err); } assertEquals(thrown, true); - } + }, }); test({ @@ -522,7 +522,7 @@ test({ assertEquals(thrown, true); assertEquals(ee.listenerCount("foo"), 0); assertEquals(ee.listenerCount("error"), 0); - } + }, }); test({ @@ -548,7 +548,7 @@ test({ assertEquals(ee.listenerCount("foo"), 0); assertEquals(ee.listenerCount("error"), 0); - } + }, }); test({ @@ -557,7 +557,7 @@ test({ const ee = new EventEmitter(); const iterable = on(ee, "foo"); - setTimeout(function() { + setTimeout(function () { ee.emit("foo", "bar"); ee.emit("foo", 42); iterable.return(); @@ -566,29 +566,29 @@ test({ const results = await Promise.all([ iterable.next(), iterable.next(), - iterable.next() + iterable.next(), ]); assertEquals(results, [ { value: ["bar"], - done: false + done: false, }, { value: [42], - done: false + done: false, }, { value: undefined, - done: true - } + done: true, + }, ]); assertEquals(await iterable.next(), { value: undefined, - done: true + done: true, }); - } + }, }); test({ @@ -620,5 +620,5 @@ test({ assertEquals(expected.length, 0); assertEquals(ee.listenerCount("foo"), 0); assertEquals(ee.listenerCount("error"), 0); - } + }, }); diff --git a/std/node/fs.ts b/std/node/fs.ts index 9135441bb25640..0681ee5a1cf205 100755 --- a/std/node/fs.ts +++ b/std/node/fs.ts @@ -24,5 +24,5 @@ export { readFile, readFileSync, readlink, - readlinkSync + readlinkSync, }; diff --git a/std/node/module.ts b/std/node/module.ts index 21992f743110e1..522eaec7e741e3 100644 --- a/std/node/module.ts +++ b/std/node/module.ts @@ -108,7 +108,7 @@ class Module { // Proxy related code removed. static wrapper = [ "(function (exports, require, module, __filename, __dirname) { ", - "\n});" + "\n});", ]; // Loads a module at the given file path. Returns that module's @@ -235,7 +235,9 @@ class Module { const lookupPaths = Module._resolveLookupPaths(request, fakeParent); for (let j = 0; j < lookupPaths!.length; j++) { - if (!paths.includes(lookupPaths![j])) paths.push(lookupPaths![j]); + if (!paths.includes(lookupPaths![j])) { + paths.push(lookupPaths![j]); + } } } } @@ -357,8 +359,9 @@ class Module { const cachedModule = Module._cache[filename]; if (cachedModule !== undefined) { updateChildren(parent, cachedModule, true); - if (!cachedModule.loaded) + if (!cachedModule.loaded) { return getExportsForCircularRequire(cachedModule); + } return cachedModule.exports; } delete relativeResolveCache[relResolveCacheIdentifier]; @@ -370,8 +373,9 @@ class Module { const cachedModule = Module._cache[filename]; if (cachedModule !== undefined) { updateChildren(parent, cachedModule, true); - if (!cachedModule.loaded) + if (!cachedModule.loaded) { return getExportsForCircularRequire(cachedModule); + } return cachedModule.exports; } @@ -436,8 +440,9 @@ class Module { if ( from.charCodeAt(from.length - 1) === CHAR_BACKWARD_SLASH && from.charCodeAt(from.length - 2) === CHAR_COLON - ) + ) { return [from + "node_modules"]; + } const paths = []; for (let i = from.length - 1, p = 0, last = from.length; i >= 0; --i) { @@ -663,7 +668,7 @@ function readPackage(requestPath: string): PackageInfo | null { name: parsed.name, main: parsed.main, exports: parsed.exports, - type: parsed.type + type: parsed.type, }; packageJsonCache.set(jsonPath, filtered); return filtered; @@ -685,11 +690,12 @@ function readPackageScope( checkPath = checkPath.slice(0, separatorIndex); if (checkPath.endsWith(path.sep + "node_modules")) return false; const pjson = readPackage(checkPath); - if (pjson) + if (pjson) { return { path: checkPath, - data: pjson + data: pjson, }; + } } return false; } @@ -822,11 +828,13 @@ function applyExports(basePath: string, expansion: string): string { const mappingKey = `.${expansion}`; let pkgExports = readPackageExports(basePath); - if (pkgExports === undefined || pkgExports === null) + if (pkgExports === undefined || pkgExports === null) { return path.resolve(basePath, mappingKey); + } - if (isConditionalDotExportSugar(pkgExports, basePath)) + if (isConditionalDotExportSugar(pkgExports, basePath)) { pkgExports = { ".": pkgExports }; + } if (typeof pkgExports === "object") { if (pkgExports.hasOwnProperty(mappingKey)) { @@ -1005,11 +1013,12 @@ const CircularRequirePrototypeWarningProxy = new Proxy( }, getOwnPropertyDescriptor(target, prop): PropertyDescriptor | undefined { - if (target.hasOwnProperty(prop)) + if (target.hasOwnProperty(prop)) { return Object.getOwnPropertyDescriptor(target, prop); + } emitCircularRequireWarning(prop); return undefined; - } + }, } ); @@ -1230,16 +1239,21 @@ function pathToFileURL(filepath: string): URL { (filePathLast === CHAR_FORWARD_SLASH || (isWindows && filePathLast === CHAR_BACKWARD_SLASH)) && resolved[resolved.length - 1] !== path.sep - ) + ) { resolved += "/"; + } const outURL = new URL("file://"); if (resolved.includes("%")) resolved = resolved.replace(percentRegEx, "%25"); // In posix, "/" is a valid character in paths - if (!isWindows && resolved.includes("\\")) + if (!isWindows && resolved.includes("\\")) { resolved = resolved.replace(backslashRegEx, "%5C"); - if (resolved.includes("\n")) resolved = resolved.replace(newlineRegEx, "%0A"); - if (resolved.includes("\r")) + } + if (resolved.includes("\n")) { + resolved = resolved.replace(newlineRegEx, "%0A"); + } + if (resolved.includes("\r")) { resolved = resolved.replace(carriageReturnRegEx, "%0D"); + } if (resolved.includes("\t")) resolved = resolved.replace(tabRegEx, "%09"); outURL.pathname = resolved; return outURL; diff --git a/std/node/os.ts b/std/node/os.ts index 4bc70d1ffa4a01..7c61e910b1f793 100644 --- a/std/node/os.ts +++ b/std/node/os.ts @@ -219,7 +219,7 @@ export const constants = { signals: Deno.Signal, priority: { // see https://nodejs.org/docs/latest-v12.x/api/os.html#os_priority_constants - } + }, }; export const EOL = Deno.build.os == "win" ? fsEOL.CRLF : fsEOL.LF; diff --git a/std/node/os_test.ts b/std/node/os_test.ts index a73a2d4e99d2e4..f0b9ca79d425ca 100644 --- a/std/node/os_test.ts +++ b/std/node/os_test.ts @@ -6,42 +6,42 @@ test({ name: "build architecture is a string", fn() { assertEquals(typeof os.arch(), "string"); - } + }, }); test({ name: "home directory is a string", fn() { assertEquals(typeof os.homedir(), "string"); - } + }, }); test({ name: "tmp directory is a string", fn() { assertEquals(typeof os.tmpdir(), "string"); - } + }, }); test({ name: "hostname is a string", fn() { assertEquals(typeof os.hostname(), "string"); - } + }, }); test({ name: "platform is a string", fn() { assertEquals(typeof os.platform(), "string"); - } + }, }); test({ name: "release is a string", fn() { assertEquals(typeof os.release(), "string"); - } + }, }); test({ @@ -61,7 +61,7 @@ test({ Error, "must be >= -2147483648 && <= 2147483647" ); - } + }, }); test({ @@ -81,7 +81,7 @@ test({ Error, "pid must be >= -2147483648 && <= 2147483647" ); - } + }, }); test({ @@ -115,7 +115,7 @@ test({ Error, "priority must be >= -20 && <= 19" ); - } + }, }); test({ @@ -150,7 +150,7 @@ test({ Error, "priority must be >= -20 && <= 19" ); - } + }, }); test({ @@ -160,21 +160,21 @@ test({ assertEquals(os.constants.signals.SIGKILL, Deno.Signal.SIGKILL); assertEquals(os.constants.signals.SIGCONT, Deno.Signal.SIGCONT); assertEquals(os.constants.signals.SIGXFSZ, Deno.Signal.SIGXFSZ); - } + }, }); test({ name: "EOL is as expected", fn() { assert(os.EOL == "\r\n" || os.EOL == "\n"); - } + }, }); test({ name: "Endianness is determined", fn() { assert(["LE", "BE"].includes(os.endianness())); - } + }, }); test({ @@ -185,7 +185,7 @@ test({ assertEquals(typeof result[0], "number"); assertEquals(typeof result[1], "number"); assertEquals(typeof result[2], "number"); - } + }, }); test({ @@ -196,7 +196,7 @@ test({ assertEquals(`${os.homedir}`, os.homedir()); assertEquals(`${os.hostname}`, os.hostname()); assertEquals(`${os.platform}`, os.platform()); - } + }, }); test({ @@ -265,5 +265,5 @@ test({ Error, "Not implemented" ); - } + }, }); diff --git a/std/node/process.ts b/std/node/process.ts index 35de23b8802f2f..89d383e8ef1fcb 100644 --- a/std/node/process.ts +++ b/std/node/process.ts @@ -4,7 +4,7 @@ const version = `v${Deno.version.deno}`; const versions = { node: Deno.version.deno, - ...Deno.version + ...Deno.version, }; const osToPlatform = (os: Deno.OperatingSystem): string => @@ -38,5 +38,5 @@ export const process = { get argv(): string[] { // Deno.execPath() also requires --allow-env return [Deno.execPath(), ...Deno.args]; - } + }, }; diff --git a/std/node/process_test.ts b/std/node/process_test.ts index f44143acbc3f35..b9d5388eace1d9 100644 --- a/std/node/process_test.ts +++ b/std/node/process_test.ts @@ -14,7 +14,7 @@ test({ assert(process.cwd().match(/\Wnode$/)); process.chdir(".."); assert(process.cwd().match(/\Wstd$/)); - } + }, }); test({ @@ -30,7 +30,7 @@ test({ // "The system cannot find the file specified. (os error 2)" so "file" is // the only common string here. ); - } + }, }); test({ @@ -40,14 +40,14 @@ test({ assertEquals(typeof process.version, "string"); assertEquals(typeof process.versions, "object"); assertEquals(typeof process.versions.node, "string"); - } + }, }); test({ name: "process.platform", fn() { assertEquals(typeof process.platform, "string"); - } + }, }); test({ @@ -56,7 +56,7 @@ test({ assertEquals(typeof process.arch, "string"); // TODO(rsp): make sure that the arch strings should be the same in Node and Deno: assertEquals(process.arch, Deno.build.arch); - } + }, }); test({ @@ -64,7 +64,7 @@ test({ fn() { assertEquals(typeof process.pid, "number"); assertEquals(process.pid, Deno.pid); - } + }, }); test({ @@ -78,7 +78,7 @@ test({ Error, "implemented" ); - } + }, }); test({ @@ -90,12 +90,12 @@ test({ "deno included in the file name of argv[0]" ); // we cannot test for anything else (we see test runner arguments here) - } + }, }); test({ name: "process.env", fn() { assertEquals(typeof process.env.PATH, "string"); - } + }, }); diff --git a/std/node/querystring.ts b/std/node/querystring.ts index fc5a00a13e516c..427183bf02770b 100644 --- a/std/node/querystring.ts +++ b/std/node/querystring.ts @@ -13,7 +13,7 @@ export function parse( ): { [key: string]: string[] | string } { const entries = str .split(sep) - .map(entry => entry.split(eq).map(decodeURIComponent)); + .map((entry) => entry.split(eq).map(decodeURIComponent)); const final: { [key: string]: string[] | string } = {}; let i = 0; diff --git a/std/node/querystring_test.ts b/std/node/querystring_test.ts index d8cb1ec35a343f..0a37eee6b098b5 100644 --- a/std/node/querystring_test.ts +++ b/std/node/querystring_test.ts @@ -10,11 +10,11 @@ test({ a: "hello", b: 5, c: true, - d: ["foo", "bar"] + d: ["foo", "bar"], }), "a=hello&b=5&c=true&d=foo&d=bar" ); - } + }, }); test({ @@ -24,7 +24,7 @@ test({ a: "hello", b: "5", c: "true", - d: ["foo", "bar"] + d: ["foo", "bar"], }); - } + }, }); diff --git a/std/node/tests/cjs/cjs_builtin.js b/std/node/tests/cjs/cjs_builtin.js index 3d182981aa2bf9..d821d2558b6737 100644 --- a/std/node/tests/cjs/cjs_builtin.js +++ b/std/node/tests/cjs/cjs_builtin.js @@ -6,5 +6,5 @@ const path = require("path"); module.exports = { readFileSync: fs.readFileSync, isNull: util.isNull, - extname: path.extname + extname: path.extname, }; diff --git a/std/node/tests/node_modules/left-pad/index.js b/std/node/tests/node_modules/left-pad/index.js index e90aec35d979c4..8501bca1b6632e 100644 --- a/std/node/tests/node_modules/left-pad/index.js +++ b/std/node/tests/node_modules/left-pad/index.js @@ -3,37 +3,37 @@ * and/or modify it under the terms of the Do What The Fuck You Want * To Public License, Version 2, as published by Sam Hocevar. See * http://www.wtfpl.net/ for more details. */ -'use strict'; +"use strict"; module.exports = leftPad; var cache = [ - '', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ' + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " ]; -function leftPad (str, len, ch) { +function leftPad(str, len, ch) { // convert `str` to a `string` - str = str + ''; + str = str + ""; // `len` is the `pad`'s length now len = len - str.length; // doesn't need to pad if (len <= 0) return str; // `ch` defaults to `' '` - if (!ch && ch !== 0) ch = ' '; + if (!ch && ch !== 0) ch = " "; // convert `ch` to a `string` cuz it could be a number - ch = ch + ''; + ch = ch + ""; // cache common use cases - if (ch === ' ' && len < 10) return cache[len] + str; + if (ch === " " && len < 10) return cache[len] + str; // `pad` starts with an empty string - var pad = ''; + var pad = ""; // loop while (true) { // add `ch` to `pad` if `len` is odd diff --git a/std/node/util_test.ts b/std/node/util_test.ts index 751dba57e77e5e..05cec15df6710a 100644 --- a/std/node/util_test.ts +++ b/std/node/util_test.ts @@ -11,7 +11,7 @@ test({ assert(util.isBoolean(false)); assert(!util.isBoolean("deno")); assert(!util.isBoolean("true")); - } + }, }); test({ @@ -22,7 +22,7 @@ test({ assert(!util.isNull(n)); assert(!util.isNull(0)); assert(!util.isNull({})); - } + }, }); test({ @@ -33,7 +33,7 @@ test({ assert(util.isNullOrUndefined(n)); assert(!util.isNullOrUndefined({})); assert(!util.isNullOrUndefined("undefined")); - } + }, }); test({ @@ -43,7 +43,7 @@ test({ assert(util.isNumber(new Number(666))); assert(!util.isNumber("999")); assert(!util.isNumber(null)); - } + }, }); test({ @@ -52,7 +52,7 @@ test({ assert(util.isString("deno")); assert(util.isString(new String("DIO"))); assert(!util.isString(1337)); - } + }, }); test({ @@ -61,7 +61,7 @@ test({ assert(util.isSymbol(Symbol())); assert(!util.isSymbol(123)); assert(!util.isSymbol("string")); - } + }, }); test({ @@ -71,7 +71,7 @@ test({ assert(util.isUndefined(t)); assert(!util.isUndefined("undefined")); assert(!util.isUndefined({})); - } + }, }); test({ @@ -81,7 +81,7 @@ test({ assert(util.isObject(dio)); assert(util.isObject(new RegExp(/Toki Wo Tomare/))); assert(!util.isObject("Jotaro")); - } + }, }); test({ @@ -93,17 +93,17 @@ test({ assert(util.isError(java)); assert(util.isError(nodejs)); assert(!util.isError(deno)); - } + }, }); test({ name: "[util] isFunction", fn() { - const f = function(): void {}; + const f = function (): void {}; assert(util.isFunction(f)); assert(!util.isFunction({})); assert(!util.isFunction(new RegExp(/f/))); - } + }, }); test({ @@ -113,7 +113,7 @@ test({ assert(util.isRegExp(/fuManchu/)); assert(!util.isRegExp({ evil: "eye" })); assert(!util.isRegExp(null)); - } + }, }); test({ @@ -122,5 +122,5 @@ test({ assert(util.isArray([])); assert(!util.isArray({ yaNo: "array" })); assert(!util.isArray(null)); - } + }, }); diff --git a/std/path/extname_test.ts b/std/path/extname_test.ts index d9e14bb48f7b73..16ca7a2f9c6bde 100644 --- a/std/path/extname_test.ts +++ b/std/path/extname_test.ts @@ -49,11 +49,11 @@ const pairs = [ ["file/", ""], ["file//", ""], ["file./", "."], - ["file.//", "."] + ["file.//", "."], ]; test(function extname() { - pairs.forEach(function(p) { + pairs.forEach(function (p) { const input = p[0]; const expected = p[1]; assertEquals(expected, path.posix.extname(input)); @@ -71,7 +71,7 @@ test(function extname() { }); test(function extnameWin32() { - pairs.forEach(function(p) { + pairs.forEach(function (p) { const input = p[0].replace(slashRE, "\\"); const expected = p[1]; assertEquals(expected, path.win32.extname(input)); diff --git a/std/path/glob.ts b/std/path/glob.ts index 8eb106b251dab3..a11865c26efaf0 100644 --- a/std/path/glob.ts +++ b/std/path/glob.ts @@ -44,7 +44,7 @@ export function globToRegExp( extended, globstar, strict: false, - filepath: true + filepath: true, }); assert(result.path != null); return result.path.regex; diff --git a/std/path/glob_test.ts b/std/path/glob_test.ts index d8da1a47b62463..8c49adecae2806 100644 --- a/std/path/glob_test.ts +++ b/std/path/glob_test.ts @@ -32,17 +32,17 @@ test({ ); assertEquals( globToRegExp(join("unicorn", "!(sleeping)", "bathroom.ts"), { - extended: true + extended: true, }).test(join("unicorn", "flying", "bathroom.ts")), true ); assertEquals( globToRegExp(join("unicorn", "(!sleeping)", "bathroom.ts"), { - extended: true + extended: true, }).test(join("unicorn", "sleeping", "bathroom.ts")), false ); - } + }, }); testWalk( @@ -55,7 +55,7 @@ testWalk( }, async function globInWalkWildcard(): Promise { const arr = await walkArray(".", { - match: [globToRegExp(join("*", "*.ts"))] + match: [globToRegExp(join("*", "*.ts"))], }); assertEquals(arr.length, 2); assertEquals(arr[0], "a/x.ts"); @@ -74,9 +74,9 @@ testWalk( match: [ globToRegExp(join("a", "**", "*.ts"), { flags: "g", - globstar: true - }) - ] + globstar: true, + }), + ], }); assertEquals(arr.length, 1); assertEquals(arr[0], "a/yo/x.ts"); @@ -98,9 +98,9 @@ testWalk( match: [ globToRegExp(join("a", "+(raptor|deno)", "*.ts"), { flags: "g", - extended: true - }) - ] + extended: true, + }), + ], }); assertEquals(arr.length, 2); assertEquals(arr[0], "a/deno/x.ts"); @@ -116,7 +116,7 @@ testWalk( }, async function globInWalkWildcardExtension(): Promise { const arr = await walkArray(".", { - match: [globToRegExp("x.*", { flags: "g", globstar: true })] + match: [globToRegExp("x.*", { flags: "g", globstar: true })], }); assertEquals(arr.length, 2); assertEquals(arr[0], "x.js"); @@ -236,7 +236,7 @@ test({ assert(!isGlob("\\a/b/c/\\[a-z\\].js")); assert(!isGlob("abc/\\(aaa|bbb).js")); assert(!isGlob("abc/\\?.js")); - } + }, }); test(function normalizeGlobGlobstar(): void { diff --git a/std/path/globrex.ts b/std/path/globrex.ts index 695294834c6dbe..0fe833a52ed10c 100644 --- a/std/path/globrex.ts +++ b/std/path/globrex.ts @@ -54,7 +54,7 @@ export function globrex( globstar = false, strict = false, filepath = false, - flags = "" + flags = "", }: GlobrexOptions = {} ): GlobrexResult { const sepPattern = new RegExp(`^${SEP}${strict ? "" : "+"}$`); @@ -319,7 +319,7 @@ export function globrex( globstar: new RegExp( !flags.includes("g") ? `^${GLOBSTAR_SEGMENT}$` : GLOBSTAR_SEGMENT, flags - ) + ), }; } diff --git a/std/path/globrex_test.ts b/std/path/globrex_test.ts index 29f039837d84c2..27541a5c8c6904 100644 --- a/std/path/globrex_test.ts +++ b/std/path/globrex_test.ts @@ -34,7 +34,7 @@ test({ t.equal(typeof globrex, "function", "constructor is a typeof function"); t.equal(res instanceof Object, true, "returns object"); t.equal(res.regex.toString(), "/^.*\\.js$/", "returns regex object"); - } + }, }); test({ @@ -64,7 +64,7 @@ test({ true, "match zero characters" ); - } + }, }); test({ @@ -72,7 +72,7 @@ test({ fn(): void { t.equal( match("*.min.js", "http://example.com/jquery.min.js", { - globstar: false + globstar: false, }), true, "complex match" @@ -84,7 +84,7 @@ test({ ); t.equal( match("*/js/*.js", "http://example.com/js/jquery.min.js", { - globstar: false + globstar: false, }), true, "complex match" @@ -171,11 +171,11 @@ test({ t.equal(match("/js*jq*.js", "http://example.com/js/jquery.min.js"), false); t.equal( match("/js*jq*.js", "http://example.com/js/jquery.min.js", { - flags: "g" + flags: "g", }), true ); - } + }, }); test({ @@ -215,7 +215,7 @@ test({ tester(true); tester(false); - } + }, }); test({ @@ -246,7 +246,7 @@ test({ tester(true); tester(false); - } + }, }); test({ @@ -304,7 +304,7 @@ test({ match("[[:digit:]b]/bar.txt", "a/bar.txt", { extended: true }), false ); - } + }, }); test({ @@ -320,7 +320,7 @@ test({ match("foo{bar,baaz}", "foobaaz", { extended: true, globstar, - flag: "g" + flag: "g", }), true ); @@ -328,7 +328,7 @@ test({ match("foo{bar,baaz}", "foobar", { extended: true, globstar, - flag: "g" + flag: "g", }), true ); @@ -336,7 +336,7 @@ test({ match("foo{bar,baaz}", "foobuzz", { extended: true, globstar, - flag: "g" + flag: "g", }), false ); @@ -344,7 +344,7 @@ test({ match("foo{bar,b*z}", "foobuzz", { extended: true, globstar, - flag: "g" + flag: "g", }), true ); @@ -352,7 +352,7 @@ test({ tester(true); tester(false); - } + }, }); test({ @@ -444,7 +444,7 @@ test({ tester(true); tester(false); - } + }, }); test({ @@ -471,7 +471,7 @@ test({ match("http://foo.com/**", "http://foo.com/bar/baz/jquery.min.js", { extended: true, globstar, - flags: "g" + flags: "g", }), true ); @@ -479,7 +479,7 @@ test({ tester(true); tester(false); - } + }, }); test({ @@ -496,7 +496,7 @@ test({ tester(true); tester(false); - } + }, }); test({ @@ -574,25 +574,25 @@ test({ t.equal( match("http://foo.com/*", "http://foo.com/bar/baz/jquery.min.js", { extended: true, - globstar: true + globstar: true, }), false ); t.equal( match("http://foo.com/*", "http://foo.com/bar/baz/jquery.min.js", { - globstar: true + globstar: true, }), false ); t.equal( match("http://foo.com/*", "http://foo.com/bar/baz/jquery.min.js", { - globstar: false + globstar: false, }), true ); t.equal( match("http://foo.com/**", "http://foo.com/bar/baz/jquery.min.js", { - globstar: true + globstar: true, }), true ); @@ -636,7 +636,7 @@ test({ ), false ); - } + }, }); test({ @@ -689,7 +689,7 @@ test({ match("?(ba[!zr]|qux)baz.txt", "bazbaz.txt", { extended: true }), false ); - } + }, }); test({ @@ -715,18 +715,18 @@ test({ t.equal( match("*(foo|bar)/**/*.txt", "foo/hello/world/bar.txt", { extended: true, - globstar: true + globstar: true, }), true ); t.equal( match("*(foo|bar)/**/*.txt", "foo/world/bar.txt", { extended: true, - globstar: true + globstar: true, }), true ); - } + }, }); test({ @@ -736,7 +736,7 @@ test({ t.equal(match("+foo.txt", "+foo.txt", { extended: true }), true); t.equal(match("+(foo).txt", ".txt", { extended: true }), false); t.equal(match("+(foo|bar).txt", "foobar.txt", { extended: true }), true); - } + }, }); test({ @@ -757,7 +757,7 @@ test({ match("@(foo|baz)bar.txt", "toofoobar.txt", { extended: true }), false ); - } + }, }); test({ @@ -774,7 +774,7 @@ test({ match("!({foo,bar})baz.txt", "foobaz.txt", { extended: true }), false ); - } + }, }); test({ @@ -783,7 +783,7 @@ test({ t.equal(match("foo//bar.txt", "foo/bar.txt"), true); t.equal(match("foo///bar.txt", "foo/bar.txt"), true); t.equal(match("foo///bar.txt", "foo/bar.txt", { strict: true }), false); - } + }, }); test({ @@ -791,7 +791,7 @@ test({ fn(): void { t.equal( match("**/*/?yfile.{md,js,txt}", "foo/bar/baz/myfile.md", { - extended: true + extended: true, }), true ); @@ -823,5 +823,5 @@ test({ match("[[:digit:]_.]/file.js", "z/file.js", { extended: true }), false ); - } + }, }); diff --git a/std/path/join_test.ts b/std/path/join_test.ts index a73cf36794edd6..d9a38fb8219a4b 100644 --- a/std/path/join_test.ts +++ b/std/path/join_test.ts @@ -53,7 +53,7 @@ const joinTests = [["/", "//foo"], "/foo"], [["/", "", "/foo"], "/foo"], [["", "/", "foo"], "/foo"], - [["", "/", "/foo"], "/foo"] + [["", "/", "/foo"], "/foo"], ]; // Windows-specific join tests @@ -103,11 +103,11 @@ const windowsJoinTests = [ [["c:.", "/"], "c:.\\"], [["c:.", "file"], "c:file"], [["c:", "/"], "c:\\"], - [["c:", "file"], "c:\\file"] + [["c:", "file"], "c:\\file"], ]; test(function join() { - joinTests.forEach(function(p) { + joinTests.forEach(function (p) { const _p = p[0] as string[]; const actual = path.posix.join.apply(null, _p); assertEquals(actual, p[1]); @@ -115,12 +115,12 @@ test(function join() { }); test(function joinWin32() { - joinTests.forEach(function(p) { + joinTests.forEach(function (p) { const _p = p[0] as string[]; const actual = path.win32.join.apply(null, _p).replace(backslashRE, "/"); assertEquals(actual, p[1]); }); - windowsJoinTests.forEach(function(p) { + windowsJoinTests.forEach(function (p) { const _p = p[0] as string[]; const actual = path.win32.join.apply(null, _p); assertEquals(actual, p[1]); diff --git a/std/path/parse_format_test.ts b/std/path/parse_format_test.ts index 0a7e83bbad4659..60be3c9a1d2797 100644 --- a/std/path/parse_format_test.ts +++ b/std/path/parse_format_test.ts @@ -24,15 +24,14 @@ const winPaths = [ ["C:\\", "C:\\"], ["C:\\abc", "C:\\"], ["", ""], - // unc ["\\\\server\\share\\file_path", "\\\\server\\share\\"], [ "\\\\server two\\shared folder\\file path.zip", - "\\\\server two\\shared folder\\" + "\\\\server two\\shared folder\\", ], ["\\\\teela\\admin$\\system32", "\\\\teela\\admin$\\"], - ["\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\"] + ["\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\"], ]; const winSpecialCaseParseTests = [["/foo/bar", { root: "/" }]]; @@ -44,7 +43,7 @@ const winSpecialCaseFormatTests = [ [{ name: "index", ext: ".html" }, "index.html"], [{ dir: "some\\dir", name: "index", ext: ".html" }, "some\\dir\\index.html"], [{ root: "C:\\", name: "index", ext: ".html" }, "C:\\index.html"], - [{}, ""] + [{}, ""], ]; const unixPaths = [ @@ -68,7 +67,7 @@ const unixPaths = [ ["/.", "/"], ["/.foo", "/"], ["/.foo.bar", "/"], - ["/foo/bar.baz", "/"] + ["/foo/bar.baz", "/"], ]; const unixSpecialCaseFormatTests = [ @@ -78,11 +77,11 @@ const unixSpecialCaseFormatTests = [ [{ name: "index", ext: ".html" }, "index.html"], [{ dir: "some/dir", name: "index", ext: ".html" }, "some/dir/index.html"], [{ root: "/", name: "index", ext: ".html" }, "/index.html"], - [{}, ""] + [{}, ""], ]; function checkParseFormat(path: any, paths: any): void { - paths.forEach(function(p: Array>) { + paths.forEach(function (p: Array>) { const element = p[0]; const output = path.parse(element); assertEquals(typeof output.root, "string"); @@ -98,18 +97,18 @@ function checkParseFormat(path: any, paths: any): void { } function checkSpecialCaseParseFormat(path: any, testCases: any): void { - testCases.forEach(function(testCase: Array>) { + testCases.forEach(function (testCase: Array>) { const element = testCase[0]; const expect = testCase[1]; const output = path.parse(element); - Object.keys(expect).forEach(function(key) { + Object.keys(expect).forEach(function (key) { assertEquals(output[key], expect[key]); }); }); } function checkFormat(path: any, testCases: unknown[][]): void { - testCases.forEach(function(testCase) { + testCases.forEach(function (testCase) { assertEquals(path.format(testCase[0]), testCase[1]); }); } @@ -138,7 +137,7 @@ const windowsTrailingTests = [ ["\\\\", { root: "\\", dir: "\\", base: "", ext: "", name: "" }], [ "c:\\foo\\\\\\", - { root: "c:\\", dir: "c:\\", base: "foo", ext: "", name: "foo" } + { root: "c:\\", dir: "c:\\", base: "foo", ext: "", name: "foo" }, ], [ "D:\\foo\\\\\\bar.baz", @@ -147,9 +146,9 @@ const windowsTrailingTests = [ dir: "D:\\foo\\\\", base: "bar.baz", ext: ".baz", - name: "bar" - } - ] + name: "bar", + }, + ], ]; const posixTrailingTests = [ @@ -159,12 +158,12 @@ const posixTrailingTests = [ ["/foo///", { root: "/", dir: "/", base: "foo", ext: "", name: "foo" }], [ "/foo///bar.baz", - { root: "/", dir: "/foo//", base: "bar.baz", ext: ".baz", name: "bar" } - ] + { root: "/", dir: "/foo//", base: "bar.baz", ext: ".baz", name: "bar" }, + ], ]; test(function parseTrailingWin32() { - windowsTrailingTests.forEach(function(p) { + windowsTrailingTests.forEach(function (p) { const actual = path.win32.parse(p[0] as string); const expected = p[1]; assertEquals(actual, expected); @@ -172,7 +171,7 @@ test(function parseTrailingWin32() { }); test(function parseTrailing() { - posixTrailingTests.forEach(function(p) { + posixTrailingTests.forEach(function (p) { const actual = path.posix.parse(p[0] as string); const expected = p[1]; assertEquals(actual, expected); diff --git a/std/path/posix.ts b/std/path/posix.ts index 4377fd54276964..ba4cf74992d5f7 100644 --- a/std/path/posix.ts +++ b/std/path/posix.ts @@ -9,7 +9,7 @@ import { assertPath, normalizeString, isPosixPathSeparator, - _format + _format, } from "./utils.ts"; export const sep = "/"; @@ -205,8 +205,9 @@ export function dirname(path: string): string { } export function basename(path: string, ext = ""): string { - if (ext !== undefined && typeof ext !== "string") + if (ext !== undefined && typeof ext !== "string") { throw new TypeError('"ext" argument must be a string'); + } assertPath(path); let start = 0; diff --git a/std/path/relative_test.ts b/std/path/relative_test.ts index 3fe5aab4b7e0dc..af5896236219fd 100644 --- a/std/path/relative_test.ts +++ b/std/path/relative_test.ts @@ -6,58 +6,52 @@ import { assertEquals } from "../testing/asserts.ts"; import * as path from "./mod.ts"; const relativeTests = { - win32: - // arguments result - [ - ["c:/blah\\blah", "d:/games", "d:\\games"], - ["c:/aaaa/bbbb", "c:/aaaa", ".."], - ["c:/aaaa/bbbb", "c:/cccc", "..\\..\\cccc"], - ["c:/aaaa/bbbb", "c:/aaaa/bbbb", ""], - ["c:/aaaa/bbbb", "c:/aaaa/cccc", "..\\cccc"], - ["c:/aaaa/", "c:/aaaa/cccc", "cccc"], - ["c:/", "c:\\aaaa\\bbbb", "aaaa\\bbbb"], - ["c:/aaaa/bbbb", "d:\\", "d:\\"], - ["c:/AaAa/bbbb", "c:/aaaa/bbbb", ""], - ["c:/aaaaa/", "c:/aaaa/cccc", "..\\aaaa\\cccc"], - ["C:\\foo\\bar\\baz\\quux", "C:\\", "..\\..\\..\\.."], - [ - "C:\\foo\\test", - "C:\\foo\\test\\bar\\package.json", - "bar\\package.json" - ], - ["C:\\foo\\bar\\baz-quux", "C:\\foo\\bar\\baz", "..\\baz"], - ["C:\\foo\\bar\\baz", "C:\\foo\\bar\\baz-quux", "..\\baz-quux"], - ["\\\\foo\\bar", "\\\\foo\\bar\\baz", "baz"], - ["\\\\foo\\bar\\baz", "\\\\foo\\bar", ".."], - ["\\\\foo\\bar\\baz-quux", "\\\\foo\\bar\\baz", "..\\baz"], - ["\\\\foo\\bar\\baz", "\\\\foo\\bar\\baz-quux", "..\\baz-quux"], - ["C:\\baz-quux", "C:\\baz", "..\\baz"], - ["C:\\baz", "C:\\baz-quux", "..\\baz-quux"], - ["\\\\foo\\baz-quux", "\\\\foo\\baz", "..\\baz"], - ["\\\\foo\\baz", "\\\\foo\\baz-quux", "..\\baz-quux"], - ["C:\\baz", "\\\\foo\\bar\\baz", "\\\\foo\\bar\\baz"], - ["\\\\foo\\bar\\baz", "C:\\baz", "C:\\baz"] - ], - posix: - // arguments result - [ - ["/var/lib", "/var", ".."], - ["/var/lib", "/bin", "../../bin"], - ["/var/lib", "/var/lib", ""], - ["/var/lib", "/var/apache", "../apache"], - ["/var/", "/var/lib", "lib"], - ["/", "/var/lib", "var/lib"], - ["/foo/test", "/foo/test/bar/package.json", "bar/package.json"], - ["/Users/a/web/b/test/mails", "/Users/a/web/b", "../.."], - ["/foo/bar/baz-quux", "/foo/bar/baz", "../baz"], - ["/foo/bar/baz", "/foo/bar/baz-quux", "../baz-quux"], - ["/baz-quux", "/baz", "../baz"], - ["/baz", "/baz-quux", "../baz-quux"] - ] + // arguments result + win32: [ + ["c:/blah\\blah", "d:/games", "d:\\games"], + ["c:/aaaa/bbbb", "c:/aaaa", ".."], + ["c:/aaaa/bbbb", "c:/cccc", "..\\..\\cccc"], + ["c:/aaaa/bbbb", "c:/aaaa/bbbb", ""], + ["c:/aaaa/bbbb", "c:/aaaa/cccc", "..\\cccc"], + ["c:/aaaa/", "c:/aaaa/cccc", "cccc"], + ["c:/", "c:\\aaaa\\bbbb", "aaaa\\bbbb"], + ["c:/aaaa/bbbb", "d:\\", "d:\\"], + ["c:/AaAa/bbbb", "c:/aaaa/bbbb", ""], + ["c:/aaaaa/", "c:/aaaa/cccc", "..\\aaaa\\cccc"], + ["C:\\foo\\bar\\baz\\quux", "C:\\", "..\\..\\..\\.."], + ["C:\\foo\\test", "C:\\foo\\test\\bar\\package.json", "bar\\package.json"], + ["C:\\foo\\bar\\baz-quux", "C:\\foo\\bar\\baz", "..\\baz"], + ["C:\\foo\\bar\\baz", "C:\\foo\\bar\\baz-quux", "..\\baz-quux"], + ["\\\\foo\\bar", "\\\\foo\\bar\\baz", "baz"], + ["\\\\foo\\bar\\baz", "\\\\foo\\bar", ".."], + ["\\\\foo\\bar\\baz-quux", "\\\\foo\\bar\\baz", "..\\baz"], + ["\\\\foo\\bar\\baz", "\\\\foo\\bar\\baz-quux", "..\\baz-quux"], + ["C:\\baz-quux", "C:\\baz", "..\\baz"], + ["C:\\baz", "C:\\baz-quux", "..\\baz-quux"], + ["\\\\foo\\baz-quux", "\\\\foo\\baz", "..\\baz"], + ["\\\\foo\\baz", "\\\\foo\\baz-quux", "..\\baz-quux"], + ["C:\\baz", "\\\\foo\\bar\\baz", "\\\\foo\\bar\\baz"], + ["\\\\foo\\bar\\baz", "C:\\baz", "C:\\baz"], + ], + // arguments result + posix: [ + ["/var/lib", "/var", ".."], + ["/var/lib", "/bin", "../../bin"], + ["/var/lib", "/var/lib", ""], + ["/var/lib", "/var/apache", "../apache"], + ["/var/", "/var/lib", "lib"], + ["/", "/var/lib", "var/lib"], + ["/foo/test", "/foo/test/bar/package.json", "bar/package.json"], + ["/Users/a/web/b/test/mails", "/Users/a/web/b", "../.."], + ["/foo/bar/baz-quux", "/foo/bar/baz", "../baz"], + ["/foo/bar/baz", "/foo/bar/baz-quux", "../baz-quux"], + ["/baz-quux", "/baz", "../baz"], + ["/baz", "/baz-quux", "../baz-quux"], + ], }; test(function relative() { - relativeTests.posix.forEach(function(p) { + relativeTests.posix.forEach(function (p) { const expected = p[2]; const actual = path.posix.relative(p[0], p[1]); assertEquals(actual, expected); @@ -65,7 +59,7 @@ test(function relative() { }); test(function relativeWin32() { - relativeTests.win32.forEach(function(p) { + relativeTests.win32.forEach(function (p) { const expected = p[2]; const actual = path.win32.relative(p[0], p[1]); assertEquals(actual, expected); diff --git a/std/path/resolve_test.ts b/std/path/resolve_test.ts index 2fc49e398dd8ea..95aa84cce35170 100644 --- a/std/path/resolve_test.ts +++ b/std/path/resolve_test.ts @@ -20,8 +20,8 @@ const windowsTests = [["c:/", "///some//dir"], "c:\\some\\dir"], [ ["C:\\foo\\tmp.3\\", "..\\tmp.3\\cycles\\root.js"], - "C:\\foo\\tmp.3\\cycles\\root.js" - ] + "C:\\foo\\tmp.3\\cycles\\root.js", + ], ]; const posixTests = // arguments result @@ -31,11 +31,11 @@ const posixTests = [["a/b/c/", "../../.."], cwd()], [["."], cwd()], [["/some/dir", ".", "/absolute/"], "/absolute"], - [["/foo/tmp.3/", "../tmp.3/cycles/root.js"], "/foo/tmp.3/cycles/root.js"] + [["/foo/tmp.3/", "../tmp.3/cycles/root.js"], "/foo/tmp.3/cycles/root.js"], ]; test(function resolve() { - posixTests.forEach(function(p) { + posixTests.forEach(function (p) { const _p = p[0] as string[]; const actual = path.posix.resolve.apply(null, _p); assertEquals(actual, p[1]); @@ -43,7 +43,7 @@ test(function resolve() { }); test(function resolveWin32() { - windowsTests.forEach(function(p) { + windowsTests.forEach(function (p) { const _p = p[0] as string[]; const actual = path.win32.resolve.apply(null, _p); assertEquals(actual, p[1]); diff --git a/std/path/utils.ts b/std/path/utils.ts index cb1c14c16148ac..fc3dc5be9517e5 100644 --- a/std/path/utils.ts +++ b/std/path/utils.ts @@ -9,7 +9,7 @@ import { CHAR_LOWERCASE_Z, CHAR_DOT, CHAR_FORWARD_SLASH, - CHAR_BACKWARD_SLASH + CHAR_BACKWARD_SLASH, } from "./constants.ts"; export function assertPath(path: string): void { diff --git a/std/path/win32.ts b/std/path/win32.ts index 2f28d22c19f43f..d4febf706a2f36 100644 --- a/std/path/win32.ts +++ b/std/path/win32.ts @@ -7,7 +7,7 @@ import { CHAR_DOT, CHAR_BACKWARD_SLASH, CHAR_COLON, - CHAR_QUESTION_MARK + CHAR_QUESTION_MARK, } from "./constants.ts"; import { @@ -15,7 +15,7 @@ import { isPathSeparator, isWindowsDeviceRoot, normalizeString, - _format + _format, } from "./utils.ts"; import { assert } from "../testing/asserts.ts"; @@ -259,8 +259,9 @@ export function normalize(path: string): string { tail = ""; } if (tail.length === 0 && !isAbsolute) tail = "."; - if (tail.length > 0 && isPathSeparator(path.charCodeAt(len - 1))) + if (tail.length > 0 && isPathSeparator(path.charCodeAt(len - 1))) { tail += "\\"; + } if (device === undefined) { if (isAbsolute) { if (tail.length > 0) return `\\${tail}`; @@ -459,8 +460,9 @@ export function relative(from: string, to: string): string { // Lastly, append the rest of the destination (`to`) path that comes after // the common path parts - if (out.length > 0) return out + toOrig.slice(toStart + lastCommonSep, toEnd); - else { + if (out.length > 0) { + return out + toOrig.slice(toStart + lastCommonSep, toEnd); + } else { toStart += lastCommonSep; if (toOrig.charCodeAt(toStart) === CHAR_BACKWARD_SLASH) ++toStart; return toOrig.slice(toStart, toEnd); @@ -590,8 +592,9 @@ export function dirname(path: string): string { } export function basename(path: string, ext = ""): string { - if (ext !== undefined && typeof ext !== "string") + if (ext !== undefined && typeof ext !== "string") { throw new TypeError('"ext" argument must be a string'); + } assertPath(path); diff --git a/std/permissions/mod.ts b/std/permissions/mod.ts index e114934267d19e..b7f80117b6a63e 100644 --- a/std/permissions/mod.ts +++ b/std/permissions/mod.ts @@ -5,7 +5,7 @@ const { PermissionDenied } = Deno.errors; function getPermissionString(descriptors: Deno.PermissionDescriptor[]): string { return descriptors.length ? ` ${descriptors - .map(pd => { + .map((pd) => { switch (pd.name) { case "read": case "write": diff --git a/std/permissions/test.ts b/std/permissions/test.ts index 2c96dfea1da54c..6a9955b6ab50a2 100644 --- a/std/permissions/test.ts +++ b/std/permissions/test.ts @@ -10,9 +10,9 @@ test({ async fn() { assertEquals(await grant({ name: "net" }, { name: "env" }), [ { name: "net" }, - { name: "env" } + { name: "env" }, ]); - } + }, }); test({ @@ -20,28 +20,28 @@ test({ async fn() { assertEquals(await grant([{ name: "net" }, { name: "env" }]), [ { name: "net" }, - { name: "env" } + { name: "env" }, ]); - } + }, }); test({ name: "grant logic", async fn() { assert(await grant({ name: "net" })); - } + }, }); test({ name: "grantOrThrow basic", async fn() { await grantOrThrow({ name: "net" }, { name: "env" }); - } + }, }); test({ name: "grantOrThrow array", async fn() { await grantOrThrow([{ name: "net" }, { name: "env" }]); - } + }, }); diff --git a/std/signal/mod.ts b/std/signal/mod.ts index e368edbd123d66..0f2b475342093a 100644 --- a/std/signal/mod.ts +++ b/std/signal/mod.ts @@ -13,13 +13,13 @@ export function signal( const streams = signos.map(Deno.signal); - streams.forEach(stream => { + streams.forEach((stream) => { mux.add(stream); }); // Create dispose method for the muxer of signal streams. const dispose = (): void => { - streams.forEach(stream => { + streams.forEach((stream) => { stream.dispose(); }); }; diff --git a/std/signal/test.ts b/std/signal/test.ts index d59484e1225c1b..16d1458a2313a2 100644 --- a/std/signal/test.ts +++ b/std/signal/test.ts @@ -56,6 +56,6 @@ if (Deno.build.os !== "win") { // yet resolved, delay to next turn of event loop otherwise, // we'll be leaking resources. await delay(10); - } + }, }); } diff --git a/std/strings/README.md b/std/strings/README.md index 7621248bb7adfe..43be553b892d0d 100644 --- a/std/strings/README.md +++ b/std/strings/README.md @@ -21,6 +21,6 @@ pad("denosorusrex", 6, { side: "left", strict: true, strictSide: "right", - strictChar: "..." + strictChar: "...", }); // output : "den..." ``` diff --git a/std/strings/pad.ts b/std/strings/pad.ts index dc75a29549db5e..b72ae2074458a2 100644 --- a/std/strings/pad.ts +++ b/std/strings/pad.ts @@ -48,7 +48,7 @@ export function pad( strict: false, side: "left", strictChar: "", - strictSide: "right" + strictSide: "right", } ): string { let out = input; diff --git a/std/strings/pad_test.ts b/std/strings/pad_test.ts index 9a125b9d2c06ac..806874bd01bdf9 100644 --- a/std/strings/pad_test.ts +++ b/std/strings/pad_test.ts @@ -18,7 +18,7 @@ test(function padTest(): void { pad("denosorusrex", 4, { char: "*", side: "right", - strict: false + strict: false, }), expected4 ); @@ -27,7 +27,7 @@ test(function padTest(): void { char: "*", side: "left", strict: true, - strictSide: "right" + strictSide: "right", }), expected5 ); @@ -36,7 +36,7 @@ test(function padTest(): void { char: "*", side: "left", strict: true, - strictSide: "left" + strictSide: "left", }), expected6 ); @@ -46,7 +46,7 @@ test(function padTest(): void { side: "left", strict: true, strictSide: "right", - strictChar: "..." + strictChar: "...", }), expected7 ); @@ -56,7 +56,7 @@ test(function padTest(): void { side: "left", strict: true, strictSide: "left", - strictChar: "..." + strictChar: "...", }), expected8 ); @@ -66,7 +66,7 @@ test(function padTest(): void { side: "left", strict: true, strictSide: "right", - strictChar: "..." + strictChar: "...", }), expected2 ); diff --git a/std/testing/README.md b/std/testing/README.md index a3640e7281ea8d..c7c614103edbd1 100644 --- a/std/testing/README.md +++ b/std/testing/README.md @@ -44,7 +44,7 @@ Deno.test({ fn(): void { assertEquals("world", "world"); assertEquals({ hello: "world" }, { hello: "world" }); - } + }, }); await Deno.runTests(); @@ -165,7 +165,7 @@ bench({ b.start(); for (let i = 0; i < 1e6; i++); b.stop(); - } + }, }); ``` diff --git a/std/testing/asserts.ts b/std/testing/asserts.ts index 44c3112043dc5a..19be68763e4cf5 100644 --- a/std/testing/asserts.ts +++ b/std/testing/asserts.ts @@ -66,7 +66,7 @@ function buildMessage(diffResult: ReadonlyArray>): string[] { } function isKeyedCollection(x: unknown): x is Set { - return [Symbol.iterator, "size"].every(k => k in (x as Set)); + return [Symbol.iterator, "size"].every((k) => k in (x as Set)); } export function equal(c: unknown, d: unknown): boolean { diff --git a/std/testing/asserts_test.ts b/std/testing/asserts_test.ts index 558ce1578d968d..62e199298240f4 100644 --- a/std/testing/asserts_test.ts +++ b/std/testing/asserts_test.ts @@ -12,7 +12,7 @@ import { equal, fail, unimplemented, - unreachable + unreachable, } from "./asserts.ts"; import { red, green, white, gray, bold } from "../fmt/colors.ts"; const { test } = Deno; @@ -53,11 +53,11 @@ test(function testingEqual(): void { equal( new Map([ ["foo", "bar"], - ["baz", "baz"] + ["baz", "baz"], ]), new Map([ ["foo", "bar"], - ["baz", "baz"] + ["baz", "baz"], ]) ) ); @@ -77,11 +77,11 @@ test(function testingEqual(): void { equal( new Map([ ["foo", "bar"], - ["baz", "qux"] + ["baz", "qux"], ]), new Map([ ["baz", "qux"], - ["foo", "bar"] + ["foo", "bar"], ]) ) ); @@ -92,7 +92,7 @@ test(function testingEqual(): void { new Map([["foo", "bar"]]), new Map([ ["foo", "bar"], - ["bar", "baz"] + ["bar", "baz"], ]) ) ); @@ -253,7 +253,7 @@ const createHeader = (): string[] => [ "", ` ${gray(bold("[Diff]"))} ${red(bold("Left"))} / ${green(bold("Right"))}`, "", - "" + "", ]; const added: (s: string) => string = (s: string): string => green(bold(s)); @@ -267,7 +267,7 @@ test({ assertEquals(10, 10); assertEquals("abc", "abc"); assertEquals({ a: 10, b: { c: "1" } }, { a: 10, b: { c: "1" } }); - } + }, }); test({ @@ -278,7 +278,7 @@ test({ AssertionError, [...createHeader(), removed(`- 1`), added(`+ 2`), ""].join("\n") ); - } + }, }); test({ @@ -289,7 +289,7 @@ test({ AssertionError, [...createHeader(), removed(`- 1`), added(`+ "1"`)].join("\n") ); - } + }, }); test({ @@ -306,10 +306,10 @@ test({ white(' "2",'), white(" 3,"), white(" ]"), - "" + "", ].join("\n") ); - } + }, }); test({ @@ -329,8 +329,8 @@ test({ removed(`- "b": "2",`), removed(`- "c": 3,`), white(" }"), - "" + "", ].join("\n") ); - } + }, }); diff --git a/std/testing/bench.ts b/std/testing/bench.ts index 1c4b01c0b81f3d..cd7b89e8c409a8 100644 --- a/std/testing/bench.ts +++ b/std/testing/bench.ts @@ -65,7 +65,7 @@ function createBenchmarkTimer(clock: BenchmarkClock): BenchmarkTimer { }, stop(): void { clock.stop = performance.now(); - } + }, }; } @@ -84,7 +84,7 @@ export function bench( candidates.push({ name: benchmark.name, runs: verifyOr1Run(benchmark.runs), - func: benchmark.func + func: benchmark.func, }); } } @@ -92,7 +92,7 @@ export function bench( /** Runs all registered and non-skipped benchmarks serially. */ export async function runBenchmarks({ only = /[^\s]/, - skip = /^\s*$/ + skip = /^\s*$/, }: BenchmarkRunOptions = {}): Promise { // Filtering candidates by the "only" and "skip" constraint const benchmarks: BenchmarkDefinition[] = candidates.filter( diff --git a/std/testing/bench_example.ts b/std/testing/bench_example.ts index d27fb97e8c9988..401516cca8de19 100644 --- a/std/testing/bench_example.ts +++ b/std/testing/bench_example.ts @@ -16,7 +16,7 @@ bench({ b.start(); for (let i = 0; i < 1e6; i++); b.stop(); - } + }, }); // Itsabug diff --git a/std/testing/bench_test.ts b/std/testing/bench_test.ts index 904ee2a8ce89c9..6dfc18b1090974 100644 --- a/std/testing/bench_test.ts +++ b/std/testing/bench_test.ts @@ -6,7 +6,7 @@ import "./bench_example.ts"; test({ name: "benching", - fn: async function(): Promise { + fn: async function (): Promise { bench(function forIncrementX1e9(b): void { b.start(); for (let i = 0; i < 1e9; i++); @@ -49,7 +49,7 @@ test({ b.start(); for (let i = 0; i < 1e6; i++); b.stop(); - } + }, }); bench(function throwing(b): void { @@ -58,5 +58,5 @@ test({ }); await runBenchmarks({ skip: /throw/ }); - } + }, }); diff --git a/std/testing/diff.ts b/std/testing/diff.ts index 5cedb402ac3b7b..97baa089f43e21 100644 --- a/std/testing/diff.ts +++ b/std/testing/diff.ts @@ -7,7 +7,7 @@ interface FarthestPoint { export enum DiffType { removed = "removed", common = "common", - added = "added" + added = "added", } export interface DiffResult { @@ -60,12 +60,12 @@ export default function diff(A: T[], B: T[]): Array> { ...A.map( (a): DiffResult => ({ type: swapped ? DiffType.added : DiffType.removed, - value: a + value: a, }) ), ...suffixCommon.map( (c): DiffResult => ({ type: DiffType.common, value: c }) - ) + ), ]; } const offset = N; @@ -107,13 +107,13 @@ export default function diff(A: T[], B: T[]): Array> { if (type === REMOVED) { result.unshift({ type: swapped ? DiffType.removed : DiffType.added, - value: B[b] + value: B[b], }); b -= 1; } else if (type === ADDED) { result.unshift({ type: swapped ? DiffType.added : DiffType.removed, - value: A[a] + value: A[a], }); a -= 1; } else { @@ -133,8 +133,9 @@ export default function diff(A: T[], B: T[]): Array> { k: number, M: number ): FarthestPoint { - if (slide && slide.y === -1 && down && down.y === -1) + if (slide && slide.y === -1 && down && down.y === -1) { return { y: 0, id: 0 }; + } if ( (down && down.y === -1) || k === M || @@ -215,6 +216,6 @@ export default function diff(A: T[], B: T[]): Array> { ...backTrace(A, B, fp[delta + offset], swapped), ...suffixCommon.map( (c): DiffResult => ({ type: DiffType.common, value: c }) - ) + ), ]; } diff --git a/std/testing/diff_test.ts b/std/testing/diff_test.ts index 0e8416274098a8..317dc0db87bdb7 100644 --- a/std/testing/diff_test.ts +++ b/std/testing/diff_test.ts @@ -6,7 +6,7 @@ test({ name: "empty", fn(): void { assertEquals(diff([], []), []); - } + }, }); test({ @@ -14,30 +14,30 @@ test({ fn(): void { assertEquals(diff(["a"], ["b"]), [ { type: "removed", value: "a" }, - { type: "added", value: "b" } + { type: "added", value: "b" }, ]); - } + }, }); test({ name: '"a" vs "a"', fn(): void { assertEquals(diff(["a"], ["a"]), [{ type: "common", value: "a" }]); - } + }, }); test({ name: '"a" vs ""', fn(): void { assertEquals(diff(["a"], []), [{ type: "removed", value: "a" }]); - } + }, }); test({ name: '"" vs "a"', fn(): void { assertEquals(diff([], ["a"]), [{ type: "added", value: "a" }]); - } + }, }); test({ @@ -45,9 +45,9 @@ test({ fn(): void { assertEquals(diff(["a"], ["a", "b"]), [ { type: "common", value: "a" }, - { type: "added", value: "b" } + { type: "added", value: "b" }, ]); - } + }, }); test({ @@ -62,9 +62,9 @@ test({ { type: "common", value: "n" }, { type: "common", value: "g" }, { type: "removed", value: "t" }, - { type: "removed", value: "h" } + { type: "removed", value: "h" }, ]); - } + }, }); test({ @@ -78,9 +78,9 @@ test({ { type: "removed", value: "n" }, { type: "removed", value: "g" }, { type: "removed", value: "t" }, - { type: "removed", value: "h" } + { type: "removed", value: "h" }, ]); - } + }, }); test({ @@ -94,9 +94,9 @@ test({ { type: "added", value: "n" }, { type: "added", value: "g" }, { type: "added", value: "t" }, - { type: "added", value: "h" } + { type: "added", value: "h" }, ]); - } + }, }); test({ @@ -105,7 +105,7 @@ test({ assertEquals(diff(["abc", "c"], ["abc", "bcd", "c"]), [ { type: "common", value: "abc" }, { type: "added", value: "bcd" }, - { type: "common", value: "c" } + { type: "common", value: "c" }, ]); - } + }, }); diff --git a/std/testing/format.ts b/std/testing/format.ts index 62fdde5eb4e339..ee291dc23e3991 100644 --- a/std/testing/format.ts +++ b/std/testing/format.ts @@ -56,7 +56,7 @@ const DEFAULT_OPTIONS: Options = { indent: 2, maxDepth: Infinity, min: false, - printFunctionName: true + printFunctionName: true, }; interface BasicValueOptions { @@ -358,8 +358,8 @@ function printIteratorValues( return result; } -const getKeysOfEnumerableProperties = (object: {}): Array => { - const keys: Array = Object.keys(object).sort(); +function getKeysOfEnumerableProperties(object: T): Array { + const keys = Object.keys(object).sort() as Array; if (Object.getOwnPropertySymbols) { Object.getOwnPropertySymbols(object).forEach((symbol): void => { @@ -372,7 +372,7 @@ const getKeysOfEnumerableProperties = (object: {}): Array => { } return keys; -}; +} /** * Return properties of an object @@ -519,7 +519,7 @@ const getConfig = (options: Options): Config => ({ ...options, indent: options.min ? "" : createIndent(options.indent), spacingInner: options.min ? " " : "\n", - spacingOuter: options.min ? "" : "\n" + spacingOuter: options.min ? "" : "\n", }); /** @@ -531,7 +531,7 @@ const getConfig = (options: Options): Config => ({ export function format(val: any, options: Optional = {}): string { const opts: Options = { ...DEFAULT_OPTIONS, - ...options + ...options, }; const basicResult = printBasicValue(val, opts); if (basicResult !== null) { diff --git a/std/testing/format_test.ts b/std/testing/format_test.ts index 14f84f3c2b8a82..eac5b7d840bcfe 100644 --- a/std/testing/format_test.ts +++ b/std/testing/format_test.ts @@ -29,12 +29,12 @@ const createVal = () => [ { id: "8658c1d0-9eda-4a90-95e1-8001e8eb6036", text: "Add alternative serialize API for pretty-format plugins", - type: "ADD_TODO" + type: "ADD_TODO", }, { id: "8658c1d0-9eda-4a90-95e1-8001e8eb6036", - type: "TOGGLE_TODO" - } + type: "TOGGLE_TODO", + }, ]; // eslint-disable-next-line @typescript-eslint/explicit-function-return-type @@ -50,7 +50,7 @@ const createExpected = () => ' "id": "8658c1d0-9eda-4a90-95e1-8001e8eb6036",', ' "type": "TOGGLE_TODO",', " },", - "]" + "]", ].join("\n"); test({ @@ -58,7 +58,7 @@ test({ fn(): void { const val = returnArguments(); assertEquals(format(val), "Arguments []"); - } + }, }); test({ @@ -66,7 +66,7 @@ test({ fn(): void { const val: unknown[] = []; assertEquals(format(val), "Array []"); - } + }, }); test({ @@ -74,7 +74,7 @@ test({ fn(): void { const val = [1, 2, 3]; assertEquals(format(val), "Array [\n 1,\n 2,\n 3,\n]"); - } + }, }); test({ @@ -82,7 +82,7 @@ test({ fn(): void { const val = new Uint32Array(0); assertEquals(format(val), "Uint32Array []"); - } + }, }); test({ @@ -90,7 +90,7 @@ test({ fn(): void { const val = new Uint32Array(3); assertEquals(format(val), "Uint32Array [\n 0,\n 0,\n 0,\n]"); - } + }, }); test({ @@ -98,7 +98,7 @@ test({ fn(): void { const val = new ArrayBuffer(3); assertEquals(format(val), "ArrayBuffer []"); - } + }, }); test({ @@ -109,7 +109,7 @@ test({ format(val), "Array [\n Array [\n 1,\n 2,\n 3,\n ],\n]" ); - } + }, }); test({ @@ -117,7 +117,7 @@ test({ fn(): void { const val = true; assertEquals(format(val), "true"); - } + }, }); test({ @@ -125,7 +125,7 @@ test({ fn(): void { const val = false; assertEquals(format(val), "false"); - } + }, }); test({ @@ -133,7 +133,7 @@ test({ fn(): void { const val = new Error(); assertEquals(format(val), "[Error]"); - } + }, }); test({ @@ -141,7 +141,7 @@ test({ fn(): void { const val = new TypeError("message"); assertEquals(format(val), "[TypeError: message]"); - } + }, }); test({ @@ -150,7 +150,7 @@ test({ // tslint:disable-next-line:function-constructor const val = new Function(); assertEquals(format(val), "[Function anonymous]"); - } + }, }); test({ @@ -163,7 +163,7 @@ test({ // tslint:disable-next-line:no-empty f((): void => {}); assertEquals(format(val), "[Function anonymous]"); - } + }, }); test({ @@ -176,7 +176,7 @@ test({ formatted === "[Function anonymous]" || formatted === "[Function val]", true ); - } + }, }); test({ @@ -185,7 +185,7 @@ test({ // tslint:disable-next-line:no-empty const val = function named(): void {}; assertEquals(format(val), "[Function named]"); - } + }, }); test({ @@ -197,7 +197,7 @@ test({ yield 3; }; assertEquals(format(val), "[Function generate]"); - } + }, }); test({ @@ -207,11 +207,11 @@ test({ const val = function named(): void {}; assertEquals( format(val, { - printFunctionName: false + printFunctionName: false, }), "[Function]" ); - } + }, }); test({ @@ -219,7 +219,7 @@ test({ fn(): void { const val = Infinity; assertEquals(format(val), "Infinity"); - } + }, }); test({ @@ -227,7 +227,7 @@ test({ fn(): void { const val = -Infinity; assertEquals(format(val), "-Infinity"); - } + }, }); test({ @@ -235,7 +235,7 @@ test({ fn(): void { const val = new Map(); assertEquals(format(val), "Map {}"); - } + }, }); test({ @@ -248,7 +248,7 @@ test({ format(val), 'Map {\n "prop1" => "value1",\n "prop2" => "value2",\n}' ); - } + }, }); test({ @@ -267,7 +267,7 @@ test({ [Symbol("description"), "symbol"], ["Symbol(description)", "string"], [["array", "key"], "array"], - [{ key: "value" }, "object"] + [{ key: "value" }, "object"], ]); const expected = [ "Map {", @@ -288,10 +288,10 @@ test({ " Object {", ' "key": "value",', ' } => "object",', - "}" + "}", ].join("\n"); assertEquals(format(val), expected); - } + }, }); test({ @@ -299,7 +299,7 @@ test({ fn(): void { const val = NaN; assertEquals(format(val), "NaN"); - } + }, }); test({ @@ -307,7 +307,7 @@ test({ fn(): void { const val = null; assertEquals(format(val), "null"); - } + }, }); test({ @@ -315,7 +315,7 @@ test({ fn(): void { const val = 123; assertEquals(format(val), "123"); - } + }, }); test({ @@ -323,7 +323,7 @@ test({ fn(): void { const val = -123; assertEquals(format(val), "-123"); - } + }, }); test({ @@ -331,7 +331,7 @@ test({ fn(): void { const val = 0; assertEquals(format(val), "0"); - } + }, }); test({ @@ -339,7 +339,7 @@ test({ fn(): void { const val = -0; assertEquals(format(val), "-0"); - } + }, }); test({ @@ -347,7 +347,7 @@ test({ fn(): void { const val = new Date(10e11); assertEquals(format(val), "2001-09-09T01:46:40.000Z"); - } + }, }); test({ @@ -355,7 +355,7 @@ test({ fn(): void { const val = new Date(Infinity); assertEquals(format(val), "Date { NaN }"); - } + }, }); test({ @@ -363,7 +363,7 @@ test({ fn(): void { const val = {}; assertEquals(format(val), "Object {}"); - } + }, }); test({ @@ -374,7 +374,7 @@ test({ format(val), 'Object {\n "prop1": "value1",\n "prop2": "value2",\n}' ); - } + }, }); test({ @@ -390,7 +390,7 @@ test({ 'Object {\n "prop": "value1",\n Symbol(symbol1): "value2",\n ' + 'Symbol(symbol2): "value3",\n}' ); - } + }, }); test({ @@ -398,15 +398,15 @@ test({ "prints an object without non-enumerable properties which have string key", fn(): void { const val = { - enumerable: true + enumerable: true, }; const key = "non-enumerable"; Object.defineProperty(val, key, { enumerable: false, - value: false + value: false, }); assertEquals(format(val), 'Object {\n "enumerable": true,\n}'); - } + }, }); test({ @@ -414,15 +414,15 @@ test({ "prints an object without non-enumerable properties which have symbol key", fn(): void { const val = { - enumerable: true + enumerable: true, }; const key = Symbol("non-enumerable"); Object.defineProperty(val, key, { enumerable: false, - value: false + value: false, }); assertEquals(format(val), 'Object {\n "enumerable": true,\n}'); - } + }, }); test({ @@ -430,7 +430,7 @@ test({ fn(): void { const val = { b: 1, a: 2 }; assertEquals(format(val), 'Object {\n "a": 2,\n "b": 1,\n}'); - } + }, }); test({ @@ -438,7 +438,7 @@ test({ fn(): void { const val = new RegExp("regexp"); assertEquals(format(val), "/regexp/"); - } + }, }); test({ @@ -446,7 +446,7 @@ test({ fn(): void { const val = /regexp/gi; assertEquals(format(val), "/regexp/gi"); - } + }, }); test({ @@ -454,7 +454,7 @@ test({ fn(): void { const val = /regexp\d/gi; assertEquals(format(val), "/regexp\\d/gi"); - } + }, }); test({ @@ -462,7 +462,7 @@ test({ fn(): void { const val = /regexp\d/gi; assertEquals(format(val, { escapeRegex: true }), "/regexp\\\\d/gi"); - } + }, }); test({ @@ -473,7 +473,7 @@ test({ format(obj, { escapeRegex: true }), 'Object {\n "test": /regexp\\\\d/gi,\n}' ); - } + }, }); test({ @@ -481,7 +481,7 @@ test({ fn(): void { const val = new Set(); assertEquals(format(val), "Set {}"); - } + }, }); test({ @@ -491,7 +491,7 @@ test({ val.add("value1"); val.add("value2"); assertEquals(format(val), 'Set {\n "value1",\n "value2",\n}'); - } + }, }); test({ @@ -499,7 +499,7 @@ test({ fn(): void { const val = "string"; assertEquals(format(val), '"string"'); - } + }, }); test({ @@ -507,7 +507,7 @@ test({ fn(): void { const val = "\"'\\"; assertEquals(format(val), '"\\"\'\\\\"'); - } + }, }); test({ @@ -515,7 +515,7 @@ test({ fn(): void { const val = "\"'\\n"; assertEquals(format(val, { escapeString: false }), '""\'\\n"'); - } + }, }); test({ @@ -523,7 +523,7 @@ test({ fn(): void { assertEquals(format('"-"'), '"\\"-\\""'); assertEquals(format("\\ \\\\"), '"\\\\ \\\\\\\\"'); - } + }, }); test({ @@ -531,7 +531,7 @@ test({ fn(): void { const val = ["line 1", "line 2", "line 3"].join("\n"); assertEquals(format(val), '"' + val + '"'); - } + }, }); test({ @@ -540,15 +540,15 @@ test({ const polyline = { props: { id: "J", - points: ["0.5,0.460", "0.5,0.875", "0.25,0.875"].join("\n") + points: ["0.5,0.460", "0.5,0.875", "0.25,0.875"].join("\n"), }, - type: "polyline" + type: "polyline", }; const val = { props: { - children: polyline + children: polyline, }, - type: "svg" + type: "svg", }; assertEquals( format(val), @@ -566,10 +566,10 @@ test({ " },", " },", ' "type": "svg",', - "}" + "}", ].join("\n") ); - } + }, }); test({ @@ -577,7 +577,7 @@ test({ fn(): void { const val = Symbol("symbol"); assertEquals(format(val), "Symbol(symbol)"); - } + }, }); test({ @@ -585,7 +585,7 @@ test({ fn(): void { const val = undefined; assertEquals(format(val), "undefined"); - } + }, }); test({ @@ -593,7 +593,7 @@ test({ fn(): void { const val = new WeakMap(); assertEquals(format(val), "WeakMap {}"); - } + }, }); test({ @@ -601,7 +601,7 @@ test({ fn(): void { const val = new WeakSet(); assertEquals(format(val), "WeakSet {}"); - } + }, }); test({ @@ -613,7 +613,7 @@ test({ 'Object {\n "prop": Object {\n "prop": Object {\n "prop": ' + '"value",\n },\n },\n}' ); - } + }, }); test({ @@ -623,7 +623,7 @@ test({ const val: any = {}; val.prop = val; assertEquals(format(val), 'Object {\n "prop": [Circular],\n}'); - } + }, }); test({ @@ -635,21 +635,21 @@ test({ format(val), 'Object {\n "prop1": Object {},\n "prop2": Object {},\n}' ); - } + }, }); test({ name: "default implicit: 2 spaces", fn(): void { assertEquals(format(createVal()), createExpected()); - } + }, }); test({ name: "default explicit: 2 spaces", fn(): void { assertEquals(format(createVal(), { indent: 2 }), createExpected()); - } + }, }); // Tests assume that no strings in val contain multiple adjacent spaces! @@ -661,7 +661,7 @@ test({ format(createVal(), { indent }), createExpected().replace(/ {2}/g, " ".repeat(indent)) ); - } + }, }); test({ @@ -672,7 +672,7 @@ test({ format(createVal(), { indent }), createExpected().replace(/ {2}/g, " ".repeat(indent)) ); - } + }, }); test({ @@ -693,8 +693,8 @@ test({ "object with constructor": new MyObject("value"), "object without constructor": Object.create(null), "set empty": new Set(), - "set non-empty": new Set(["value"]) - } + "set non-empty": new Set(["value"]), + }, ]; assertEquals( format(v, { maxDepth: 2 }), @@ -715,17 +715,17 @@ test({ ' "set empty": [Set],', ' "set non-empty": [Set],', " },", - "]" + "]", ].join("\n") ); - } + }, }); test({ name: "prints objects with no constructor", fn(): void { assertEquals(format(Object.create(null)), "Object {}"); - } + }, }); test({ @@ -736,10 +736,10 @@ test({ const expected = [ "Object {", // Object instead of undefined ' "constructor": "constructor",', - "}" + "}", ].join("\n"); assertEquals(format(obj), expected); - } + }, }); test({ @@ -748,11 +748,11 @@ test({ assertEquals( format({ toJSON: (): unknown => ({ value: false }), - value: true + value: true, }), 'Object {\n "value": false,\n}' ); - } + }, }); test({ @@ -761,11 +761,11 @@ test({ assertEquals( format({ toJSON: (): string => "[Internal Object]", - value: true + value: true, }), '"[Internal Object]"' ); - } + }, }); test({ @@ -774,11 +774,11 @@ test({ assertEquals( format({ toJSON: false, - value: true + value: true, }), 'Object {\n "toJSON": false,\n "value": true,\n}' ); - } + }, }); test({ @@ -787,11 +787,11 @@ test({ assertEquals( format({ toJSON: (): unknown => ({ toJSON: (): unknown => ({ value: true }) }), - value: false + value: false, }), 'Object {\n "toJSON": [Function toJSON],\n}' ); - } + }, }); test({ @@ -801,5 +801,5 @@ test({ // eslint-disable-next-line @typescript-eslint/no-explicit-any (set as any).toJSON = (): string => "map"; assertEquals(format(set), '"map"'); - } + }, }); diff --git a/std/testing/runner.ts b/std/testing/runner.ts index 9aa31cb4a7434e..0abc6012bd7c9f 100755 --- a/std/testing/runner.ts +++ b/std/testing/runner.ts @@ -75,7 +75,7 @@ export async function* findTestModules( exclude: excludePaths, includeDirs: true, extended: true, - globstar: true + globstar: true, }; async function* expandDirectory(d: string): AsyncIterableIterator { @@ -83,7 +83,7 @@ export async function* findTestModules( for await (const walkInfo of expandGlob(dirGlob, { ...expandGlobOpts, root: d, - includeDirs: false + includeDirs: false, })) { yield filePathToUrl(walkInfo.filename); } @@ -170,7 +170,7 @@ export async function runTestModules({ exitOnFail = false, only = /[^\s]/, skip = /^\s*$/, - disableLog = false + disableLog = false, }: RunTestModulesOptions = {}): Promise { let moduleCount = 0; const testModules = []; @@ -235,7 +235,7 @@ export async function runTestModules({ exitOnFail, only, skip, - disableLog + disableLog, }); } @@ -247,14 +247,14 @@ async function main(): Promise { exclude: ["e"], failfast: ["f"], help: ["h"], - quiet: ["q"] + quiet: ["q"], }, default: { "allow-none": false, failfast: false, help: false, - quiet: false - } + quiet: false, + }, }); if (parsedArgs.help) { return showHelp(); @@ -277,7 +277,7 @@ async function main(): Promise { exclude, allowNone, disableLog, - exitOnFail: true + exitOnFail: true, }); } catch (error) { if (!disableLog) { diff --git a/std/textproto/mod.ts b/std/textproto/mod.ts index b27b1d59b7b39b..760a068b5306e5 100644 --- a/std/textproto/mod.ts +++ b/std/textproto/mod.ts @@ -5,24 +5,14 @@ import { BufReader } from "../io/bufio.ts"; import { charCode } from "../io/util.ts"; +import { concat } from "../bytes/mod.ts"; +import { decode } from "../strings/mod.ts"; -const asciiDecoder = new TextDecoder(); function str(buf: Uint8Array | null | undefined): string { if (buf == null) { return ""; } else { - return asciiDecoder.decode(buf); - } -} - -export function append(a: Uint8Array, b: Uint8Array): Uint8Array { - if (a == null) { - return b; - } else { - const output = new Uint8Array(a.length + b.length); - output.set(a, 0); - output.set(b, a.length); - return output; + return decode(buf); } } @@ -146,9 +136,7 @@ export class TextProtoReader { } return l; } - - // @ts-ignore - line = append(line, l); + line = line ? concat(line, l) : l; if (!more) { break; } diff --git a/std/textproto/reader_test.ts b/std/textproto/reader_test.ts deleted file mode 100644 index f0ae63894ddec7..00000000000000 --- a/std/textproto/reader_test.ts +++ /dev/null @@ -1,180 +0,0 @@ -// Based on https://github.com/golang/go/blob/master/src/net/textproto/reader_test.go -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -import { BufReader } from "../io/bufio.ts"; -import { TextProtoReader } from "./mod.ts"; -import { stringsReader } from "../io/util.ts"; -import { - assert, - assertEquals, - assertThrows, - assertNotEOF -} from "../testing/asserts.ts"; -const { test } = Deno; - -function reader(s: string): TextProtoReader { - return new TextProtoReader(new BufReader(stringsReader(s))); -} - -test({ - ignore: true, - name: "[textproto] Reader : DotBytes", - fn(): Promise { - const _input = - "dotlines\r\n.foo\r\n..bar\n...baz\nquux\r\n\r\n.\r\nanot.her\r\n"; - return Promise.resolve(); - } -}); - -test(async function textprotoReadEmpty(): Promise { - const r = reader(""); - const m = await r.readMIMEHeader(); - assertEquals(m, Deno.EOF); -}); - -test(async function textprotoReader(): Promise { - const r = reader("line1\nline2\n"); - let s = await r.readLine(); - assertEquals(s, "line1"); - - s = await r.readLine(); - assertEquals(s, "line2"); - - s = await r.readLine(); - assert(s === Deno.EOF); -}); - -test({ - name: "[textproto] Reader : MIME Header", - async fn(): Promise { - const input = - "my-key: Value 1 \r\nLong-key: Even Longer Value\r\nmy-Key: " + - "Value 2\r\n\n"; - const r = reader(input); - const m = assertNotEOF(await r.readMIMEHeader()); - assertEquals(m.get("My-Key"), "Value 1, Value 2"); - assertEquals(m.get("Long-key"), "Even Longer Value"); - } -}); - -test({ - name: "[textproto] Reader : MIME Header Single", - async fn(): Promise { - const input = "Foo: bar\n\n"; - const r = reader(input); - const m = assertNotEOF(await r.readMIMEHeader()); - assertEquals(m.get("Foo"), "bar"); - } -}); - -test({ - name: "[textproto] Reader : MIME Header No Key", - async fn(): Promise { - const input = ": bar\ntest-1: 1\n\n"; - const r = reader(input); - const m = assertNotEOF(await r.readMIMEHeader()); - assertEquals(m.get("Test-1"), "1"); - } -}); - -test({ - name: "[textproto] Reader : Large MIME Header", - async fn(): Promise { - const data: string[] = []; - // Go test is 16*1024. But seems it can't handle more - for (let i = 0; i < 1024; i++) { - data.push("x"); - } - const sdata = data.join(""); - const r = reader(`Cookie: ${sdata}\r\n\r\n`); - const m = assertNotEOF(await r.readMIMEHeader()); - assertEquals(m.get("Cookie"), sdata); - } -}); - -// Test that we read slightly-bogus MIME headers seen in the wild, -// with spaces before colons, and spaces in keys. -test({ - name: "[textproto] Reader : MIME Header Non compliant", - async fn(): Promise { - const input = - "Foo: bar\r\n" + - "Content-Language: en\r\n" + - "SID : 0\r\n" + - "Audio Mode : None\r\n" + - "Privilege : 127\r\n\r\n"; - const r = reader(input); - const m = assertNotEOF(await r.readMIMEHeader()); - assertEquals(m.get("Foo"), "bar"); - assertEquals(m.get("Content-Language"), "en"); - assertEquals(m.get("SID"), "0"); - assertEquals(m.get("Privilege"), "127"); - // Not a legal http header - assertThrows((): void => { - assertEquals(m.get("Audio Mode"), "None"); - }); - } -}); - -test({ - name: "[textproto] Reader : MIME Header Malformed", - async fn(): Promise { - const input = [ - "No colon first line\r\nFoo: foo\r\n\r\n", - " No colon first line with leading space\r\nFoo: foo\r\n\r\n", - "\tNo colon first line with leading tab\r\nFoo: foo\r\n\r\n", - " First: line with leading space\r\nFoo: foo\r\n\r\n", - "\tFirst: line with leading tab\r\nFoo: foo\r\n\r\n", - "Foo: foo\r\nNo colon second line\r\n\r\n" - ]; - const r = reader(input.join("")); - - let err; - try { - await r.readMIMEHeader(); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.InvalidData); - } -}); - -test({ - name: "[textproto] Reader : MIME Header Trim Continued", - async fn(): Promise { - const input = - "" + // for code formatting purpose. - "a:\n" + - " 0 \r\n" + - "b:1 \t\r\n" + - "c: 2\r\n" + - " 3\t\n" + - " \t 4 \r\n\n"; - const r = reader(input); - let err; - try { - await r.readMIMEHeader(); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.InvalidData); - } -}); - -test({ - name: "[textproto] #409 issue : multipart form boundary", - async fn(): Promise { - const input = [ - "Accept: */*\r\n", - 'Content-Disposition: form-data; name="test"\r\n', - " \r\n", - "------WebKitFormBoundaryimeZ2Le9LjohiUiG--\r\n\n" - ]; - const r = reader(input.join("")); - const m = assertNotEOF(await r.readMIMEHeader()); - assertEquals(m.get("Accept"), "*/*"); - assertEquals(m.get("Content-Disposition"), 'form-data; name="test"'); - } -}); diff --git a/std/textproto/test.ts b/std/textproto/test.ts index 9a992a2cf6f53f..5833935baab45f 100644 --- a/std/textproto/test.ts +++ b/std/textproto/test.ts @@ -1,17 +1,180 @@ -// Based on https://github.com/golang/go/blob/891682/src/net/textproto/ +// Based on https://github.com/golang/go/blob/master/src/net/textproto/reader_test.go // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -import { append } from "./mod.ts"; -import { assertEquals } from "../testing/asserts.ts"; +import { BufReader } from "../io/bufio.ts"; +import { TextProtoReader } from "./mod.ts"; +import { stringsReader } from "../io/util.ts"; +import { + assert, + assertEquals, + assertThrows, + assertNotEOF, +} from "../testing/asserts.ts"; const { test } = Deno; -test(function textprotoAppend(): void { - const enc = new TextEncoder(); - const dec = new TextDecoder(); - const u1 = enc.encode("Hello "); - const u2 = enc.encode("World"); - const joined = append(u1, u2); - assertEquals(dec.decode(joined), "Hello World"); +function reader(s: string): TextProtoReader { + return new TextProtoReader(new BufReader(stringsReader(s))); +} + +test({ + ignore: true, + name: "[textproto] Reader : DotBytes", + fn(): Promise { + const _input = + "dotlines\r\n.foo\r\n..bar\n...baz\nquux\r\n\r\n.\r\nanot.her\r\n"; + return Promise.resolve(); + }, +}); + +test("[textproto] ReadEmpty", async () => { + const r = reader(""); + const m = await r.readMIMEHeader(); + assertEquals(m, Deno.EOF); +}); + +test("[textproto] Reader", async () => { + const r = reader("line1\nline2\n"); + let s = await r.readLine(); + assertEquals(s, "line1"); + + s = await r.readLine(); + assertEquals(s, "line2"); + + s = await r.readLine(); + assert(s === Deno.EOF); +}); + +test({ + name: "[textproto] Reader : MIME Header", + async fn(): Promise { + const input = + "my-key: Value 1 \r\nLong-key: Even Longer Value\r\nmy-Key: " + + "Value 2\r\n\n"; + const r = reader(input); + const m = assertNotEOF(await r.readMIMEHeader()); + assertEquals(m.get("My-Key"), "Value 1, Value 2"); + assertEquals(m.get("Long-key"), "Even Longer Value"); + }, +}); + +test({ + name: "[textproto] Reader : MIME Header Single", + async fn(): Promise { + const input = "Foo: bar\n\n"; + const r = reader(input); + const m = assertNotEOF(await r.readMIMEHeader()); + assertEquals(m.get("Foo"), "bar"); + }, +}); + +test({ + name: "[textproto] Reader : MIME Header No Key", + async fn(): Promise { + const input = ": bar\ntest-1: 1\n\n"; + const r = reader(input); + const m = assertNotEOF(await r.readMIMEHeader()); + assertEquals(m.get("Test-1"), "1"); + }, +}); + +test({ + name: "[textproto] Reader : Large MIME Header", + async fn(): Promise { + const data: string[] = []; + // Go test is 16*1024. But seems it can't handle more + for (let i = 0; i < 1024; i++) { + data.push("x"); + } + const sdata = data.join(""); + const r = reader(`Cookie: ${sdata}\r\n\r\n`); + const m = assertNotEOF(await r.readMIMEHeader()); + assertEquals(m.get("Cookie"), sdata); + }, +}); + +// Test that we read slightly-bogus MIME headers seen in the wild, +// with spaces before colons, and spaces in keys. +test({ + name: "[textproto] Reader : MIME Header Non compliant", + async fn(): Promise { + const input = + "Foo: bar\r\n" + + "Content-Language: en\r\n" + + "SID : 0\r\n" + + "Audio Mode : None\r\n" + + "Privilege : 127\r\n\r\n"; + const r = reader(input); + const m = assertNotEOF(await r.readMIMEHeader()); + assertEquals(m.get("Foo"), "bar"); + assertEquals(m.get("Content-Language"), "en"); + assertEquals(m.get("SID"), "0"); + assertEquals(m.get("Privilege"), "127"); + // Not a legal http header + assertThrows((): void => { + assertEquals(m.get("Audio Mode"), "None"); + }); + }, +}); + +test({ + name: "[textproto] Reader : MIME Header Malformed", + async fn(): Promise { + const input = [ + "No colon first line\r\nFoo: foo\r\n\r\n", + " No colon first line with leading space\r\nFoo: foo\r\n\r\n", + "\tNo colon first line with leading tab\r\nFoo: foo\r\n\r\n", + " First: line with leading space\r\nFoo: foo\r\n\r\n", + "\tFirst: line with leading tab\r\nFoo: foo\r\n\r\n", + "Foo: foo\r\nNo colon second line\r\n\r\n", + ]; + const r = reader(input.join("")); + + let err; + try { + await r.readMIMEHeader(); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.InvalidData); + }, +}); + +test({ + name: "[textproto] Reader : MIME Header Trim Continued", + async fn(): Promise { + const input = + "" + // for code formatting purpose. + "a:\n" + + " 0 \r\n" + + "b:1 \t\r\n" + + "c: 2\r\n" + + " 3\t\n" + + " \t 4 \r\n\n"; + const r = reader(input); + let err; + try { + await r.readMIMEHeader(); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.InvalidData); + }, +}); + +test({ + name: "[textproto] #409 issue : multipart form boundary", + async fn(): Promise { + const input = [ + "Accept: */*\r\n", + 'Content-Disposition: form-data; name="test"\r\n', + " \r\n", + "------WebKitFormBoundaryimeZ2Le9LjohiUiG--\r\n\n", + ]; + const r = reader(input.join("")); + const m = assertNotEOF(await r.readMIMEHeader()); + assertEquals(m.get("Accept"), "*/*"); + assertEquals(m.get("Content-Disposition"), 'form-data; name="test"'); + }, }); diff --git a/std/types/react-dom.d.ts b/std/types/react-dom.d.ts index f135197f2b40bf..3be59411fb25bc 100644 --- a/std/types/react-dom.d.ts +++ b/std/types/react-dom.d.ts @@ -30,7 +30,7 @@ import { DOMAttributes, DOMElement, ReactNode, - ReactPortal + ReactPortal, } from "./react.d.ts"; export function findDOMNode( diff --git a/std/types/react.d.ts b/std/types/react.d.ts index b512a43a291d32..725503b13e71c2 100644 --- a/std/types/react.d.ts +++ b/std/types/react.d.ts @@ -3231,9 +3231,7 @@ declare namespace React { // naked 'any' type in a conditional type will short circuit and union both the then/else branches // so boolean is only resolved for T = any -type IsExactlyAny = boolean extends (T extends never -? true -: false) +type IsExactlyAny = boolean extends (T extends never ? true : false) ? true : false; diff --git a/std/types/tests/react-dom_mock.js b/std/types/tests/react-dom_mock.js index 68b4137ba38d71..cbc20958bc12f5 100644 --- a/std/types/tests/react-dom_mock.js +++ b/std/types/tests/react-dom_mock.js @@ -3,7 +3,7 @@ const ReactDOM = { render(element) { return JSON.stringify(element); - } + }, }; export default ReactDOM; diff --git a/std/types/tests/react_mock.js b/std/types/tests/react_mock.js index 93faa6c9b1718d..3dec4f4220bcda 100644 --- a/std/types/tests/react_mock.js +++ b/std/types/tests/react_mock.js @@ -3,7 +3,7 @@ const React = { createElement(type, props, ...children) { return JSON.stringify({ type, props, children }); - } + }, }; export default React; diff --git a/std/util/deep_assign_test.ts b/std/util/deep_assign_test.ts index a69d30b7370312..e759a33acaf267 100644 --- a/std/util/deep_assign_test.ts +++ b/std/util/deep_assign_test.ts @@ -13,10 +13,10 @@ test(function deepAssignTest(): void { const expected = { foo: { deno: new Date("1979-05-27T07:32:00Z"), - bar: "deno" + bar: "deno", }, deno: { bar: { deno: ["is", "not", "node"] } }, - reg: RegExp(/DENOWOWO/) + reg: RegExp(/DENOWOWO/), }; assert(date !== expected.foo.deno); assert(reg !== expected.reg); diff --git a/std/uuid/mod.ts b/std/uuid/mod.ts index 26e4b43ffb060a..8e312c5585d6a6 100644 --- a/std/uuid/mod.ts +++ b/std/uuid/mod.ts @@ -14,7 +14,7 @@ const NOT_IMPLEMENTED = { }, validate(): never { throw new Error("Not implemented"); - } + }, }; // TODO Implement diff --git a/std/uuid/tests/isNil.ts b/std/uuid/tests/isNil.ts index 7719f1229e3efa..4514576daa7606 100644 --- a/std/uuid/tests/isNil.ts +++ b/std/uuid/tests/isNil.ts @@ -11,5 +11,5 @@ test({ const u = "582cbcff-dad6-4f28-888a-e062ae36bafc"; assert(isNil(nil)); assert(!isNil(u)); - } + }, }); diff --git a/std/uuid/tests/v4/generate.ts b/std/uuid/tests/v4/generate.ts index c9946d46c0656a..897a53fde90c39 100644 --- a/std/uuid/tests/v4/generate.ts +++ b/std/uuid/tests/v4/generate.ts @@ -9,7 +9,7 @@ test({ const u = generate(); assertEquals(typeof u, "string", "returns a string"); assert(u !== "", "return string is not empty"); - } + }, }); test({ @@ -19,5 +19,5 @@ test({ const u = generate() as string; assert(validate(u), `${u} is not a valid uuid v4`); } - } + }, }); diff --git a/std/uuid/tests/v4/validate.ts b/std/uuid/tests/v4/validate.ts index feeecf6b7c0aa1..3735de51e58c1e 100644 --- a/std/uuid/tests/v4/validate.ts +++ b/std/uuid/tests/v4/validate.ts @@ -12,5 +12,5 @@ Deno.test({ assert(validate(u), `generated ${u} should be valid`); assert(validate(t), `${t} should be valid`); assert(!validate(n), `${n} should not be valid`); - } + }, }); diff --git a/std/uuid/v4.ts b/std/uuid/v4.ts index 7688a53061a984..d291b5478d5078 100644 --- a/std/uuid/v4.ts +++ b/std/uuid/v4.ts @@ -28,6 +28,6 @@ export function generate(): string { "-", ...bits.slice(8, 10), "-", - ...bits.slice(10) + ...bits.slice(10), ].join(""); } diff --git a/std/ws/README.md b/std/ws/README.md index a8101f9f0269d1..2379d9f96ecebb 100644 --- a/std/ws/README.md +++ b/std/ws/README.md @@ -12,7 +12,7 @@ import { acceptWebSocket, isWebSocketCloseEvent, isWebSocketPingEvent, - WebSocket + WebSocket, } from "https://deno.land/std/ws/mod.ts"; /** websocket echo server */ @@ -24,7 +24,7 @@ for await (const req of serve(`:${port}`)) { conn, headers, bufReader: req.r, - bufWriter: req.w + bufWriter: req.w, }) .then( async (sock: WebSocket): Promise => { @@ -73,7 +73,7 @@ import { connectWebSocket, isWebSocketCloseEvent, isWebSocketPingEvent, - isWebSocketPongEvent + isWebSocketPongEvent, } from "https://deno.land/std/ws/mod.ts"; import { encode } from "https://deno.land/std/strings/mod.ts"; import { BufReader } from "https://deno.land/std/io/bufio.ts"; @@ -84,7 +84,7 @@ const endpoint = Deno.args[0] || "ws://127.0.0.1:8080"; /** simple websocket cli */ const sock = await connectWebSocket(endpoint); console.log(green("ws connected! (type 'close' to quit)")); -(async function(): Promise { +(async function (): Promise { for await (const msg of sock.receive()) { if (typeof msg === "string") { console.log(yellow("< " + msg)); diff --git a/std/ws/example_client.ts b/std/ws/example_client.ts index 664073210d9be4..e6653362d49a5b 100644 --- a/std/ws/example_client.ts +++ b/std/ws/example_client.ts @@ -2,7 +2,7 @@ import { connectWebSocket, isWebSocketCloseEvent, isWebSocketPingEvent, - isWebSocketPongEvent + isWebSocketPongEvent, } from "../ws/mod.ts"; import { encode } from "../strings/mod.ts"; import { BufReader } from "../io/bufio.ts"; @@ -13,7 +13,7 @@ const endpoint = Deno.args[0] || "ws://127.0.0.1:8080"; /** simple websocket cli */ const sock = await connectWebSocket(endpoint); console.log(green("ws connected! (type 'close' to quit)")); -(async function(): Promise { +(async function (): Promise { for await (const msg of sock.receive()) { if (typeof msg === "string") { console.log(yellow("< " + msg)); diff --git a/std/ws/example_server.ts b/std/ws/example_server.ts index 03adc0a4988bf8..04819832674299 100644 --- a/std/ws/example_server.ts +++ b/std/ws/example_server.ts @@ -4,7 +4,7 @@ import { acceptWebSocket, isWebSocketCloseEvent, isWebSocketPingEvent, - WebSocket + WebSocket, } from "./mod.ts"; /** websocket echo server */ @@ -16,7 +16,7 @@ for await (const req of serve(`:${port}`)) { conn, headers, bufReader: req.r, - bufWriter: req.w + bufWriter: req.w, }) .then( async (sock: WebSocket): Promise => { diff --git a/std/ws/mod.ts b/std/ws/mod.ts index 3332ed8dd22ba6..a9b8cb67529df1 100644 --- a/std/ws/mod.ts +++ b/std/ws/mod.ts @@ -9,6 +9,7 @@ import { writeResponse } from "../http/io.ts"; import { TextProtoReader } from "../textproto/mod.ts"; import { Deferred, deferred } from "../util/async.ts"; import { assertNotEOF } from "../testing/asserts.ts"; +import { concat } from "../bytes/mod.ts"; import Conn = Deno.Conn; import Writer = Deno.Writer; @@ -18,7 +19,7 @@ export enum OpCode { BinaryFrame = 0x2, Close = 0x8, Ping = 0x9, - Pong = 0xa + Pong = 0xa, } export type WebSocketEvent = @@ -57,20 +58,6 @@ export function isWebSocketPongEvent( export type WebSocketMessage = string | Uint8Array; -// TODO move this to common/util module -export function append(a: Uint8Array, b: Uint8Array): Uint8Array { - if (a == null || !a.length) { - return b; - } - if (b == null || !b.length) { - return a; - } - const output = new Uint8Array(a.length + b.length); - output.set(a, 0); - output.set(b, a.length); - return output; -} - export interface WebSocketFrame { isLastFrame: boolean; opcode: OpCode; @@ -138,20 +125,20 @@ export async function writeFrame( 0x80 | frame.opcode, hasMask | 0b01111110, payloadLength >>> 8, - payloadLength & 0x00ff + payloadLength & 0x00ff, ]); } else { header = new Uint8Array([ 0x80 | frame.opcode, hasMask | 0b01111111, - ...sliceLongToBytes(payloadLength) + ...sliceLongToBytes(payloadLength), ]); } if (frame.mask) { - header = append(header, frame.mask); + header = concat(header, frame.mask); } unmask(frame.payload, frame.mask); - header = append(header, frame.payload); + header = concat(header, frame.payload); const w = BufWriter.create(writer); await w.write(header); await w.flush(); @@ -199,7 +186,7 @@ export async function readFrame(buf: BufReader): Promise { isLastFrame, opcode, mask, - payload + payload, }; } @@ -222,7 +209,7 @@ class WebSocketImpl implements WebSocket { conn, bufReader, bufWriter, - mask + mask, }: { conn: Conn; bufReader?: BufReader; @@ -284,7 +271,7 @@ class WebSocketImpl implements WebSocket { await this.enqueue({ opcode: OpCode.Pong, payload: frame.payload, - isLastFrame: true + isLastFrame: true, }); yield ["ping", frame.payload] as WebSocketPingEvent; break; @@ -303,7 +290,7 @@ class WebSocketImpl implements WebSocket { const { d, frame } = entry; writeFrame(frame, this.bufWriter) .then(() => d.resolve()) - .catch(e => d.reject(e)) + .catch((e) => d.reject(e)) .finally(() => { this.sendQueue.shift(); this.dequeue(); @@ -331,7 +318,7 @@ class WebSocketImpl implements WebSocket { isLastFrame, opcode, payload, - mask: this.mask + mask: this.mask, }; return this.enqueue(frame); } @@ -342,7 +329,7 @@ class WebSocketImpl implements WebSocket { isLastFrame: true, opcode: OpCode.Ping, mask: this.mask, - payload + payload, }; return this.enqueue(frame); } @@ -368,7 +355,7 @@ class WebSocketImpl implements WebSocket { isLastFrame: true, opcode: OpCode.Close, mask: this.mask, - payload + payload, }); } catch (e) { throw e; @@ -391,7 +378,7 @@ class WebSocketImpl implements WebSocket { this._isClosed = true; const rest = this.sendQueue; this.sendQueue = []; - rest.forEach(e => + rest.forEach((e) => e.d.reject( new Deno.errors.ConnectionReset("Socket has already been closed") ) @@ -444,8 +431,8 @@ export async function acceptWebSocket(req: { headers: new Headers({ Upgrade: "websocket", Connection: "Upgrade", - "Sec-WebSocket-Accept": secAccept - }) + "Sec-WebSocket-Accept": secAccept, + }), }); return sock; } @@ -556,7 +543,7 @@ export async function connectWebSocket( conn, bufWriter, bufReader, - mask: createMask() + mask: createMask(), }); } diff --git a/std/ws/sha1.ts b/std/ws/sha1.ts index dc8ba680c97706..fc86881f87415c 100644 --- a/std/ws/sha1.ts +++ b/std/ws/sha1.ts @@ -358,7 +358,7 @@ export class Sha1 { (h4 >> 24) & 0xff, (h4 >> 16) & 0xff, (h4 >> 8) & 0xff, - h4 & 0xff + h4 & 0xff, ]; } diff --git a/std/ws/test.ts b/std/ws/test.ts index f1efa8e409b1b7..583750bb1a23b4 100644 --- a/std/ws/test.ts +++ b/std/ws/test.ts @@ -14,7 +14,7 @@ import { readFrame, unmask, writeFrame, - createWebSocket + createWebSocket, } from "./mod.ts"; import { encode, decode } from "../strings/mod.ts"; import Writer = Deno.Writer; @@ -50,7 +50,7 @@ test("[ws] read masked text frame", async () => { 0x9f, 0x4d, 0x51, - 0x58 + 0x58, ]) ) ); @@ -136,8 +136,8 @@ test("[ws] acceptable", () => { const ret = acceptable({ headers: new Headers({ upgrade: "websocket", - "sec-websocket-key": "aaa" - }) + "sec-websocket-key": "aaa", + }), }); assertEquals(ret, true); @@ -148,12 +148,12 @@ test("[ws] acceptable", () => { ["host", "127.0.0.1:9229"], [ "sec-websocket-extensions", - "permessage-deflate; client_max_window_bits" + "permessage-deflate; client_max_window_bits", ], ["sec-websocket-key", "dGhlIHNhbXBsZSBub25jZQ=="], ["sec-websocket-version", "13"], - ["upgrade", "WebSocket"] - ]) + ["upgrade", "WebSocket"], + ]), }) ); }); @@ -161,25 +161,25 @@ test("[ws] acceptable", () => { test("[ws] acceptable should return false when headers invalid", () => { assertEquals( acceptable({ - headers: new Headers({ "sec-websocket-key": "aaa" }) + headers: new Headers({ "sec-websocket-key": "aaa" }), }), false ); assertEquals( acceptable({ - headers: new Headers({ upgrade: "websocket" }) + headers: new Headers({ upgrade: "websocket" }), }), false ); assertEquals( acceptable({ - headers: new Headers({ upgrade: "invalid", "sec-websocket-key": "aaa" }) + headers: new Headers({ upgrade: "invalid", "sec-websocket-key": "aaa" }), }), false ); assertEquals( acceptable({ - headers: new Headers({ upgrade: "websocket", "sec-websocket-ky": "" }) + headers: new Headers({ upgrade: "websocket", "sec-websocket-ky": "" }), }), false ); @@ -205,7 +205,7 @@ test("[ws] write and read masked frame", async () => { isLastFrame: true, mask, opcode: OpCode.TextFrame, - payload: encode(msg) + payload: encode(msg), }, buf ); @@ -282,19 +282,19 @@ function dummyConn(r: Reader, w: Writer): Conn { write: (x): Promise => w.write(x), close: (): void => {}, localAddr: { transport: "tcp", hostname: "0.0.0.0", port: 0 }, - remoteAddr: { transport: "tcp", hostname: "0.0.0.0", port: 0 } + remoteAddr: { transport: "tcp", hostname: "0.0.0.0", port: 0 }, }; } function delayedWriter(ms: number, dest: Writer): Writer { return { write(p: Uint8Array): Promise { - return new Promise(resolve => { + return new Promise((resolve) => { setTimeout(async (): Promise => { resolve(await dest.write(p)); }, ms); }); - } + }, }; } test({ @@ -308,7 +308,7 @@ test({ sock.send("first"), sock.send("second"), sock.ping(), - sock.send(new Uint8Array([3])) + sock.send(new Uint8Array([3])), ]); const bufr = new BufReader(buf); const first = await readFrame(bufr); @@ -322,7 +322,7 @@ test({ assertEquals(ping.opcode, OpCode.Ping); assertEquals(third.opcode, OpCode.BinaryFrame); assertEquals(bytes.equal(third.payload, new Uint8Array([3])), true); - } + }, }); test("[ws] createSecKeyHasCorrectLength", () => { @@ -337,7 +337,7 @@ test("[ws] WebSocket should throw `Deno.errors.ConnectionReset` when peer closed const eofReader: Deno.Reader = { read(_: Uint8Array): Promise { return Promise.resolve(Deno.EOF); - } + }, }; const conn = dummyConn(eofReader, buf); const sock = createWebSocket({ conn }); @@ -355,7 +355,7 @@ test("[ws] WebSocket shouldn't throw `Deno.errors.UnexpectedEof` on recive()", a const eofReader: Deno.Reader = { read(_: Uint8Array): Promise { return Promise.resolve(Deno.EOF); - } + }, }; const conn = dummyConn(eofReader, buf); const sock = createWebSocket({ conn }); @@ -373,10 +373,10 @@ test({ let timer: number | undefined; const lazyWriter: Deno.Writer = { write(_: Uint8Array): Promise { - return new Promise(resolve => { + return new Promise((resolve) => { timer = setTimeout(() => resolve(0), 1000); }); - } + }, }; const conn = dummyConn(buf, lazyWriter); const sock = createWebSocket({ conn }); @@ -384,7 +384,7 @@ test({ const p = Promise.all([ sock.send("hello").catch(onError), sock.send(new Uint8Array([1, 2])).catch(onError), - sock.ping().catch(onError) + sock.ping().catch(onError), ]); sock.closeForce(); assertEquals(sock.isClosed, true); @@ -396,5 +396,5 @@ test({ // Wait for another event loop turn for `timeout` op promise // to resolve, otherwise we'll get "op leak". await delay(10); - } + }, }); diff --git a/test_plugin/tests/test.js b/test_plugin/tests/test.js index 49b126e62d23b3..d6d531f145678e 100644 --- a/test_plugin/tests/test.js +++ b/test_plugin/tests/test.js @@ -28,7 +28,7 @@ function runTestSync() { console.log(`Plugin Sync Response: ${textDecoder.decode(response)}`); } -testAsync.setAsyncHandler(response => { +testAsync.setAsyncHandler((response) => { console.log(`Plugin Async Response: ${textDecoder.decode(response)}`); }); diff --git a/third_party b/third_party index 44f4b5618e024d..4a3ade332261af 160000 --- a/third_party +++ b/third_party @@ -1 +1 @@ -Subproject commit 44f4b5618e024d58bc7465bfb30e3bad58c0342b +Subproject commit 4a3ade332261afb8fcb8b364e59d3cca7c975d36 diff --git a/tools/deno_http_proxy.ts b/tools/deno_http_proxy.ts index 589a14338d38fd..6e51413779b167 100644 --- a/tools/deno_http_proxy.ts +++ b/tools/deno_http_proxy.ts @@ -9,7 +9,7 @@ async function proxyRequest(req: ServerRequest): Promise { const url = `http://${originAddr}${req.url}`; const resp = await fetch(url, { method: req.method, - headers: req.headers + headers: req.headers, }); req.respond(resp); } diff --git a/tools/deno_tcp.ts b/tools/deno_tcp.ts index 9a884cb7058a2d..068c48a04f0415 100644 --- a/tools/deno_tcp.ts +++ b/tools/deno_tcp.ts @@ -8,7 +8,6 @@ const listener = Deno.listen({ hostname, port: Number(port) }); const response = new TextEncoder().encode( "HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World\n" ); - async function handle(conn: Deno.Conn): Promise { const buffer = new Uint8Array(1024); try { diff --git a/tools/deno_tcp_proxy.ts b/tools/deno_tcp_proxy.ts index cd1bad2471d1c2..43c61831c944c9 100644 --- a/tools/deno_tcp_proxy.ts +++ b/tools/deno_tcp_proxy.ts @@ -10,7 +10,7 @@ const listener = Deno.listen({ hostname, port: Number(port) }); async function handle(conn: Deno.Conn): Promise { const origin = await Deno.connect({ hostname: originHostname, - port: Number(originPort) + port: Number(originPort), }); try { await Promise.all([Deno.copy(conn, origin), Deno.copy(origin, conn)]); diff --git a/tools/node_http_proxy.js b/tools/node_http_proxy.js index d90cbe8350a7c5..b984c484f59088 100644 --- a/tools/node_http_proxy.js +++ b/tools/node_http_proxy.js @@ -9,10 +9,10 @@ http port: originPort, path: req.url, method: req.method, - headers: req.headers + headers: req.headers, }; - const proxy = http.request(options, proxyRes => { + const proxy = http.request(options, (proxyRes) => { res.writeHead(proxyRes.statusCode, proxyRes.headers); proxyRes.pipe(res, { end: true }); }); diff --git a/tools/node_tcp.js b/tools/node_tcp.js index 3899a671a5c381..7c6147dbff9d9b 100644 --- a/tools/node_tcp.js +++ b/tools/node_tcp.js @@ -8,11 +8,11 @@ const response = Buffer.from( "HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World\n" ); -Server(socket => { - socket.on("data", _ => { +Server((socket) => { + socket.on("data", (_) => { socket.write(response); }); - socket.on("error", _ => { + socket.on("error", (_) => { socket.destroy(); }); }).listen(port); diff --git a/tools/node_tcp_promise.js b/tools/node_tcp_promise.js index d522f1751a348b..c59a9a7b46cc2e 100644 --- a/tools/node_tcp_promise.js +++ b/tools/node_tcp_promise.js @@ -15,8 +15,8 @@ function write(socket, buffer) { return Promise.resolve(p); } -Server(async socket => { - socket.on("error", _ => { +Server(async (socket) => { + socket.on("error", (_) => { socket.destroy(); }); for await (const _ of socket) { diff --git a/tools/node_tcp_proxy.js b/tools/node_tcp_proxy.js index 7dc1b2612af839..304ed0407d0a04 100644 --- a/tools/node_tcp_proxy.js +++ b/tools/node_tcp_proxy.js @@ -1,6 +1,6 @@ const net = require("net"); -process.on("uncaughtException", function(error) { +process.on("uncaughtException", function (error) { console.error(error); }); @@ -14,46 +14,46 @@ const remoteport = process.argv[3]; const remotehost = "127.0.0.1"; -const server = net.createServer(function(localsocket) { +const server = net.createServer(function (localsocket) { const remotesocket = new net.Socket(); remotesocket.connect(remoteport, remotehost); - localsocket.on("data", function(data) { + localsocket.on("data", function (data) { const flushed = remotesocket.write(data); if (!flushed) { localsocket.pause(); } }); - remotesocket.on("data", function(data) { + remotesocket.on("data", function (data) { const flushed = localsocket.write(data); if (!flushed) { remotesocket.pause(); } }); - localsocket.on("drain", function() { + localsocket.on("drain", function () { remotesocket.resume(); }); - remotesocket.on("drain", function() { + remotesocket.on("drain", function () { localsocket.resume(); }); - localsocket.on("close", function() { + localsocket.on("close", function () { remotesocket.end(); }); - remotesocket.on("close", function() { + remotesocket.on("close", function () { localsocket.end(); }); - localsocket.on("error", function() { + localsocket.on("error", function () { localsocket.end(); }); - remotesocket.on("error", function() { + remotesocket.on("error", function () { remotesocket.end(); }); });